Following on from this answer, I've attempted to reverse serialize objects from a many to many relationship.
Using a serializer method field, I've tried to populate the people that have a person type however this is causing a RecursionError
from django.
I can see the issue, PersonA
has PersonTypeA
who has PersonA
etc. but I'm not sure how to 'flatten' the returned people to one level.
How can I overcome the recursion error?
Models:
class PersonType(models.Model):
name = models.CharField(max_length=128)
created = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now_add=True)
start_time = models.DateTimeField()
end_time = models.DateTimeField(null=True)
class Person(models.Model):
title = models.CharField(max_length=16)
first_name = models.CharField(max_length=128)
last_name = models.CharField(max_length=128)
email_address = models.CharField(max_length=256)
created = models.DateTimeField(auto_now_add=True)
last_updated = models.DateTimeField(auto_now_add=True)
start_time = models.DateTimeField()
end_time = models.DateTimeField(null=True)
person_types = models.ManyToManyField(PersonType, related_name="people")
Serializers:
class PersonTypeSerializer(serializers.ModelSerializer):
people = serializers.SerializerMethodField()
class Meta:
model = PersonType
fields = '__all__'
def get_people(self, obj):
people = obj.people.all()
response = PersonSerializer(people, many=True).data
return response
class PersonSerializer(serializers.ModelSerializer):
person_types = PersonTypeSerializer(many=True)
class Meta:
model = Person
fields = '__all__'
depth = 1
The RecursionError
is happening not directly because of the models but rather due to the form on how you are trying to serialize your data.
If a Person
instance is included in a Type
that contains that Person
then you enter in a never ending recursion loop where your serializers
are eternally calling each other.
To solve the error immediately, instead of trying to serialize the QuerySet from your SerializerMethodField
, return its values instead:
class PersonTypeSerializer(serializers.ModelSerializer):
people = serializers.SerializerMethodField()
class Meta:
model = PersonType
fields = '__all__'
def get_people(self, obj):
people = obj.people.all()
return people.values()
class PersonSerializer(serializers.ModelSerializer):
...
Also, I need to point out that you are trying to use depth
to represent the nested relation. But instead, by creating your own serializer (PersonTypeSerializer), you are overriding it, so you could just have one serializer and let the framework traverse it for you:
class PersonSerializer(serializers.ModelSerializer):
class Meta:
model = Person
fields = '__all__'
depth = 1
Although, that would not return people
field which is part of your customization. Meaning that depth
in this case is useless.