Как сделать пользовательский сериализатор из модели в 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()) сериализатора с помощью этого.