I have a model with a self referential field called parent. Model:
class Zone(BaseModel): name = models.CharField(max_length=200) parent = models.ForeignKey('self', models.CASCADE, blank=True, null=True, related_name='children') def __unicode__(self): return self.name
class ZoneSerializer(ModelSerializer): parent = PrimaryKeyRelatedField(many=False, queryset=Zone.objects.all()) parent_disp = StringRelatedField(many=False, source="parent") class Meta: model = Zone fields = ('id', 'name', 'parent', 'parent_disp')
Now I want to serialize the parent of the zone and its parent and its parent till parent is none. I found recursive serialization methods for children but not for parent. How can I do this?
Try use SerializerMethodField here:
def get_parent(self, obj): # query what your want here.
I'm not sure D-R-F has build-in methods for this, but you can use query to get what you want in this method.
Ok, I got it working like that.
class ZoneSerializer(ModelSerializer): parent = SerializerMethodField() class Meta: model = Zone fields = ('id', 'name', 'project', 'parent',) def get_parent(self, obj): if obj.parent is not None: return ZoneSerializer(obj.parent).data else: return None
Just wanted to add an additional solution that worked better for me.
The answer above using the
SerializerMethodField and then instantiating a new serializer class works nicely, but if you are trying to serialize a larger nested dataset instantiating a new serializer for each of your nested objects might become quite slow.
Trying to use a single instance of the serializer for all the nested objects made it a lot faster.
class ZoneSerializer(ModelSerializer): ... def get_parent(self, obj): if obj.parent is not None: return self.to_representation(obj) else: return None
One more step could be to also convert your return of the serializer method field to a
ReturnDict instance, which is what a serializer normally does when you call
from rest_framework.utils.serializer_helpers import ReturnDict class ZoneSerializer(ModelSerializer): ... def get_parent(self, obj): if obj.parent is not None: return ReturnDict(self.to_representation(obj), serializer=self) else: return None
There are some potential disadvantages of this approach of course, like loosing validation that happens when instantiating a serializer, harder to modify for nested objects, etc. If you are confident in your serializer setup and data being passed to the serializer this can be a nice optimization.
You also can do:
class ZoneSerializer(ModelSerializer): class Meta: model = Zone fields = ('id', 'name', 'project', 'parent',) def to_representation(self, instance): self.fields['parent'] = ZoneSerializer(read_only=True) return super(ZoneSerializer, self).to_representation(instance)