Django Rest Framework-ModelSerializerにカスタムフィールドを追加する方法


88

を作成しModelSerializer、モデルの一部ではないカスタムフィールドを追加したいと考えています。

ここにフィールドを追加するための説明を見つけ、次のことを試しました。

customField = CharField(source='my_field')

このフィールドを追加してvalidate()関数を呼び出すと、このフィールドはattr辞書の一部ではなくなります。attr追加のフィールドを除く、指定されたすべてのモデルフィールドが含まれます。上書きされた検証でこのフィールドにアクセスできませんか?

このフィールドを次のようにフィールドリストに追加すると、

class Meta:
    model = Account
    fields = ('myfield1', 'myfield2', 'customField')

次にcustomField、がモデルの一部ではないためにエラーが発生します。このシリアライザのためだけに追加したいので、何が正しいのでしょうか。

カスタムフィールドを追加する方法はありますか?


「しかし、私のフィールドがシリアライザで指定されたモデルフィールドリストにない場合、それはvalidate()attr-dictionaryの一部ではありません。」について詳しく説明してもらえますか。
トムクリスティ

また、「モデルにcustomFieldフィールドがないと不平を言う-正しく-」、あなたが見ている例外について明示的に教えてもらえますか-ありがとう!:)
トムクリスティ

私は私の投稿を更新し、それが今より明確になることを願っています。私だけ...私は私のモデルの一部ではないフィールドを追加する方法を知りたい
ロン・


回答:


62

あなたは正しいことをしていますが、CharField(そして他の型付けされたフィールドは)書き込み可能なフィールドのためのものです。

この場合、単純な読み取り専用フィールドが必要なので、代わりに次のように使用します。

customField = Field(source='get_absolute_url')

4
ありがとう、でも書き込み可能なフィールドが欲しい。ユーザーを識別する特定のユーザートークンを渡します。しかし、私のモデルでは、トークンではなくユーザーを持っています。トークンを渡して、クエリを介してユーザーオブジェクトに「変換」したいのです。
Ron

次はソースがモデル属性をターゲットにする必要があるということですよね?私の場合、ポイントする属性がありません。
Ron

コメントのユーザー/トークンビットがわかりません。ただし、モデルインスタンスに復元する前に取り除かれるフィールドをシリアライザーに含める場合は、.validate()メソッドを使用して属性を削除できます。:参照してくださいdjango-rest-framework.org/api-guide/serializers.html#validation 私は本当にユースケースを理解していないのに、あなたが必要とする何だろう、またはあなたが欲しい理由を書き込み可能な Aに結び付けられていますフィールドを読み取り専用プロパティget_absolute_url
トムクリスティー

get_absolute_urlドキュメントからコピー&ペーストしたことを忘れてください。でアクセスできる通常の書き込み可能なフィールドが必要ですvalidate()。私はsource属性が必要だと思っていました...
Ron

それはもっと理にかなっています。:)値は検証のために渡される必要があるため、シリアライザをどのようにインスタンス化しているか、およびその値が実際に提供されているかどうかを再確認します。
Tom Christie

82

実際には、すべてのモデルに触れることなく解決策があります。を使用SerializerMethodFieldして、シリアライザに任意のメソッドを接続できます。

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

    def get_foo(self, obj):
        return "Foo id: %i" % obj.pk

4
OPがこのコメントで述べたように、彼らは書き込み可能なフィールドを望んでいますが、そうでSerializerMethodFieldはありません
esmail

14

...わかりやすくするために、次の方法でモデルメソッドを定義している場合:

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

2
書き込み可能にしたい場合はどうなりますか?
Csaba Toth 2015

1
@Csaba:(「メソッド」の下を参照してください「の保存と削除フック」:あなたは、追加コンテンツのためのフックの保存や削除、書き込みカスタムする必要がありますここであなたが書き込みカスタムする必要があります)perform_create(self, serializer)perform_update(self, serializer)perform_destroy(self, instance)
リンダウソン2015

13

ここであなたの質問に答えてください。モデルアカウントに追加する必要があります。

@property
def my_field(self):
    return None

今あなたは使うことができます:

customField = CharField(source='my_field')

ソース:https : //stackoverflow.com/a/18396622/3220916


6
このアプローチは意味があるときに使用しましたが、特定のAPI呼び出しでのみ実際に使用されるもののためにモデルに追加のコードを追加するのはよくありません。
アンディベイカー

1
次のプロキシモデルを記述できます
ashwoods 2014

9

表示するself.author.full_nameには、でエラーが発生しましたField。それはで働いたReadOnlyField

class CommentSerializer(serializers.HyperlinkedModelSerializer):
    author_name = ReadOnlyField(source="author.full_name")
    class Meta:
        model = Comment
        fields = ('url', 'content', 'author_name', 'author')

6

Django Rest Frameworkの最新バージョンでは、追加するフィールドの名前を使用してモデルにメソッドを作成する必要があります。

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

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

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

3

モデルシリアライザーに書き込み可能なカスタムフィールドを追加するためのソリューションを探していました。私はこれを見つけましたが、この質問への回答には含まれていません。

確かに、独自のシンプルなシリアライザを作成する必要があるようです。

class PassThroughSerializer(serializers.Field):
    def to_representation(self, instance):
        # This function is for the direction: Instance -> Dict
        # If you only need this, use a ReadOnlyField, or SerializerField
        return None

    def to_internal_value(self, data):
        # This function is for the direction: Dict -> Instance
        # Here you can manipulate the data if you need to.
        return data

これで、このシリアライザーを使用して、カスタムフィールドをModelSerializerに追加できます

class MyModelSerializer(serializers.ModelSerializer)
    my_custom_field = PassThroughSerializer()

    def create(self, validated_data):
        # now the key 'my_custom_field' is available in validated_data
        ...
        return instance

これは、モデルMyModelに実際に呼び出されるプロパティmy_custom_fieldがあるが、そのバリデーターを無視したい場合にも機能します。


0

ここですべての回答を読んだ後、私の結論は、これをきれいに行うことは不可能であるということです。ダーティプレイを行い、write_onlyフィールドを作成するなどの厄介なことを実行し、validateおよびto_representationメソッドをオーバーライドする必要があります。これは私のために働いたものです:

class FooSerializer(ModelSerializer):

    foo = CharField(write_only=True)

    class Meta:
        model = Foo
        fields = ["foo", ...]

    def validate(self, data):
        foo = data.pop("foo", None)
        # Do what you want with your value
        return super().validate(data)

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data["foo"] = whatever_you_want
        return data
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.