Django Rest Framework-如何在ModelSerializer中添加自定义字段


89

我创建了一个,ModelSerializer并希望添加一个不属于我的模型的自定义字段。

我在此处找到了添加其他字段的说明,并尝试了以下操作:

customField = CharField(source='my_field')

当我添加此字段并调用我的validate()函数时,则此字段不是attr字典的一部分。attr包含所有指定的模型字段,除了额外的字段。因此,我无法在覆盖的验证中访问此字段,可以吗?

当我将此字段添加到字段列表中时,如下所示:

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

然后我得到一个错误,因为customField它不是我的模型的一部分-正确的是因为我只想为此序列化器添加它。

有什么方法可以添加自定义字段?


您是否可以在“但是当我的字段不在序列化程序中指定的模型字段列表中时,它不属于validate()attr-dictionary的一部分。”的情况下,我不确定是否很清楚。
克里斯蒂

另外,“它抱怨-正确-我的模型中没有字段customField。”,您能否明确说明所看到的异常-谢谢!:)
Tom Christie

我更新了我的帖子,希望现在可以更清楚。我只想知道如何添加不属于我的模型的字段...
罗恩


Answers:


63

您在做正确的事情,除了CharField(和其他类型的字段)用于可写字段。

在这种情况下,您只需要一个简单的只读字段,因此只需使用:

customField = Field(source='get_absolute_url')

4
谢谢,但是我想要一个可写的字段。我传递了一个可以识别我的用户的用户令牌。但在我的模型中,我拥有用户,而不是令牌。所以我想传递令牌并通过查询将其“转换”为用户对象。
罗恩

接下来的事情是源需要针对模型属性,对吗?就我而言,我没有指向的属性。
罗恩

我不了解评论的用户/令牌位。但是,如果要在序列化器中包含一个要在还原到模型实例之前被剥离的字段,则可以使用该.validate()方法删除属性。请参阅:django-rest-framework.org/api-guide/serializers.html#validation 尽管我不太了解用例,或者为什么想要一个与字段相关联的可写字段,但这可以满足您的需求只读属性get_absolute_url
克里斯蒂

忘了get_absolute_url我只是从文档中复制并粘贴它。我只希望可以在中访问一个普通的可写字段validate()。我只是猜测我需要该source属性...
罗恩

这更有意义。:)该值应该通过传递以进行验证,因此我将仔细检查您如何实例化序列化程序,以及是否确实提供了该值。
汤姆·克里斯蒂

82

实际上,有一个解决方案完全不涉及模型。您可以使用SerializerMethodField它允许您将任何方法插入序列化程序。

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

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

6
正如OP在此评论中提到的那样,他们想要一个可写字段,而SerializerMethodField不是

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

3
如果我希望它可写怎么办?
卡萨巴·托斯

1
@Csaba:你只需要编写自定义的保存和删除挂钩附加内容:请参阅“保存和删除挂钩”下的“方法”(这里)你需要编写自定义perform_create(self, serializer)perform_update(self, serializer)perform_destroy(self, instance)
Lindauson

13

在这里回答您的问题。您应将其添加到模型帐户中:

@property
def my_field(self):
    return None

现在您可以使用:

customField = CharField(source='my_field')

来源:https : //stackoverflow.com/a/18396622/3220916


6
我在有意义的情况下使用了这种方法,但是为模型中添加的代码(仅用于特定的API调用)并不是很好。
安迪·贝克

1
您可以为
ashwoods 2014年

10

为了显示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

我一直在寻找将可写的自定义字段添加到模型序列化器的解决方案。我找到了这个,但这个问题的答案中并未涉及。

看来您确实确实需要编写自己的简单Serializer。

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

如果ModelMyModel实际上有一个名为的属性,my_custom_field但您想忽略其验证器,则这也可以工作。


因此,如果my_custom_field不是MyModel的属性,它是行不通的吗?我收到错误消息:序列化程序字段的名称可能不正确,并且与MyModel实例上的任何属性或键都不匹配。
Sandeep Balagopal

2

在阅读完所有答案后,我的结论是不可能做到这一点。您必须精打细算,做些仓促的事情,例如创建一个write_only字段,然后覆盖validateandto_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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.