Как сделать пользовательский сериализатор из модели в 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')

Как я могу добиться такого вывода? Какой тип сериализатора лучше всего подходит для получения такого вывода?

Я очень ценю любую помощь, которую вы можете оказать.

Вы можете использовать метод serializer field для всех пользовательских полей, необходимых в выводе.

Одним из способов достижения этой цели является использование 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()) сериализатора с помощью этого.

Вернуться на верх