191

我想序列化一个模型,但想包含一个额外的字段,该字段需要对要序列化的模型实例进行一些数据库查找:

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 连接到该可调用对象?那看起来像什么?

如有必要,很高兴澄清这个问题。

4

9 回答 9

287

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

于 2013-08-25T06:02:58.800 回答
52

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

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),你不需要更改属性。模型方法可以正常工作。

于 2013-08-23T06:51:31.683 回答
16

使用最新版本的 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',)
于 2016-06-30T14:19:23.527 回答
15

如果你想在你的额外字段上读写,你可以使用一个新的自定义序列化程序,它扩展了 serializers.Serializer,并像这样使用它

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

我在具有一些自定义逻辑的相关嵌套字段中使用它

于 2018-05-10T10:56:25.380 回答
11

我对类似问题的回答(此处)可能有用。

如果您有以下方式定义的模型方法:

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',
        )
于 2015-04-06T16:59:51.320 回答
3

这对我有用。如果我们只想在 中添加一个额外的字段ModelSerializer,我们可以像下面那样做,并且可以在一些查找计算后为该字段分配一些 val。或者在某些情况下,如果我们想在 API 响应中发送参数。

在模型.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 ')

希望这可以帮助某人。

于 2018-07-20T11:13:17.460 回答
3

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

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 动态添加键和值,希望您喜欢它

于 2021-09-08T10:10:42.500 回答
2
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')
于 2020-08-30T01:03:13.967 回答
0

正如化学程序员此评论中所说,在最新的 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 文档源

于 2018-04-12T13:23:09.967 回答