简体   繁体   中英

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

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM