Cuándo usar create () de Serializer y create () perform_create () de ModelViewset

95

Quiero aclarar la documentación proporcionada django-rest-frameworksobre la creación de un objeto modelo. Hasta ahora encontré que hay 3 enfoques sobre cómo manejar tales eventos.

  1. El create()método del serializador . Aquí está la documentación

    class CommentSerializer(serializers.Serializer):
    
        def create(self, validated_data):
            return Comment.objects.create(**validated_data)
    
  2. El create()método ModelViewset . Documentación

    class AccountViewSet(viewsets.ModelViewSet):
    
        queryset = Account.objects.all()
        serializer_class = AccountSerializer
        permission_classes = [IsAccountAdminOrReadOnly]
    
  3. El perform_create()método ModelViewset . Documentación

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

Estos tres enfoques son importantes según el entorno de su aplicación.

Pero, ¿CUÁNDO necesitamos usar cada create() / perform_create()función? Por otro lado, encontré una cuenta de que se llamaron dos métodos de creación para una sola solicitud de publicación del modelviewset create()y del serializador create().

Espero que alguien comparta algunos de sus conocimientos para explicarlo y esto seguramente será muy útil en mi proceso de desarrollo.

Roel
fuente

Respuestas:

125
  1. Lo usaría create(self, validated_data)para agregar detalles adicionales en el objeto antes de guardar los valores Y "prod" en cada campo del modelo tal como lo **validated_datahace. Idealmente hablando, desea hacer esta forma de "pinchazo" solo en UN lugar para que el createmétodo en su lugar CommentSerializersea ​​el mejor. Además de esto, es posible que también desee llamar a apis externas para crear cuentas de usuario de su lado justo antes de guardar sus cuentas en su propia base de datos. Debe utilizar esta createfunción junto con ModelViewSet. Piense siempre: "Vistas finas, serializadores gruesos".

Ejemplo:

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. La create(self, request, *args, **kwargs)función en ModelViewSetse define en la CreateModelMixinclase que es el padre de ModelViewSet. CreateModelMixinLas principales funciones son 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 puede ver, la createfunción anterior se encarga de llamar a la validación en su serializador y producir la respuesta correcta. La belleza detrás de esto es que ahora puede aislar la lógica de su aplicación y NO preocuparse por las llamadas de validación mundanas y repetitivas y el manejo de la salida de respuesta :). Esto funciona bastante bien en conjunto con lo que se create(self, validated_data)encuentra en el serializador (donde podría residir la lógica de su aplicación específica).

  1. Ahora podría preguntar, ¿por qué tenemos una perform_create(self, serializer)función separada con solo una línea de código? Bueno, la razón principal detrás de esto es permitir la personalización al llamar a la savefunción. Es posible que desee proporcionar datos adicionales antes de llamar save (por ejemplo,serializer.save(owner=self.request.user) y si no lo hicimos perform_create(self, serializer), tendría que anular el create(self, request, *args, **kwargs)y eso simplemente anula el propósito de tener mixins haciendo el trabajo pesado y aburrido.

¡Espero que esto ayude!

Apoorv Kansal
fuente
¡Hola! ¡Gracias por compartir sus conocimientos! Acerca del create(self, validated_data)serializador, ¿significa que se centra en la lógica de validación de datos? y más, puede ayudar a devolver los datos del serializador dado a la respuesta, ¿verdad?
Roel
1
No, en este punto, ya ha pasado toda su validación. Estoy hablando de cómo es posible que desee personalizar los datos validados justo antes de guardarlos en una base de datos. Daré un ejemplo en mi respuesta.
Apoorv Kansal
1
No se preocupe, solo agregué un ejemplo para dar más contexto.
Apoorv Kansal
1
Sí, esa es la línea final que guardará su objeto en la base de datos
Apoorv Kansal
1
Por lo que la createfunción en el propio serializador es única llamada cuando lo hace serializer.save(). En el create(self, request)interior de la función ( AccountViewSet), usted no está llamando serializer.save()a todos y, por lo tanto, la única creación de la instancia que está pasando con esta llamada: Account.objects.create_user(**serializer.validated_data).
Apoorv Kansal