如何从 django rest 框架中的模型制作自定义序列化程序?

How to make custom serializer from model in django rest framework?

我想从模型制作自定义序列化程序。

我想要这样的输出:

{
  'name': {
    'value': 'field value from model',
    'type': 'String',  # 'what the model field type like: String'
  },
  'number': {
    'value': 'field value from model',
    'type': 'Number',  # 'what the model field type like: Number'
  },
  'type': {
    'value': 'field value from model',
    'type': 'Choice',  # 'what the model field type like: Choice'
    'options': ['Paved', 'UnPaved']
  },
  'category': {
    'value': 'field value from model',
    'type': 'Choice',  # 'what the model field type like: Choice'
    'options': ['primary', 'secondary']
  },
  'width': {
    'value': 'field value from model',
    'type': 'Number',  # 'what the model field type like: Number'
  }
}

这是我的模型:

class Road(models.Model):
  name = models.CharField(max_length=250, null=True)
  number = models.CharField(max_length=200, null=True)
  type = models.CharField(max_length=100, null=True)
  category = models.CharField(max_length=200, null=True)
  width = models.FloatField(null=True)
  created = models.DateTimeField(auto_now_add=True)
  updated = models.DateTimeField(auto_now=True)

这是序列化程序代码:

class RoadSerializer(serializers.ModelSerializer):
  class Meta:
    model = Road
    exclude = ['created', 'updated']

视图如下:

@api_view(['GET'])
def get_road(request, pk=None):

   queryset = Road.objects.all()
   road= get_object_or_404(queryset, pk=pk)
   serializer = RoadSerializer(road)
   return Response(serializer.data)

把URL像这样

path(r'view/list/<pk>', views.get_road, name='road')

如何实现该输出? 哪种类型的序列化程序最适合获得这种输出?

非常感谢您提供的任何帮助。

实现此目的的一种方法是对所有自定义字段使用 SerializerMethodField(),类似于以下代码:

class RoadSerializer(serializers.ModelSerializer):
  name = serializers.SerializerMethodField()
  number = serializers.SerializerMethodField()
  type = serializers.SerializerMethodField()
  category = serializers.SerializerMethodField()
  width = serializers.SerializerMethodField()
   
  class Meta:
    model = Road
    fields = (
         "name",
         "number",
         "type",
         "category",
         "width",
    )
    exclude = ['created', 'updated']
  def get_name(self, road)
    return {
      'value': road.name,
      'type': 'String',
    }
  def get_number(selft, road)
    return {
      'value': road.number,
      'type': 'Number',
    }
  def get_type(self, road)
    return {
      'value': road.type,
      'type': 'Choice',
      'options': ['Paved', 'UnPaved']
    }
 def get_category(self, road)
    return {
      'value': road.category,
      'type': 'Choice',
      'options': ['primary', 'secondary']
    }
 def get_width(self, road)
    return {
      'value': road.width,
      'type': 'Number',
    }

您可以覆盖 .to_representation() 序列化程序。你可以从这个开始:

class RoadSerializer(serializer.ModelSerializer):
    # ...

    def to_representation(self, obj):
        base_representation = super().to_representation(obj)
        fields = self.get_fields()

        new_representation = OrderedDict()
        for field_name, value in base_representation.items():
            field = fields.get(field_name, None)
            parsed_value = {
                'value': value,
            }

            if field:
                parsed_value['type'] = field.__class__.__name__

            if isinstance(field, serializers.ChoiceField):
                parsed_value['options'] = field.choices

            new_representation[field_name] = parsed_value

        return new_representation

我只是简化了此答案中每个字段的解析 type。您可以调整它以使用将序列化程序字段映射到特定字符串的函数。

虽然您可能必须为每个需要自定义输出的序列化程序执行此操作,但是您仍然保留序列化程序的其他功能(如 .create().update())。