Django REST Framework:ModelSerializerにフィールドを追加する


147

モデルをシリアル化したいが、シリアル化するモデルインスタンスでいくつかのデータベースルックアップを実行する必要がある追加のフィールドを含めたい:

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

これを行う正しい方法は何ですか?余分な「コンテキスト」をシリアライザに渡すことができる思いますが、コンテキストディクショナリの追加フィールドを渡す正しい答えは何ですか。そのアプローチでは、必要なフィールドを取得するロジックはシリアライザ定義で自己完結することはなく、すべてのシリアル化されたインスタンスがを必要とするため理想的ですmy_field。他の場所でDRFシリアライザのドキュメントでそれは言う、「追加のフィールドは、モデル上の任意のプロパティまたは呼び出し可能に対応させることができます」。余分なフィールドは私が話していることですか?Fooのモデル定義でmy_field値を返す関数を定義し、シリアライザでmy_fieldをその呼び出し可能オブジェクトにフックする必要がありますか?それはどのように見えますか?

よろしくお願いします。必要に応じて、質問を明確にします。

回答:


224

SerializerMethodFieldはあなたが探しているものだと思います:

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


19
そのようなフィールドに検証を追加することは可能ですか?私の質問は、post_save()ハンドラーで検証および処理できるカスタムPOST値をどのように受け入れるかです。
Alp

20
SerializerMethodFieldは読み取り専用であるため、これは受信POST / PUT / PATCHでは機能しません。
スコットA

24
DRF 3には、に変更されるfield_name = serializers.SerializerMethodField()def get_field_name(self, obj):
化学プログラマー

1
fooSerializerMethodFieldを定義するときはどうですか?CreateAPIViewを使用する場合、fooは保存されているか、それからis_named_bar()メソッドを使用できますか?
244boy 2017年

したがって、この答えに基づいて、たとえば12個の追加フィールドをシリアライザに渡したい場合は、foo.field_customを返すだけのフィールドごとに12個の特定のメソッドを定義する必要があります。
AlxVallejo

41

モデルのメソッドをプロパティに変更して、このアプローチでシリアライザーで使用できます。

class Foo(models.Model):
    . . .
    @property
    def my_field(self):
        return stuff
    . . .

class FooSerializer(ModelSerializer):
    my_field = serializers.ReadOnlyField(source='my_field')

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

編集:最近のバージョンのRESTフレームワーク(3.3.3を試しました)では、プロパティを変更する必要はありません。モデルメソッドはうまくいきます。


@Wasilに感謝!私はDjangoモデルでのプロパティの使用に精通しておらず、それが何を意味するのかについての適切な説明を見つけることができません。説明できますか?ここで@propertyデコレータのポイントは何ですか?
ニール

2
つまり、このメソッドをプロパティのように呼び出すことができます。つまり、デコレータなしの場合variable = model_instance.my_fieldと同じ結果が得られvariable = model_instance.my_field()ます。また:stackoverflow.com/a/6618176/2198571
Wasil Sergejczyk 2013

1
これは、少なくともDjango 1.5.1 / djangorestframework == 2.3.10では機能しません。「フィールド」メタ属性で明示的に参照されていても、ModelSerializerはプロパティを取得していません。
ygneo 2014年

9
実際のモデルフィールドではないため、シリアライザーにフィールドを追加する必要があります。my_field= serializers.Field(source = 'my_field')
Marius

2
source='my_field' は必要なくなり、例外が発生します
Guillaume Vincent

13

Django Rest Frameworkの最新バージョンでは、追加するフィールドの名前を使用してモデルにメソッドを作成する必要があります。必要はありません@propertyし、source='field'エラーを発生させます。

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

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

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

requestfooの値を変更できるdef foo(self)内にオブジェクトが必要な場合はどうなりますか?(request.userベースの検索の例)
saran3h

1
fooの値がリクエストからのものである場合はどうなりますか?
saran3h

11

同様の質問(ここ)に対する私の回答が役に立つかもしれません。

次の方法で定義されたモデルメソッドがある場合:

class MyModel(models.Model):
    ...

    def model_method(self):
        return "some_calculated_result"

上記のメソッドを呼び出した結果をシリアライザに次のように追加できます。

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

psカスタムフィールドは実際にはモデル内のフィールドではないため、通常は次のように読み取り専用にする必要があります。

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

10

追加のフィールドで読み書きしたい場合は、serializers.Serializerを拡張した新しいカスタムシリアライザーを使用して、次のように使用できます。

class ExtraFieldSerializer(serializers.Serializer):
    def to_representation(self, instance): 
        # this would have the same as body as in a SerializerMethodField
        return 'my logic here'

    def to_internal_value(self, data):
        # This must return a dictionary that will be used to
        # update the caller's validation data, i.e. if the result
        # produced should just be set back into the field that this
        # serializer is set to, return the following:
        return {
          self.field_name: 'Any python object made with data: %s' % data
        }

class MyModelSerializer(serializers.ModelSerializer):
    my_extra_field = ExtraFieldSerializer(source='*')

    class Meta:
        model = MyModel
        fields = ['id', 'my_extra_field']

私はいくつかのカスタムロジックで関連するネストされたフィールドでこれを使用します


2

これは私にとってうまく いきました.ModelSerializerにフィールドを追加するだけの場合は、以下のように行うことができます。また、ルックアップの計算後にフィールドに値を割り当てることができます。または、APIレスポンスでパラメータを送信する場合。

model.py

class Foo(models.Model):
    """Model Foo"""
    name = models.CharField(max_length=30, help_text="Customer Name")



   **

serializer.py

**

class FooSerializer(serializers.ModelSerializer):
    retrieved_time = serializers.SerializerMethodField()

    @classmethod
    def get_retrieved_time(self, object):
        """getter method to add field retrieved_time"""
        return None

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

**

これが誰かを助けることを願っています

**


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.