Index ¦ Archives ¦ Atom ¦ RSS

Using multiple serializers with DjangoRestFramework

How to use different serializers with DjangoRestFramework

Imagine to have a viewset and you want to parametrize the output, using different serializers.

class Person(models.Model):
    title = models.CharField(...)
    last_name = models.CharField(...)
    first_name = models.CharField(...)
    mail = models.EmailField(...)
    address = models.CharField(...)
    birthday = models.DateField()

class PersonSerializer(HouseSerializer):    
    full_name = serializers.SerializerMethodField()

    class Meta:
        model = House
        fields = ('title', 'last_name', 'first_name', 'mail', 'full_name')

    def get_full_name(self, obj):
        return "{0.last_name}, {1.first_name}".format(obj)

class PersonView(DynamicSerializerMixin, generics.ListAPIView):
    queryset = House.objects.all()
    serializer_class = HouseSerializer

it is easy to build a "serializer factory" to build on the fly

cache = {}

def serializer_factory(model, base=ModelSerializer, fields=None, exclude=None):
    attrs = {'model': model}
    if fields is not None:
        attrs['fields'] = fields
    if exclude is not None:
        attrs['exclude'] = exclude

    parent = (object,)
    if hasattr(base, 'Meta'):
        parent = (base.Meta, object)
    Meta = type(str('Meta'), parent, attrs)
    if model:
        class_name = model.__name__ + 'Serializer'
    else:
        class_name = 'Serializer'
    return type(base)(class_name, (base,), {'Meta': Meta, })


class DynamicSerializerMixin(object):
    serializers_fieldsets = {'std': None}
    serializer_class = ModelSerializer

    def get_serializer_class(self):
        ser = self.request.QUERY_PARAMS.get('serializer', 'std')
        if ser not in cache:                
            fields = self.serializers_fieldsets.get(ser, 'std')
            cache[ser] =  serializer_factory(self.model,
                                  self.serializer_class,
                                  fields=fields)

        return cache[ser]

adopt it:

class PersonView(DynamicSerializerMixin, generics.ListAPIView):
    queryset = Person.objects.all()
    serializer_class = PersonSerializer
    serializers_fieldsets = {'std': PersonSerializer,
                             'simple': ('first_name', 'last_name')
                             }

invoke it:

?serializer=std
?serializer=simpleA

© 2014 Stefano Apostolico. Built using Pelican. Member of the Internet Defense League.