2013-08-23 14 views
91

Chcę serializacji modelu, ale chcesz dołączyć dodatkowe pole, które wymaga robi kilka wyszukiwań bazy danych na przykład modelowego być szeregowane:Django REST ramowa: dodając dodatkowe pole do 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') 

Jaki jest Właściwy sposób to zrobić? Widzę, że you can pass in extra "context" do serializera, jest właściwą odpowiedzią do przekazania w dodatkowym polu w słowniku kontekstowym? Dzięki takiemu podejściu logika uzyskania potrzebnej mi dziedziny nie byłaby niezależna od definicji serializera, co jest idealne, ponieważ każda wystąpienie serializowane będzie wymagać my_field. Gdzie indziej w serializacjach DRF dokumentacja to says "dodatkowe pola mogą odpowiadać dowolnej właściwości lub można ją wywoływać na modelu". Czy dodatkowe pola, o których mówię? Czy powinienem zdefiniować funkcję w definicji modelu Foo, która zwraca wartość my_field, a w serializatorze podłączam my_field do tego wywołania? Jak to wygląda?

Z góry dziękuję, chętnie wyjaśniam pytanie w razie potrzeby.

Odpowiedz

158

myślę SerializerMethodField jest to, czego szukasz:

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, czy to też działa w przypadku CustomSerializer? –

+12

Czy można dodać sprawdzanie poprawności do takich pól? moje pytanie brzmi: jak zaakceptować niestandardowe wartości POST, które można zwalidować i przetwarzać w procedurze post_save()? – Alp

+7

Należy zauważyć, że SerializerMethodField jest tylko do odczytu, więc nie będzie działać dla przychodzących POST/PUT/PATCH. –

29

Możesz zmienić metodę swojego modelu na właściwość i używać jej w serializatorze z tym podejściem.

Edytuj: W przypadku niedawnych wersji reszta ramy (próbowałem 3.3.3), nie trzeba zmieniać na właściwość. Metoda modelu po prostu działa dobrze.

+0

Dzięki @Wasil! Nie jestem zaznajomiony z używaniem właściwości w modelach Django i nie mogę znaleźć dobrego wyjaśnienia, co to znaczy. Możesz wytłumaczyć? Jaki jest sens dekoratora @property? – Neil

+2

oznacza to, że możesz wywołać tę metodę jak własność: to jest 'variable = model_instance.my_field' daje taki sam wynik jak' variable = model_instance.my_field() 'bez dekoratora. także: http://stackoverflow.com/a/6618176/2198571 –

+0

To nie działa, przynajmniej w Django 1.5.1/djangorestframework == 2.3.10. ModelSerializer nie uzyskuje właściwości, nawet jeśli jest explicite przywoływany w metodzie "fields". – ygneo

8

Moja odpowiedź na podobne pytanie (here) może być przydatne.

Jeśli masz metodę modeli zdefiniowane w następujący sposób:

class MyModel(models.Model): 
    ... 

    def model_method(self): 
     return "some_calculated_result" 

można dodać wyniku wywołania tego sposobu do serializatora tak:

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

PS: Ponieważ pole zwyczaj nie jest to dziedzina, w modelu, będziesz zazwyczaj chcemy, aby było tylko do odczytu, tak jak poniżej:

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

z ostatnią wersją Rest Django Framework, trzeba stworzyć metoda w twoim modelu z nazwą pola, które chcesz dodać. Nie ma potrzeby zgłaszania błędu przez @property i source='field'.

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

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

    class Meta: 
     model = Foo 
     fields = ('foo',) 
Powiązane problemy