I'm using Django 1.6 (very soon upgrading to 1.8), Python 2.7, and DRF 3.2.5 (very soon upgrading to latest).
I've got a set of deeply nested serializers (~10 levels deep, with a total of 20-30 models that are serialized). I'm trying to add a boolean flag to the context, which will determine whether the serialized output hierarchy will be detailed (include all models' fields) or basic (part of the fields only).
I wrote the following code (partial snippet):
from rest_framework import serializers
from app.models import Institute, Department, Member
class MemberSerializer(serializers.ModelSerializer):
def get_fields(self):
fields = super(MemberSerializer, self).get_fields()
if self.context['basic_view']:
for field in ['height', 'weight']:
del fields[field]
return fields
class Meta:
model = Member
fields = ('id', 'birth_date', 'height', 'weight')
class DepartmentSerializer(serializers.ModelSerializer):
members = MemberSerializer(many=True, read_only=True)
def get_fields(self):
fields = super(DepartmentSerializer, self).get_fields()
if self.context['basic_view']:
for field in ['type', 'manager']:
del fields[field]
return fields
class Meta:
model = Department
fields = ('id', 'name', 'type', 'manager', 'members')
class InstituteSerializer(serializers.ModelSerializer):
departments = DepartmentSerializer(many=True, read_only=True)
def get_fields(self):
fields = super(InstituteSerializer, self).get_fields()
if self.context['basic_view']:
for field in ['name', 'type']:
del fields[field]
return fields
class Meta:
model = Institute
fields = ('id', 'name', 'type', 'departments')
def get_entities(is_basic_view):
institutes_list = Institute.objects.all()
serializer = InstituteSerializer(institutes_list, many=True, read_only=True, context={'basic_view': is_basic_view})
return serializer.data
But then found out that the 'context' that is passed from 'get_entities' to 'InstituteSerializer' is not passed-on to the nested serializers. Meaning that in the example above - InstituteSerializer has 'basic_view' in the 'context', but MemberSerializer & DepartmentSerializer don't.
I found a working solution in context in nested serializers django rest framework : to use SerializerMethodField per nested field (e.g. 'departments'), and in the 'get_' method to manually pass-on the context. My problem with that solution is that it requires embedding this code 20-30 times in my code, eventually doubling the number of source lines.
My request - if someone has (or can help implement) an extension for serializers.ModelSerializer, which will get an additional parameter upon construction, e.g. 'inherit_context'. Then the only thing I'll need to change in my classes, for example in 'InstituteSerializer', is the addition of that parameter:
class InstituteSerializer(serializers.ModelSerializer):
departments = DepartmentSerializer(many=True, read_only=True, inherit_context=True)
def get_fields(self):
fields = super(InstituteSerializer, self).get_fields()
if self.context['basic_view']:
for field in ['name', 'type']:
del fields[field]
return fields
class Meta:
model = Institute
fields = ('id', 'name', 'type', 'departments')
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.
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.
The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.
DRF provides a Serializer class that gives you a powerful, generic way to control the output of your responses, as well as a ModelSerializer class that provides a useful shortcut for creating serializers that deal with model instances and querysets.
Apparently I missed something... The 'context' is already inherited down to the nested serializers...
However, the reason it didn't work for me, is because as part of my nesting, some of the child serializers were defined via serializers.SerializerMethodField(). And in such as case (only!) the context is not automatically inherited.
The solution is to simply pass-on the 'context', within the 'get_...' method related to each SerializerMethodField:
class ParentSerializer(serializers.ModelSerializer):
child = serializers.SerializerMethodField()
def get_child(self, obj):
child = ....
serializer = ChildSerializer(instance=child, context=self.context)
return serializer.data
P.S - a DRF github issue similar to mine was created a while ago: https://github.com/tomchristie/django-rest-framework/issues/2555
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With