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

Posted

技术标签:

【中文标题】Django Rest Framework - 如何在 ModelSerializer 中添加自定义字段【英文标题】:Django Rest Framework - How to add custom field in ModelSerializer 【发布时间】:2013-01-13 01:51:09 【问题描述】:

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

我找到了添加额外字段here 的说明,我尝试了以下方法:

customField = CharField(source='my_field')

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

当我像这样将此字段添加到字段列表时:

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

然后我收到一个错误,因为 customField 不是我的模型的一部分 - 什么是正确的,因为我只想为这个序列化程序添加它。

有没有办法添加自定义字段?

【问题讨论】:

您能否扩展“但是当我的字段不在序列化程序中指定的模型字段列表中时,它不是 validate() attr-dictionary 的一部分。”,我不确定这是不是很清除。 另外,“它抱怨 - 正确 - 我的模型中没有 customField 字段。”,您能否明确说明您看到的异常 - 谢谢! :) 我更新了我的帖子,希望现在更清楚。我只想知道如何添加一个不属于我的模型的字段... How to extend model on serializer level with django-rest-framework Django REST Framework: adding additional field to ModelSerializer的可能重复 【参考方案1】:

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

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

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

【讨论】:

正如this comment 中提到的OP,他们想要一个可写字段,而SerializerMethodFields 不是【参考方案2】:

你做对了,除了CharField(和其他类型的字段)是用于可写字段的。

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

customField = Field(source='get_absolute_url')

【讨论】:

谢谢,但我想要一个可写字段。我传递了一个标识我的用户的特定用户令牌。但在我的模型中,我有用户而不是令牌。所以我想传递令牌并通过查询将其“转换”为用户对象。 接下来的事情是源需要以模型属性为目标,对吧?就我而言,我没有指向的属性。 我不明白评论的用户/令牌位。但是,如果您想在序列化程序中包含一个字段,该字段在您恢复到模型实例之前被剥离,您可以使用.validate() 方法来删​​除该属性。请参阅:django-rest-framework.org/api-guide/serializers.html#validation 这可以满足您的需求,尽管我并不真正了解用例,或者为什么您想要一个与 只读 绑定的 writable 字段/b> 属性get_absolute_url? 忘记get_absolute_url 我只是从文档中复制并粘贴它。我只想要一个可以在validate() 中访问的普通可写字段。我只是猜想我需要source 属性... 这更有意义。 :) 该值应该被传递以进行验证,所以我会仔细检查您如何实例化序列化程序,以及是否确实提供了该值。【参考方案3】:

...为清楚起见,如果您有以下方式定义的模型方法:

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

【讨论】:

如果我想让它可写怎么办? @Csaba:您只需要为附加内容编写自定义保存和删除挂钩:请参阅“方法”下的“保存和删除挂钩”(Here)您需要编写自定义perform_create(self, serializer)perform_update(self, serializer)perform_destroy(self, instance)【参考方案4】:

这里回答你的问题。 您应该添加到您的模型帐户:

@property
def my_field(self):
    return None

现在你可以使用了:

customField = CharField(source='my_field')

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

【讨论】:

我已经使用了这种方法,但它并不适合为模型添加额外代码以用于仅真正用于特定 API 调用的事物。 你可以为写一个代理模型【参考方案5】:

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

【讨论】:

【参考方案7】:

我正在寻找一种将可写自定义字段添加到模型序列化程序的解决方案。我找到了这个,这个问题的答案中没有涉及到。

看来您确实需要编写自己的简单序列化器。

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

现在您可以使用此 Serializer 将自定义字段添加到 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 的属性但您想忽略它的验证器,这也有效。

【讨论】:

所以如果 my_custom_field 不是 MyModel 的属性,它就不起作用,对吗?我收到错误序列化程序字段可能命名不正确,并且与MyModel 实例上的任何属性或键都不匹配。【参考方案8】:

在这里阅读所有答案后,我的结论是不可能干净地做到这一点。您必须玩弄脏话并做一些像创建 write_only 字段这样的事情,然后覆盖 validateto_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

【讨论】:

如果你设置了write_only=True,那你为什么还要设置def to_representation?听起来你既想读又想写....

以上是关于Django Rest Framework - 如何在 ModelSerializer 中添加自定义字段的主要内容,如果未能解决你的问题,请参考以下文章

Django Rest Framework api如何为所有人添加身份验证权限

如何处理 django-rest-framework 中 url 模式中的外键关系

Django REST Framework:如何用空字符串替换 null?

Django Rest Framework:在 ViewSet 上打开分页(如 ModelViewSet 分页)

Django Rest Framework - 如何为所有 ModelSerializer 字段创建自定义错误消息?

使用 django-rest-framework-simplejwt 注册后返回令牌