29
In my opinion your code is fine, because you do not have a logic circular dependency.
Your ImportError
is only raised because of the way import()
evaluates top level statements of the entire file when called.
However, nothing is impossible in pythonโฆ
There is a way around it if you positively want your imports on top:
From David Beazleys excellent talk Modules and Packages: Live and Let Die! โ PyCon 2015, 1:54:00
, here is a way to deal with circular imports in python:
try:
from images.serializers import SimplifiedImageSerializer
except ImportError:
import sys
SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']
This tries to import SimplifiedImageSerializer
and if ImportError
is raised, because it already is imported, it will pull it from the importcache.
PS: You have to read this entire post in David Beazleyโs voice.
6
Separating usual and nested serializers does the trick for me.
For your structure it will be something like:
Profiles app
# profiles/serializers/common.py
from images.serializers.nested import SimplifiedImageSerializer
class ProfileSerializer(SimplifiedProfileSerializer):
recent_images = SimplifiedImageSerializer(many=True)
And nested:
# profiles/serializers/nested.py
class SimplifiedProfileSerializer(serializers.Serializer):
name = serializers.CharField()
Images app
# images/serializers/common.py
from profiles.serializers.nested import SimplifiedProfileSerializer
class ImageSerializer(SimplifiedImageSerializer):
profile = SimplifiedProfileSerializer()
And nested:
# images/serializers/nested.py
class SimplifiedImageSerializer(serializers.Serializer):
title = serializers.CharField()
- [Django]-How do you skip a unit test in Django?
- [Django]-What is the SQL ''LIKE" equivalent on Django ORM queries?
- [Django]-Django โ how to specify a database for a model?
3
you can do a local import of serializers like this:
class MySerializer(Serializer):
from app.core.serializers import AnotherSerializer
Do that in both of your imports. No need to use sys.modules
That is, as mentioned by Sebastian Wozny, that you donโt have a logical circular dependancy
- [Django]-How do I invalidate @cached_property in django
- [Django]-Update only specific fields in a models.Model
- [Django]-Convert seconds to hh:mm:ss in Python
1
You should consider having a look at Specifying nested serialization in the Rest Framework documentation. The usage of depth
meta attribute enables you to retrieve related objects to the depth you set.
It is very convenient to avoid using serializers in both sides and thus having ImportError caused by cycles.
The default ModelSerializer uses primary keys for relationships, but you can also easily generate nested representations using the depth option:
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Account
fields = ['id', 'account_name', 'users', 'created']
depth = 1
- [Django]-Do I need Nginx with Gunicorn if I am not serving any static content?
- [Django]-How to change empty_label for modelForm choice field?
- [Django]-How to compare two JSON objects with the same elements in a different order equal?
1
I just created this utility class to handle circular import problem:
from django.utils.module_loading import import_string
from django.utils.functional import cached_property
from rest_framework.serializers import RelatedField
class DynamicRelatedField(RelatedField):
def __init__(self, serializer_path=None, **kwargs):
assert serializer_path is not None, 'The `serializer_path` argument is required.'
assert kwargs['read_only'], 'Only readonly fields are supported for DynamicRelatedField'
self.serializer_path = serializer_path
super().__init__(**kwargs)
@cached_property
def serializer_object(self):
serializer_class = import_string(self.serializer_path)
return serializer_class()
def to_representation(self, obj):
return self.serializer_object.to_representation(obj)
def to_internal_value(self, data):
return None
And then, I can use it like the following:
class ProfessorDetailsSerializer(serializers.ModelSerializer):
courses = DynamicRelatedField('courses.serializers.CourseDetailsSerializer', many=True, read_only=True)
class Meta:
model = Professor
fields = ('id', 'name', 'courses')
Notes
- I used
cached_property
to prevent serializer_object creation on each instance when usingmany=True
. - This snippet doesnโt support writable fields, but adding this feature wonโt take much work
- [Django]-How to get full url from django request
- [Django]-Pass extra arguments to Serializer Class in Django Rest Framework
- [Django]-Django optional URL parameters
0
Iโd take a different approach as you do have coupling one way or another.
Iโd go with defining the serializer I actually use within the application itself.
Profile application:
# profiles/serializers.py
class SimplifiedImageSerializer(serializers.Serializer):
title = serializers.CharField()
class ProfileSerializer(SimplifiedProfileSerializer):
recent_images = SimplifiedImageSerializer(many=True)
Image application:
# images/serializers.py
class SimplifiedProfileSerializer(serializers.Serializer):
name = serializers.CharField()
class ImageSerializer(SimplifiedImageSerializer):
profile = SimplifiedProfileSerializer()
- [Django]-Django admin: how to sort by one of the custom list_display fields that has no database field
- [Django]-How to set True as default value for BooleanField on Django?
- [Django]-Django: Get list of model fields?
0
I have suffered a lot with Django Serializers Circular Dependency issue and found only two ways to solve it.
- Arranging my code in a way so that I donโt have to face circular dependency (which was not possible in my case)
- Creating separate serializer class with the serializer I need and using this new serializer where I needed. This one may not be the most efficient one but this solved my issue.
- [Django]-Raw SQL queries in Django views
- [Django]-Django โ view sql query without publishing migrations
- [Django]-Django.db.utils.OperationalError Could not connect to server