Django Rest-Framework serialization

Django Rest-Framework (DRF) is the go to library when it comes to creating production quality Rest APIs for a Django application.

Recently I have been working on a bunch of different APIs and have come across some issues whose solutions aren't that obvious reading the documentation. Usually ended up finding links to particular manual pages from Stack Overflow.

Anyway, here are some notable quirks/issues I came across and their solutions:


Nested Data

So, say you have data that needs to be serialized in a nested dict.

{ 'top_level_dict':{'level1'{'level2':some_data}}}

My first instinct is to use SerializerMethodField() but if you don't have any super convoluted pre processing that you need to do on the raw data, you could simply extract some_data by simply specifying the level using the dot notation. So, my some_data attribute in the serializer would become:

class MySerializer(serializers.Serializer):  
    some_data = serializers.CharField(source='top_level_dict.level1.level2')

That should save a few lines of code.


SerializerMethodField doesn't respect source

SerializerMethodField() has an exposed source kwarg but it isn't respected. Which means, this won't work.

class MySerializer(serializers.Serializer):  
    some_data = serializers.SerializerMethodField(source='get_me_icecream')

    def get_me_icecream(self):
        return "some_data"

It's going to use getattr(data, 'get_' + name_of_the_attribute) which comes to be getattr(data, 'get_some_data') in this case. So it's actually going to look for get_<name of the attribute> in the data object as opposed to going for the method you specify in source.


Can't use SerializerMethodField for a nested serializer

If your data object has a nested object b in this example that is to be passed to a separate serializer:

data_dict = {  
    'a': {
        'id0': 'Some Data'

    },
    'b': [
        {'id': 'key1', 'value': 'value1',},
        {'id': 'key2', 'value': 'value2',},
        {'id': 'key3', 'value': 'value3',},
        {'id': 'key4', 'value': 'value4',}
    ]
}

You can't/shouldn't use the SerializerMethodField() to pass the part of the object to a new serializer and return it using the data attribute on the serializer. So, this is bad:

class MySerializer(serializers.Serializer):  
    some_data = serializers.SerializerMethodField()

    def get_some_data(self, obj):
        return SecondSerializer(obj, many=True).data 

Instead, you should do something like this, directly:

class MySerializer(serializers.Serializer):  
    some_data = SecondSerializer(many=True)

Let DRF do the rest.


Specifying source with the same name as attribute is redundant and will raise an exception

If something is redundant, it should be a warning as opposed to breaking the flow. So if you specify a source the same name as the attribute, it'll raise an exception as opposed to logging a warning.

class MySerializer(serializers.Serializer):  
    some_data = serializers.CharField(source='some_data')

This was a part of the DRF 3.0 release announcement


There are a bunch of new features expected in 3.1 but there are so many features that aren't apparent in the current documentation. DRF won't be my first choice to build an API but I've got to admit, it's pretty good when it works. Combined with Swagger it's pretty incredible.