Wann werden Serializers create () und ModelViewset's create () perform_create () verwendet?

95

Ich möchte die gegebene Dokumentation django-rest-frameworkbezüglich der Erstellung eines Modellobjekts klarstellen . Bisher habe ich festgestellt, dass es drei Ansätze gibt, wie man mit solchen Ereignissen umgeht.

  1. Die create()Methode des Serializers . Hier ist die Dokumentation

    class CommentSerializer(serializers.Serializer):
    
        def create(self, validated_data):
            return Comment.objects.create(**validated_data)
    
  2. Die ModelViewset- create()Methode. Dokumentation

    class AccountViewSet(viewsets.ModelViewSet):
    
        queryset = Account.objects.all()
        serializer_class = AccountSerializer
        permission_classes = [IsAccountAdminOrReadOnly]
    
  3. Die ModelViewset- perform_create()Methode. Dokumentation

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

Diese drei Ansätze sind abhängig von Ihrer Anwendungsumgebung wichtig.

Aber wann müssen wir jede create() / perform_create()Funktion verwenden? Auf der anderen Seite fand ich einen Bericht, dass zwei Erstellungsmethoden für eine einzelne Post-Anfrage des Modelviewset create()und des Serializers aufgerufen wurden create().

Hoffentlich würde jeder etwas von seinem Wissen teilen, um es zu erklären, und dies wird sicherlich sehr hilfreich in meinem Entwicklungsprozess sein.

Roel
quelle

Antworten:

125
  1. Sie würden create(self, validated_data)dem Objekt zusätzliche Details hinzufügen, bevor Sie UND "prod" -Werte in jedem Modellfeld speichern, genau wie dies der **validated_dataFall ist. Idealerweise möchten Sie diese Form des "Stupsens" nur an EINEM Ort durchführen, damit die createMethode in Ihrem CommentSerializerder beste Ort ist. Darüber hinaus möchten Sie möglicherweise auch externe APIs aufrufen, um Benutzerkonten auf ihrer Seite zu erstellen, bevor Sie Ihre Konten in Ihrer eigenen Datenbank speichern. Sie sollten diese createFunktion in Verbindung mit verwenden ModelViewSet. Denken Sie immer - "Thin Views, Thick Serializers".

Beispiel:

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. Die create(self, request, *args, **kwargs)Funktion in der ModelViewSetwird in der CreateModelMixinKlasse definiert, deren Eltern übergeordnet sind ModelViewSet. CreateModelMixinDie Hauptfunktionen sind:

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

Wie Sie sehen können, createsorgt die obige Funktion dafür, dass die Validierung auf Ihrem Serializer aufgerufen und die richtige Antwort erzeugt wird. Das Schöne daran ist, dass Sie jetzt Ihre Anwendungslogik isolieren können und sich NICHT um die alltäglichen und sich wiederholenden Validierungsaufrufe und die Verarbeitung der Antwortausgabe kümmern müssen :). Dies funktioniert recht gut in Verbindung mit dem create(self, validated_data)im Serializer gefundenen (wo sich möglicherweise Ihre spezifische Anwendungslogik befindet).

  1. Nun fragen Sie sich vielleicht, warum wir eine separate perform_create(self, serializer)Funktion mit nur einer Codezeile haben!?!? Der Hauptgrund dafür ist die Anpassbarkeit beim Aufrufen der saveFunktion. Vielleicht möchten Sie vor dem Anruf zusätzliche Daten bereitstellen save (wieserializer.save(owner=self.request.user) und wenn wir keine hätten perform_create(self, serializer), müssten Sie die überschreiben, create(self, request, *args, **kwargs)und das macht den Zweck zunichte, dass Mixins die schwere und langweilige Arbeit erledigen.

Hoffe das hilft!

Apoorv Kansal
quelle
Hallo! Vielen Dank für Ihr Wissen! Über das create(self, validated_data)im Serializer bedeutet es, dass es sich auf Datenvalidierungslogik konzentriert? und darüber hinaus kann es helfen, die Daten des angegebenen Serializers wieder auf die Antwort zurückzuführen, oder?
Roel
1
Nein, zu diesem Zeitpunkt haben Sie bereits alle Ihre Validierungen bestanden. Ich spreche darüber, wie Sie die validierten Daten anpassen möchten, bevor sie in einer Datenbank gespeichert werden. Ich werde in meiner Antwort ein Beispiel geben.
Apoorv Kansal
1
Keine Sorge - habe nur ein Beispiel hinzugefügt, um mehr Kontext zu schaffen.
Apoorv Kansal
1
Ja, das ist die letzte Zeile, die Ihr Objekt in der Datenbank speichert
Apoorv Kansal
1
Die createFunktion im Serializer selbst wird also nur aufgerufen, wenn Sie dies tun serializer.save(). In Ihrer create(self, request)Funktion inside ( AccountViewSet) rufen Sie überhaupt nicht serializer.save()auf, und daher erfolgt die einzige Instanzerstellung mit diesem Aufruf : Account.objects.create_user(**serializer.validated_data).
Apoorv Kansal