Когда использовать Serializer create() и ModelViewset create() perform_create()

Я хочу уточнить данную документацию django-rest-framework относительно создания модельного объекта. До сих пор я обнаружил, что существует три подхода к обработке таких событий.

  1. Метод Serializer create(). Вот документация

    class CommentSerializer(serializers.Serializer):
    
        def create(self, validated_data):
            return Comment.objects.create(**validated_data)
    
  2. Метод ModelViewset create(). Документация

    class AccountViewSet(viewsets.ModelViewSet):
    
        queryset = Account.objects.all()
        serializer_class = AccountSerializer
        permission_classes = [IsAccountAdminOrReadOnly]
    
  3. Метод ModelViewset perform_create(). Документация

    class SnippetViewSet(viewsets.ModelViewSet):
    
        def perform_create(self, serializer):
            serializer.save(owner=self.request.user)
    

Эти три подхода важны в зависимости от среды вашего приложения.

Но КОГДА нам нужно использовать каждую функцию create()/perform_create()?? С другой стороны, я обнаружил, что для одного пост-запроса были вызваны два метода create: modelviewset create() и serializer create().

Надеюсь, кто-нибудь поделится некоторыми своими знаниями, чтобы объяснить, и это, безусловно, будет очень полезно в моем процессе разработки.

Ответ 1

  1. Вы должны использовать create(self, validated_data) чтобы добавить любые дополнительные детали в объект перед сохранением значений И "prod" в каждое поле модели, как это делает **validated_data. В идеале, вы хотите делать эту форму "подталкивания" только в ОДНОМ месте, поэтому метод create в вашем CommentSerializer - лучшее место. Кроме того, вы можете также вызвать внешний apis для создания учетных записей пользователей на их стороне непосредственно перед сохранением ваших учетных записей в вашей собственной базе данных. Вы должны использовать эту функцию create вместе с ModelViewSet. Всегда думай - "Тонкие взгляды, Толстые сериализаторы".

Пример:

def create(self, validated_data):
    email = validated.data.get("email", None)
    validated.pop("email") 
    # Now you have a clean valid email 
    # You might want to call an external API or modify another table
    # (eg. keep track of number of accounts registered.) or even
    # make changes to the email format.

    # Once you are done, create the instance with the validated data
    return models.YourModel.objects.create(email=email, **validated_data)
  1. Функция create(self, request, *args, **kwargs) в ModelViewSet определяется в классе CreateModelMixin который является родителем ModelViewSet. Основные функции CreateModelMixin в:

    from rest_framework import status
    from rest_framework.response import Response
    
    
    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)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
    
    def perform_create(self, serializer):
        serializer.save()
    

Как вы можете видеть, вышеупомянутая функция create заботится о вызове проверки вашего сериализатора и получении правильного ответа. Прелесть этого в том, что теперь вы можете изолировать логику своего приложения и НЕ беспокоиться о повседневных и повторяющихся вызовах проверки и обработки вывода ответов :). Это работает довольно хорошо в сочетании с create(self, validated_data) найденным в сериализаторе (где может находиться логика вашего конкретного приложения).

  1. Теперь вы можете спросить, почему у нас есть отдельная perform_create(self, serializer) с одной строкой кода!?!? Ну, главная причина этого заключается в том, чтобы позволить настраиваемость при вызове функции save. Возможно, вы захотите предоставить дополнительные данные перед вызовом save (например, serializer.save(owner=self.request.user) и если у нас не было perform_create(self, serializer), вам придется переопределить create(self, request, *args, **kwargs) и это только побуждает миксинов выполнять тяжелую и скучную работу.

Надеюсь это поможет!