Quando usar o create () do Serializer e o create () perform_create () do ModelViewset

102

Quero esclarecer a documentação fornecida django-rest-frameworksobre a criação de um objeto de modelo. Até agora descobri que existem 3 abordagens sobre como lidar com esses eventos.

  1. O create()método do serializador . Aqui está a documentação

    class CommentSerializer(serializers.Serializer):
    
        def create(self, validated_data):
            return Comment.objects.create(**validated_data)
    
  2. O create()método ModelViewset . Documentação

    class AccountViewSet(viewsets.ModelViewSet):
    
        queryset = Account.objects.all()
        serializer_class = AccountSerializer
        permission_classes = [IsAccountAdminOrReadOnly]
    
  3. O perform_create()método ModelViewset . Documentação

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

Essas três abordagens são importantes, dependendo do ambiente do seu aplicativo.

Mas QUANDO precisamos usar cada create() / perform_create()função ??. Por outro lado, descobri que dois métodos de criação foram chamados para uma única solicitação de postagem do modelviewset create()e do serializador create().

Espero que alguém compartilhe um pouco de seu conhecimento para explicar e isso certamente será muito útil no meu processo de desenvolvimento.

Roel
fonte

Respostas:

131
  1. Você usaria create(self, validated_data)para adicionar quaisquer detalhes extras ao objeto antes de salvar os valores AND "prod" em cada campo do modelo, assim como **validated_datafaz. Em termos ideais, você deseja fazer essa forma de "cutucar" apenas em UM local, para que o createmétodo em seu CommentSerializerseja o melhor. Além disso, você também pode chamar apis externas para criar contas de usuário antes de salvar suas contas em seu próprio banco de dados. Você deve usar esta createfunção em conjunto com ModelViewSet. Sempre pense - "Visualizações finas, serializadores espessos".

Exemplo:

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. A create(self, request, *args, **kwargs)função em ModelViewSeté definida na CreateModelMixinclasse que é pai de ModelViewSet. CreateModelMixinAs principais funções de são estas:

    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()
    

Como você pode ver, a createfunção acima se encarrega de chamar a validação em seu serializador e produzir a resposta correta. A beleza por trás disso é que agora você pode isolar a lógica de seu aplicativo e NÃO se preocupar com as chamadas de validação mundanas e repetitivas e como lidar com a saída de resposta :). Isso funciona muito bem em conjunto com o create(self, validated_data)encontrado no serializador (onde a lógica de seu aplicativo específico pode residir).

  1. Agora você pode perguntar, por que temos uma perform_create(self, serializer)função separada com apenas uma linha de código!?!? Bem, a principal razão por trás disso é permitir a personalização ao chamar a savefunção. Você pode querer fornecer dados extras antes de chamar save (comoserializer.save(owner=self.request.user) e se não tivéssemos perform_create(self, serializer), você teria que substituir o create(self, request, *args, **kwargs)e isso anula o propósito de ter mixins fazendo o trabalho pesado e enfadonho.

Espero que isto ajude!

Apoorv Kansal
fonte
Oi! Obrigado por compartilhar seu conhecimento! Sobre o create(self, validated_data)no serializador, significa que ele se concentra na lógica de validação de dados? e mais sobre isso pode ajudar a retornar os dados do serializador fornecido de volta para a resposta, certo?
Roel
1
Não, neste ponto, você já passou em toda a sua validação. Estou falando sobre como você pode querer personalizar os dados validados antes de salvá-los em um banco de dados. Vou dar um exemplo na minha resposta.
Apoorv Kansal
1
Não se preocupe - apenas adicionei um exemplo para dar mais contexto.
Apoorv Kansal
1
Sim, essa é a linha final que salvará seu objeto no banco de dados
Apoorv Kansal
1
Assim, a createfunção no próprio serializador é única chamada quando você faz serializer.save(). Em sua create(self, request)função dentro ( AccountViewSet), você não está chamando serializer.save()a todos e, portanto, a única criação da instância está acontecendo com esta chamada: Account.objects.create_user(**serializer.validated_data).
Apoorv Kansal