#angularjs #json #django #ionic-framework #django-rest-framework
#angularjs #json #django #ionic-framework #django-rest-framework
Вопрос:
Я стажер и работаю над проектом, в котором я разрабатываю DRF API, который должен взаимодействовать с мобильным приложением, написанным моим коллегой с помощью Ionic framework. Мы создаем нового пользователя. Мой метод просмотра следующий:
class NewUser(generics.CreateAPIView):
model = User
permission_classes = [permissions.AllowAny]
serializer_class = NewUserSerializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
token, created = Token.objects.get_or_create(user=serializer.instance)
return Response({'token': token.key}, status=status.HTTP_201_CREATED, headers=headers)
Когда кто-то хочет создать нового пользователя с помощью POST-запроса, если имя пользователя еще не было введено, API возвращает код состояния 201 и токен в JSON, если имя пользователя уже введено, он возвращает статус 400 и сообщение об ошибке в JSON. МОЙ коллега просит меня изменить сообщение о состоянии на 200, когда он пытается создать имя пользователя с уже существующим именем. Он говорит, что не может использовать ответ об ОШИБКЕ.
Его код выглядит так:
$http.post(url,{
username:$scope.tel,
password:$scope.passwd
}).success(function(data){
alert(data);
$ionicLoading.hide();
console.log(data);
})
Вопрос:
1) Должен ли я настроить свой API для отправки статуса 200 вместо более логичных 400 для ошибки «пользователь уже зарегистрирован»?
Я попытался изменить свой код, но не смог найти метод переопределения в CreateAPIView / ModelSerializer DRF. В итоге я переписал свой класс view в метод:
@api_view(['POST'])
def newUser(request):
"""
Saves a new user on the database
"""
if request.method == 'POST':
serializer = NewUserSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
token, created = Token.objects.get_or_create(user=serializer.instance)
return Response({'token': token.key}, status=status.HTTP_201_CREATED, headers=serializer.data)
else:
return Response(serializer.errors, status=status.HTTP_200_OK)
Вопрос:
2) Если я хочу изменить поведение API и ответа, какой метод я должен переопределить
3) Я новичок в Django и до сих пор не знаю, где мы должны использовать общие представления VS. @…. методы
Ответ №1:
200 против 400 в этом случае в основном предпочтение. 400 означает «Неверный запрос». Как правило, это более корректно для неправильно отформатированного запроса, а не для запроса, который не соответствует какому-либо условию.
200 так же уместен, он передает правильную информацию:
Ваш запрос был действительным, но я не создавал новую запись.
Что касается того, как сделать переопределение. Кратчайший путь — переопределить CreateAPIView.create
и изменить используемый код ответа. Вам также следует избегать повторения поведения по умолчанию CreateAPIView
при вызове super
.
class CreateUserView(generics.CreateAPIView):
model = User
permission_classes = [permissions.AllowAny]
serializer_class = NewUserSerializer
def create(self, request, *args, **kwargs):
response = super(CreateUserView, self).create(request, *args, **kwargs)
token, created = Token.objects.get_or_create(user=serializer.instance)
response.status = status.HTTP_200_OK
response.data = {'token': token.key}
return response
Лично я бы также создал my NewUserSerializer
, чтобы иметь поле токена и обрабатывать токен, поэтому мне не нужно было выполнять эту работу в View
. Он не принадлежит a View
.
Комментарии:
1. Спасибо за ваше внимание, но в вашем коде отсутствует та часть, где мы создаем «сериализатор». Таким образом, в строке «token, created = Token.objects.get_or_create (user=serializer.instance)» ошибка глобального имени не определена
2. Справедливо, все, что действительно имеет значение, это изменение статуса ответа. Но еще раз, поскольку у вас здесь неправильное разделение проблем, это заставляет вас дублировать код. Вы должны создавать свое
Token
творение как часть сериализатораsave
, чтобы у вас вообще не было всей этой бизнес-логики в представлении и избегать копирования кода вставки из суперкласса.
Ответ №2:
Хуки сохранения и удаления:
Следующие методы предоставляются классами mixin и обеспечивают простое переопределение поведения сохранения или удаления объекта.
perform_create(self, serializer) — вызывается CreateModelMixin при сохранении нового экземпляра объекта. perform_update(self, serializer) — вызывается UpdateModelMixin при сохранении существующего экземпляра объекта. perform_destroy(self, экземпляр) — вызывается DestroyModelMixin при удалении экземпляра объекта.
Эти перехваты особенно полезны для установки атрибутов, которые неявно присутствуют в запросе, но не являются частью данных запроса. Например, вы можете установить атрибут для объекта на основе пользователя запроса или на основе аргумента ключевого слова URL.
https://www.django-rest-framework.org/api-guide/generic-views/#methods
class CourseOrder(generics.CreateAPIView):
serializer_class = serializers.OrderCoursesSerializer
permission_classes = [permissions.AllowAny]
# hook before creating
def perform_create(self, serializer):
# print(serializer['name'].value)
# save post data
serializer.save()
try:
subject, from_email, to = 'New order', 'zelenchyks@gmail.com', 'zelenchyks@gmail.com'
text_content = 'New order'
html_content = '''
<p>client name: %s </p>
<p>client phone: %s </p>
'''
% (serializer['name'].value, serializer['mobile'].value)
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, "text/html")
msg.send()
except Warning:
print('Huston we have a problems with smtp')