2013-08-23 13 views
91

ich ein Modell serialisieren möchten, wollen aber ein zusätzliches Feld enthalten, die einige Datenbankabfragen auf dem Modellinstanz erfordert tun serialisiert werden:Django REST Framework: Hinzufügen zusätzlicher Feld ModelSerializer

class FooSerializer(serializers.ModelSerializer): 
    my_field = ... # result of some database queries on the input Foo object 
    class Meta: 
     model = Foo 
     fields = ('id', 'name', 'myfield') 

Was das ist richtiger Weg, dies zu tun? Ich sehe, dass you can pass in extra "context" an den Serializer, ist die richtige Antwort, um das zusätzliche Feld in einem Kontextwörterbuch übergeben? Mit diesem Ansatz würde die Logik, das Feld zu erhalten, das ich brauche, nicht mit der Serialisiererdefinition in sich geschlossen, was ideal ist, da jede serialisierte Instanz my_field benötigen wird. Anderswo in der DRF-Serializer-Dokumentation ist es says "zusätzliche Felder können jeder Eigenschaft entsprechen oder auf dem Modell abrufbar sein". Ist zusätzliche Felder, worüber ich spreche? Sollte ich eine Funktion in Foo 's Modelldefinition definieren, die my_field Wert zurückgibt, und in den Serialisierer hänge ich my_field auf diese aufrufbar? Wie sieht das aus?

Vielen Dank im Voraus, gerne die Frage zu klären, wenn nötig.

Antwort

158

Ich denke, SerializerMethodField ist das, was Sie suchen:

class FooSerializer(serializers.ModelSerializer): 
    my_field = serializers.SerializerMethodField('is_named_bar') 

    def is_named_bar(self, foo): 
     return foo.name == "bar" 

    class Meta: 
    model = Foo 
    fields = ('id', 'name', 'my_field') 

http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

+0

+1, Würde das auch für einen CustomSerializer funktionieren? –

+12

ist es möglich, solche Felder zu validieren? Meine Frage ist: Wie akzeptiere ich benutzerdefinierte POST-Werte, die validiert und im post_save() - Handler verarbeitet werden können? – Alp

+7

Beachten Sie, dass SerializerMethodField schreibgeschützt ist. Dies funktioniert nicht für eingehende POST/PUT/PATCH. –

29

Sie können Ihre Modellmethode in Eigenschaft ändern und sie mit diesem Ansatz im Serializer verwenden.

Edit: Mit den letzten Versionen von Rest Framework (ich versuchte 3.3.3), müssen Sie nicht zu Eigenschaft ändern. Die Modellmethode wird einfach funktionieren.

+0

Danke @Wasil! Ich bin nicht vertraut mit der Verwendung von Eigenschaften in Django-Modellen und kann keine gute Erklärung dafür finden, was es bedeutet. Können Sie erklären? Was ist der Sinn des @property Dekorators hier? – Neil

+2

bedeutet, dass Sie diese Methode wie eine Eigenschaft aufrufen können: d. H. 'Variable = model_instance.my_field' gibt das gleiche Ergebnis wie' variable = model_instance.my_field() 'ohne den Decorator. auch: http://stackoverflow.com/a/6618176/2198571 –

+0

Dies funktioniert nicht, zumindest in Django 1.5.1/djangorestframework == 2.3.10. Der ModelSerializer erhält das Property auch dann nicht, wenn explizit auf das Metaattribut "fields" verwiesen wird. – ygneo

8

Meine Antwort auf eine ähnliche Frage (here) nützlich sein könnten.

Wenn Sie ein Modell-Methode auf folgende Weise definiert:

class MyModelSerializer(serializers.ModelSerializer): 
    model_method_field = serializers.CharField(source='model_method') 

P. S.:

class MyModel(models.Model): 
    ... 

    def model_method(self): 
     return "some_calculated_result" 

Sie das Ergebnis des Aufrufs des Verfahrens zu Ihrem Serializer wie so hinzufügen Da das benutzerdefinierte Feld nicht wirklich ein Feld in Ihrem Modell ist, werden Sie in der Regel wollen sie nur schreib machen, etwa so:

class Meta: 
    model = MyModel 
    read_only_fields = (
     'model_method_field', 
     ) 
7

Mit der letzten Version von Django Ruhe Framework müssen Sie ein erstellen Methode in Ihrem Modell mit dem Namen des Felds, das Sie hinzufügen möchten. Keine Notwendigkeit für @property und source='field' einen Fehler auslösen.

class Foo(models.Model): 
    . . . 
    def foo(self): 
     return 'stuff' 
    . . . 

class FooSerializer(ModelSerializer): 
    foo = serializers.ReadOnlyField() 

    class Meta: 
     model = Foo 
     fields = ('foo',) 
Verwandte Themen