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

95

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

  1. Метод сериализатора 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()и сериализатор create().

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

Roel
источник

Ответы:

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

Пример:

def create(self, validated_data):
    email = validated_data.get("email", None)
    validated.pop("email") 
    # Now you have a clean valid email string 
    # 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)и это просто противоречит цели, чтобы миксины выполняли тяжелую и скучную работу.

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

Апурв Кансал
источник
Здравствуй! Спасибо за то, что поделились своими знаниями! Что create(self, validated_data)касается сериализатора, это означает, что он фокусируется на логике проверки данных? и более того, это может помочь вернуть данные сериализатора обратно в ответ, верно?
Roel
1
Нет, на данный момент вы уже прошли все проверки. Я говорю о том, как вы можете настроить проверенные данные непосредственно перед их сохранением в базе данных. В своем ответе я приведу пример.
Apoorv Kansal
1
Не беспокойтесь - просто добавили пример, чтобы дать больше контекста.
Apoorv Kansal
1
Да, это последняя строка, которая сохранит ваш объект в базе данных
Apoorv Kansal
1
Таким образом, createфункция в самом сериализаторе вызывается только тогда, когда вы это делаете serializer.save(). В вашей create(self, request)функции внутри ( AccountViewSet), вы не вызывая serializer.save()вообще и , следовательно, только создание экземпляра происходит с этим вызовом: Account.objects.create_user(**serializer.validated_data).
Apoorv Kansal