Django REST Framework:向ModelSerializer添加其他字段

Nei*_*eil 122 django rest django-rest-framework

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

class FooSerializer(serializers.ModelSerializer):
  my_field = ... # result of some database queries on the input Foo object
  class Meta:
        model = Foo
        fields = ('id', 'name', 'myfield')
Run Code Online (Sandbox Code Playgroud)

这样做的正确方法是什么?我看到你可以将额外的"上下文"传递给序列化器,是在上下文字典中传入附加字段的正确答案吗?使用这种方法,获得我需要的字段的逻辑不会与串行器定义一起自包含,这是理想的,因为每个序列化实例都需要my_field.在DRF序列化器文档的其他地方,它 "额外的字段可以对应于模型上的任何属性或可调用".我正在谈论的是额外的领域吗?我应该在Foo模型定义中定义一个返回my_field值的函数吗?在序列化器中我将my_field挂钩到那个可调用的函数?那是什么样的?

在此先感谢,如有必要,请尽快澄清问题.

小智 199

我认为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')
Run Code Online (Sandbox Code Playgroud)

http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

  • 在DRF 3中,它被更改为`field_name = serializers.SerializerMethodField()`和`def get_field_name(self,obj): (21认同)
  • 请注意,SerializerMethodField是只读的,因此这对传入的POST/PUT/PATCH不起作用. (19认同)
  • 是否可以为这些字段添加验证?我的问题是:如何接受可以在post_save()处理程序中验证和处理的自定义POST值? (18认同)
  • 当定义 SerializerMethodField 时,`foo` 是什么?使用 CreateAPIView 时,foo 是否已存储然后可以使用 is_named_bar() 方法? (2认同)

Was*_*zyk 36

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

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',)
Run Code Online (Sandbox Code Playgroud)

编辑:使用最新版本的rest框架(我尝试过3.3.3),您不需要更改为属性.模型方法将正常工作.

  • 你需要将字段添加到序列化程序,因为它不是*real*modelfield:my_field = serializers.Field(source ='my_field') (9认同)
  • 这意味着你可以像一个属性一样调用这个方法:即`variable = model_instance.my_field`给出与`variable = model_instance.my_field()`相同的结果而没有装饰器.还有:http://stackoverflow.com/a/6618176/2198571 (2认同)
  • `source ='my_field'`不再需要并引发异常 (2认同)

Gui*_*ent 13

使用最新版本的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',)
Run Code Online (Sandbox Code Playgroud)

  • 如果 foo 的值来自请求怎么办? (4认同)

Maj*_*esh 10

如果你想为每个对象动态添加字段,你可以使用 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
Run Code Online (Sandbox Code Playgroud)

通过这种方式,您可以动态地为每个对象添加键和值希望您喜欢它


Lin*_*son 9

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

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

class MyModel(models.Model):
    ...

    def model_method(self):
        return "some_calculated_result"
Run Code Online (Sandbox Code Playgroud)

您可以将调用所述方法的结果添加到序列化程序中,如下所示:

class MyModelSerializer(serializers.ModelSerializer):
    model_method_field = serializers.CharField(source='model_method')
Run Code Online (Sandbox Code Playgroud)

ps由于自定义字段实际上不是模型中的字段,因此您通常希望将其设置为只读,如下所示:

class Meta:
    model = MyModel
    read_only_fields = (
        'model_method_field',
        )
Run Code Online (Sandbox Code Playgroud)


小智 9

如果您想在多余的字段上进行读写,则可以使用新的自定义序列化程序,该序列化程序扩展了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']
Run Code Online (Sandbox Code Playgroud)

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


Vin*_*mar 5

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

在模型.py中

class Foo(models.Model):
    """Model Foo"""
    name = models.CharField(max_length=30, help_text="Customer Name")
Run Code Online (Sandbox Code Playgroud)

在序列化器.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 ')
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助某人。