2013-08-23 11 views
91

voglio serializzare un modello, ma di includere un campo aggiuntivo che richiede facendo alcune ricerche nei database nell'istanza modello da serializzato:Django REST quadro: l'aggiunta di ulteriore campo di 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') 

Qual è la modo giusto per fare questo? Vedo che you can pass in extra "context" per il serializzatore, è la risposta giusta per passare nel campo aggiuntivo in un dizionario di contesto? Con questo approccio, la logica di ottenere il campo di cui ho bisogno non sarebbe autonoma con la definizione di serializzatore, che è l'ideale poiché ogni istanza serializzata avrà bisogno di my_field. Altrove nella documentazione dei serializzatori DRF è says "campi aggiuntivi possono corrispondere a qualsiasi proprietà o chiamabile sul modello". Sono campi extra di cosa sto parlando? Devo definire una funzione nella definizione del modello di Foo che restituisce il valore my_field e nel serializzatore collego my_field a tale chiamabile? Che aspetto ha?

Grazie in anticipo, felice di chiarire la domanda se necessario.

risposta

158

Penso SerializerMethodField è quello che stai cercando:

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, Potrebbe funzionare anche per un CustomSerializer? –

+12

è possibile aggiungere la convalida a tali campi? la mia domanda è: come accettare i valori POST personalizzati che possono essere validati e processati nel gestore post_save()? – Alp

+7

Nota che SerializerMethodField è di sola lettura, quindi non funzionerà con POST/PUT/PATCH in arrivo. –

29

È possibile modificare il metodo del modello in proprietà e utilizzarlo in serializzatore con questo approccio.

Modifica: Con le versioni recenti di rest framework (ho provato 3.3.3), non è necessario modificare la proprietà. Il metodo del modello funzionerà correttamente.

+0

Grazie @Wasil! Non ho familiarità con l'uso delle proprietà nei modelli Django e non riesco a trovare una buona spiegazione di cosa significhi. Puoi spiegare? Qual è il punto del decoratore @property qui? – Neil

+2

significa che puoi chiamare questo metodo come una proprietà: ad esempio 'variable = model_instance.my_field' dà lo stesso risultato di' variable = model_instance.my_field() 'senza il decoratore. anche: http://stackoverflow.com/a/6618176/2198571 –

+0

Questo non funziona, almeno in Django 1.5.1/djangorestframework == 2.3.10. ModelSerializer non sta ottenendo la proprietà anche se esplicitamente indicato nell'attributo Meta "fields". – ygneo

8

La mia risposta a una domanda simile (here) potrebbe essere utile.

Se si dispone di un metodo del modello definito nel seguente modo:

class MyModel(models.Model): 
    ... 

    def model_method(self): 
     return "some_calculated_result" 

È possibile aggiungere il risultato della chiamata tale metodo al vostro serializzatore in questo modo:

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

P.S. Dal momento che il campo personalizzato non è davvero un campo nel modello, è solitamente desidera rendere di sola lettura, in questo modo:

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

Con l'ultima versione di Django Resto Framework, è necessario creare un metodo nel tuo modello con il nome del campo che vuoi aggiungere. Non è necessario per @property e source='field' generare un errore.

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

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

    class Meta: 
     model = Foo 
     fields = ('foo',) 
Problemi correlati