我想序列化一个模型,但希望包含一个额外的字段,该字段需要对要序列化的模型实例进行一些数据库查找:
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序列化程序文档的其他地方;额外字段可以对应于任何属性或可在模型上调用";。是";额外字段";我在说什么?
我是否应该在Foo
的模型定义中定义一个返回my_field
值的函数,并在序列化程序中将my_field连接到该可调用函数?那是什么样子的?
如果有必要,很乐意澄清这个问题。
我认为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
您可以将模型方法更改为property,并使用此方法在序列化程序中使用它。
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),您不需要更改属性。模型方法会很好地工作。
如果您想对额外的字段进行读写,可以使用一个新的自定义序列化程序来扩展序列化程序。序列化程序,并像这样使用
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']
我在带有一些自定义逻辑的相关嵌套字段中使用这个
使用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',)
我对类似问题的回答(此处)可能很有用。
如果您有以下方式定义的模型方法:
class MyModel(models.Model):
...
def model_method(self):
return "some_calculated_result"
您可以将调用上述方法的结果添加到序列化程序中,如下所示:
class MyModelSerializer(serializers.ModelSerializer):
model_method_field = serializers.CharField(source='model_method')
p.s.由于自定义字段在您的模型中并不是一个真正的字段,您通常希望将其设为只读字段,如下所示:
class Meta:
model = MyModel
read_only_fields = (
'model_method_field',
)
如果您想为每个对象动态添加字段,您可以使用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添加键和值希望你喜欢
这对我很有效。如果我们只想在ModelSerializer
中添加一个额外的字段,我们可以按照下面的方式操作,也可以在查找的一些计算。或者在某些情况下,如果我们想发送API响应中的参数。
型号.py
class Foo(models.Model):
"""Model Foo"""
name = models.CharField(max_length=30, help_text="Customer Name")
串行化.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')
尽管这不是作者想要的,但它仍然可以被认为对这里的人有用:
如果您使用的是.save()
ModelSerializer的方法,您可以将**kwargs
传递给它。这样,您可以保存多个动态值。
即.save(**{'foo':'bar', 'lorem':'ipsum'})
正如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文档源
在序列化程序类中添加以下内容:
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['package_id'] = "custom value"
return representation