Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it possible to dynamically change field name within django-rest-framework serializer?

I have Product and ProductCategory models.

Let's say I have ProductCategory TV, which has Sony, Samsung as its products. I also have MobilePhone category with Apple and Nokia as its products. Using DRF, I would like to get JSON output using serializers, which is similar to the below:

{
    'TV': 
        [
            'Sony': 
                {
                    'price': '$100',
                    'country': 'Japan',
                },
            'Samsung': 
                {
                    'price': '$110',
                    'country': 'Korea',
                }
        ]

    'mobile_phone':
        [
            'Apple': 
                {
                    'price': '$300',
                    'country': 'USA',
                },
            'Nokia': 
                {
                    'price': '$210',
                    'country': 'Finland',
                }
        ]
}

The problem here is that the field names('TV', 'mobile_phone') in serializer have to be dynamic.

I know I can get the following JSON type

{ 
    [
            {   
                'product_category': 'TV',
                'manufacturer: 'Sony',
                'price': '$100',
                'country': 'Japan',
            },
            {
                'product_category': 'TV',
                'manufacturer: 'Samgsung',
                'price': '$110',
                'country': 'Korea',
            }
    ]

    [
            {
                'product_category': 'mobile_phone',
                'manufacturer: 'Samgsung',
                'price': '$300',
                'country': 'USA',
            },
            {
                'product_category': 'mobile_phone',
                'manufacturer: 'Apple',
                'price': '$210',
                'country': 'Finland',
            }
    ]
}

with

class CategorySerializer(serializers.Serializer):
    product_category = serializer.CharField()
    manufacturer = serializer.CharField()
    price = serializer.CharField()
    country = serializer.CharField()

But the dynamically-changing-field-names is difficult to achieve. Is there any way I can do this?

like image 844
Bossam Avatar asked Apr 01 '17 12:04

Bossam


People also ask

How do I update user details in Django REST framework?

Open auth/urls.py and add update profile endpoint. we should send a PUT request to API for checking update profile endpoint. We must add username, first_name, last_name and email. If fields passed validations, user profile will be changed.

Do we need Serializers in Django REST framework?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

How do you pass extra context data to Serializers in Django REST framework?

In function based views we can pass extra context to serializer with "context" parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with "self. context". From example, to get "exclude_email_list" we just used code 'exclude_email_list = self.


1 Answers

You can support this kind of custom format by overriding to_representation of your Serializer and of the default ListSerializer:

  1. First, you override to_representation of your serializer:

    class CategorySerializer(serializers.Serializer):
        # your fields here
    
        def to_representation(self, obj):
          return {
              obj.manufacturer: {
                 'price': obj.price,
                 'country': obj.country
              }
          }
    

    So that your serialized categories are of this form:

    {
        'Sony': {
          'price': '$100',
          'country': 'Japan'
        }
    }
    
  2. Then to prepend the product_category in front of your list, you can use a custom ListSerializer with a custom to_representation:

    class CategoryListSerializer(serializers.ListSerializer):
    
        def to_representation(self, data):
            # Group your data entries by category here
            ...
            return {
                'TV': tv_data
                'mobile_phone': mobile_data
            }
    
    class CategorySerializer(serializers.Serializer):
        ...
        class Meta:
          list_serializer_class = CategoryListSerializer
    
like image 161
pchiquet Avatar answered Oct 01 '22 23:10

pchiquet