I'm fighting with circular dependencies within serializers in my web API written using Django Rest Framework 3. Whereas I know that circular dependencies in a project is almost always a sign of bad design, I can't find a decent way of avoiding it without making the app a big monolithic nightmare.
A simple stripped down example pictures well enough what happens in all places I'm having the similar problem.
Let's have two simple models in two apps:
Profiles app
# profiles/models.py
from images.models import Image
class Profile(models.Model):
name = models.CharField(max_length=140)
def recent_images(self):
return Image.objects.recent_images_for_user(self)
Images app
# images/models.py
class Image(models.Model):
profile = models.ForeignKey('profiles.Profile')
title = models.CharField(max_length=140)
Following the principle of fat models I often use multiple imports in my models to allow easy retrieval of related objects using methods on Profile, but that rarely causes circular dependencies, since I rarely do the same from the other end.
The problem begins when I try to add serializers to the bunch. To make the API footprint small and limit the amount of necessary calls to the minimum, I want to serialize on both ends some of the related objects in their simplified forms.
I want to be able to retrieve profiles on /profile
endpoint that will have simplified info about few recent images created by the user nested. Also, when retrieving images from /images
endpoint I'd like to have profile info embedded in the image JSON.
To achieve this and avoid recursive nesting, I have two serializers - one that nests related objects, and one that does not, for both apps.
Profiles app
# profiles/serializers.py
from images.serializers import SimplifiedImageSerializer
class SimplifiedProfileSerializer(serializers.Serializer):
name = serializers.CharField()
class ProfileSerializer(SimplifiedProfileSerializer):
recent_images = SimplifiedImageSerializer(many=True)
Images app
# images/serializers.py
from profiles.serializers import SimplifiedProfileSerializer
class SimplifiedImageSerializer(serializers.Serializer):
title = serializers.CharField()
class ImageSerializer(SimplifiedImageSerializer):
profile = SimplifiedProfileSerializer()
The expected behaviour is to get the following JSON results:
Profiles app at /profiles
[{
'name': 'Test profile',
'recent_images': [{
'title': 'Test image 1'
}, {
'title': 'Test image 2'
}]
]]
Images app at /images
[{
'title': 'Test image 1',
'profile': {
'name': 'Test profile'
}
},
{
'title': 'Test image 2',
'profile': {
'name': 'Test profile'
}
}]
but then I hit the wall with circular imports of the serializers.
I feel that joining those two apps into one is definitely not the road to take - after all, images are something completely different from user profiles.
The serializers also in my view should belong to their respective apps.
The only way to go around this problem I found as of now is import in the method as follows:
class ImageSerializer(SimplifiedProfileSerializer):
profile = SerializerMethodField()
def get_profile(self, instance):
from profiles.serializers import SimplifiedProfileSerializer
return SimplifiedProfileSerializer(instance.profile).data
but that feels like an ugly, ugly, uuuugly hack.
Could you please share your experience with similar problems?
Thanks!
question from:
https://stackoverflow.com/questions/33413523/circular-dependency-in-django-rest-framework-serializers