web-dev-qa-db-ja.com

Django RESTフレームワーク: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')

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

事前に感謝し、必要に応じて質問を明確にします。

115
Neil

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

191
J.P.

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

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',)

編集:レストフレームワークの最新バージョン(3.3.3を試しました)では、プロパティに変更する必要はありません。モデルメソッドは正常に機能します。

34

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',)
12

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

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

class MyModel(models.Model):
    ...

    def model_method(self):
        return "some_calculated_result"

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

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

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

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

余分なフィールドで読み取りと書き込みが必要な場合は、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']

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

6
Marco Silva

これは私のために働いた。ルックアップの計算後、フィールドにvalを割り当てることができます。または、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 ')

**

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

**

1
Vinay Kumar

Chemical Programerこのコメント で述べたように、最新のDRFでは次のようにできます:

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

    def get_extra_field(self, foo_instance):
        return foo_instance.a + foo_instance.b

    class Meta:
        model = Foo
        fields = ('extra_field', ...)

DRFドキュメントソース

0
trici0pa