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

正确的做法是什么?我看到你可以传入额外的“context”;到序列化器,是在上下文字典中传递附加字段的正确答案吗?

使用这种方法,获取我需要的字段的逻辑将不包含在序列化器定义中,这是理想的,因为每个序列化实例都需要my_field。在DRF序列化器文档的其他地方额外字段可以对应于模型上的任何属性或可调用项。是“额外字段”;我在说什么?

我是否应该在Foo的模型定义中定义一个返回my_field值的函数,并在序列化器中将my_field连接到该可调用对象?它看起来像什么?

如果有必要,我很乐意澄清问题。

159502 次浏览

您可以将模型方法更改为属性,并使用此方法在序列化器中使用它。

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),您不需要更改属性。模型方法可以很好地工作。

我认为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

我对类似问题(在这里)的回答可能有用。

如果你有一个模型方法定义如下:

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

在上一个版本的Django Rest Framework中,你需要在你的模型中创建一个带有你想要添加的字段名称的方法。不需要@propertysource='field'引发错误。

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


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


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

正如化学程式设计师这样的评论中所说,在最新的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 docs source

如果你想读写额外的字段,你可以使用一个新的自定义序列化器,它扩展了序列化器。序列化器,像这样使用它

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']

我使用这个相关的嵌套字段与一些自定义逻辑

< p > 这对我有用。 如果我们只想在ModelSerializer中添加一个额外的字段,我们可以做到 做它像下面,也字段可以分配一些val后 查找的一些计算。或者在某些情况下,如果我们想发送

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

希望这能帮助到一些人。

class Demo(models.Model):
...
@property
def property_name(self):
...

如果你想使用相同的属性名:

class DemoSerializer(serializers.ModelSerializer):
property_name = serializers.ReadOnlyField()
class Meta:
model = Product
fields = '__all__' # or you can choose your own fields

如果你想使用不同的属性名,只需更改这个:

new_property_name = serializers.ReadOnlyField(source='property_name')

如果你想为每个对象动态添加字段,你可以使用to_representation。

class FooSerializer(serializers.ModelSerializer):
class Meta:
model = Foo
fields = ('id', 'name',)
  

def to_representation(self, instance):
representation = super().to_representation(instance)
if instance.name!='': #condition
representation['email']=instance.name+"@xyz.com"#adding key and value
representation['currency']=instance.task.profile.currency #adding key and value some other relation field
return representation
return representation
通过这种方式,您可以为每个obj动态添加键和值 希望你喜欢

尽管这不是作者想要的,但它仍然可以被认为对这里的人有用:

如果你正在使用.save() ModelSerializer的方法,你可以将**kwargs传递给它。这样,您就可以保存多个动态值。

例如.save(**{'foo':'bar', 'lorem':'ipsum'})

在序列化器类中添加以下内容:

def to_representation(self, instance):
representation = super().to_representation(instance)
representation['package_id'] = "custom value"
return representation