I want to make a custom serializer from a model.
I want output like this:
{
'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'
}
}
Here is my model:
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)
Here is the serializer code:
class RoadSerializer(serializers.ModelSerializer):
class Meta:
model = Road
exclude = ['created', 'updated']
Here is the view:
@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)
put URL like this
path(r'view/list/<pk>', views.get_road, name='road')
How can I achieve that output? Which type of serializer is best to get this kind of output?
I really appreciate any help you can provide.
You can override .to_representation()
of serializers. You could start with this:
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
I just simplified resolving type
for each field in this answer. You could tweak it to use a function that maps a serializer field to a specific string.
Although you would probably have to do this for every serializer you need the custom output however you still retain the other functionalities (like .create()
, .update()
) of the serializer with this.
One way that you can achieve this is by using SerializerMethodField() for all the custom fields similar to the code below:
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',
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.