Übergeben Sie zusätzliche Argumente an die Serializer-Klasse im Django Rest Framework

73

Ich möchte einige Argumente von Viewset an die DRF Serializer-Klasse übergeben, daher habe ich Folgendes versucht:

class OneZeroSerializer(rest_serializer.ModelSerializer):

    def __init__(self, *args, **kwargs):
        print args # show values that passed

    location = rest_serializer.SerializerMethodField('get_alternate_name')

    def get_alternate_name(self, obj):
        return ''


    class Meta:
        model = OneZero

        fields = ('id', 'location')

Ansichten

class OneZeroViewSet(viewsets.ModelViewSet):

   serializer_class = OneZeroSerializer(realpart=1)
   #serializer_class = OneZeroSerializer

   queryset = OneZero.objects.all()

Grundsätzlich möchte ich einen Wert basierend auf dem Querystring von Ansichten an die Serializer-Klasse übergeben, und diese werden dann Feldern zugewiesen.

Diese Felder sind nicht in dynamisch erstellten Feldern enthalten.

Gleicher Fall in dieser Frage Stapelüberlauf , aber ich kann die Antwort nicht verstehen.

Kann mir jemand in diesem Fall helfen oder mir bessere Optionen vorschlagen.

Shoaib Ijaz
quelle
@PauloScardine Kannst du mir ein einfaches Beispiel oder einen Link geben, über den ich Hilfe bekommen kann? Ich bin neu in Django, deshalb kann ich deine Worte nicht verstehen.
Shoaib Ijaz
1
Die Antwort auf die von Ihnen angegebene Frage ist richtig. Lesen Sie die Dokumentation zur get_serializerMethode und überschreiben Sie sie, um eine benutzerdefinierte Instanz des Serializers zurückzugeben.
Paulo Scardine
Ich habe diese Frage auch als Referenz erwähnt, aber es gibt kein Detail, das mir helfen kann
Shoaib Ijaz
1
Ich habe die Dokumentation gelesen, kann aber kein Beispiel finden, in dem zusätzliche Parameter übergeben werden. Es gibt nur ein Beispiel für die Verwendung verschiedener Serialisierungsklassen. Deshalb habe ich hier eine Frage gestellt
Shoaib Ijaz

Antworten:

102

Mit "context" arg für den "ModelSerializer" -Konstruktor ist das sehr einfach.

Zum Beispiel:

im Hinblick auf:

my_objects = MyModelSerializer(
    input_collection, 
    many=True, 
    context={'user_id': request.user.id}
).data

in Serialisierern:

class MyModelSerializer(serializers.ModelSerializer):
...

    is_my_object = serializers.SerializerMethodField('_is_my_find')
...

    def _is_my_find(self, obj):
        user_id = self.context.get("user_id")
        if user_id:
            return user_id in obj.my_objects.values_list("user_id", flat=True)
        return False
...

Sie können also "self.context" verwenden, um zusätzliche Parameter abzurufen.

Referenz

Redcyb
quelle
12
Dies funktioniert nicht. Wenn ich den Kontext mit einem zusätzlichen Feld in meinem Serializer übergebe, fehlt dieses zusätzliche Feld und der Kontext sieht wie {'request': <rest_framework.request.Request object at 0x103a2ba20>, 'view': <api.views.CourseAssignmentViewSet object at 0x10326b828>, 'format': None}
folgt
@redcyb könnten Sie mir dabei helfen bitte stackoverflow.com/questions/62039305/…
banky
27

Um die Antwort von Redcyb zu erfüllen, sollten Sie die get_serializer_contextMethode aus Ihrer Sicht GenericAPIViewwie folgt verwenden :

def get_serializer_context(self):
    return {'user': self.request.user.email}
Andilabs
quelle
6
Nur das Überschreiben reicht get_serializer_contextnicht aus, da der eigentliche Ort, an dem der validated_dataKontext aktualisiert wird serializer.save(), die Methode ist, die von ViewSet.update() -> ViewSet.perform_update()und aufgerufen wird ViewSet.create() -> ViewSet.perform_create(). Aber der Haken ist, dass sie nicht **kwargsmit dem Kontext weitergeben save(). Um den Kontext zu mischen, müssen wir ihn überschreiben perform_createund ihn perform_updatean übergeben save().
Boris Burkov
@andilabs könntest du mir bitte dabei helfen? stackoverflow.com/questions/62039305/…
banky
26

In der YourView- Überschreibungsmethode können Sie Folgendes tunget_serializer_context :

class YourView(GenericAPIView):

    def get_serializer_context(self):
        context = super().get_serializer_context()
        context["customer_id"] = self.kwargs['customer_id']
        context["query_params"] = self.request.query_params
        return context

oder so:

class YourView(GenericAPIView):
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        serializer.context["customer_id"] = request.user.id
        serializer.context["query_params"] = request.query_params

        serializer.is_valid(raise_exception=True)
        ...

und überall in Ihrem Serializer können Sie es bekommen. Zum Beispiel in einer benutzerdefinierten Methode:

class YourSerializer(ModelSerializer):
    def get_alternate_name(self, obj):
        customer_id = self.context["customer_id"]
        query_params = self.context["query_params"]
        ...
M.Void
quelle
Könnten
banky
@banky, ich habe einen Kommentar unter stackoverflow.com/a/62040334/6077223
M.Void
Rettete meinen Tag! Ich habe lange danach gesucht
Shamsul Arefin Sajib
9

Ein alter Code, den ich geschrieben habe und der hilfreich sein könnte, um verschachtelte Serializer zu filtern:

class MySerializer(serializers.ModelSerializer):

    field3  = serializers.SerializerMethodField('get_filtered_data')

    def get_filtered_data(self, obj):
        param_value = self.context['request'].QUERY_PARAMS.get('Param_name', None)
        if param_value is not None:
            try:
                data = Other_model.objects.get(pk_field=obj, filter_field=param_value)
            except:
                return None
            serializer = OtherSerializer(data)
            return serializer.data
        else:
            print "Error stuff"

    class Meta:
        model = Model_name
        fields = ('filed1', 'field2', 'field3')

So überschreiben Sie get_serializer_class:

class ViewName(generics.ListAPIView):

    def get_serializer_class(self):
        param_value = self.context['request'].QUERY_PARAMS.get('Param_name', None)
        if param_value is not None:
            return Serializer1
        else:
            return Serializer2

    def get_queryset(self):
       .....

Hoffe, das hilft Leuten, die danach suchen.

yeaske
quelle
4
genau das, was ich brauchte, um Abfrageparameter zu erhalten, danke! Beachten Sie, dass der angezeigte Code veraltet ist. Um Parameterwerte zu erhalten, sieht es jetzt so aus self.context['request'].query_params.get().
Nick Brady