Comment éviter les "Import cyclic" avec Django rest framework
Je vais être franc, je ne suis pas sûr de proposer une solution élégante à ce problème, mais je n'ai pas réussi à trouver mieux.
Pour illustrer le problème, il suffit de prendre le cas d'un model Utilisateur et d'un model Article qui sont chacun dans une application différente.
On souhaite créer un UserSerializer qui inclut tous les Articles de l'auteur et un ArticleSerializer qui inclut l'auteur de l'article. Personellement j'aime bien séparer mes serializers, avec dans ce cas 2 fichiers : users/serializers.py et articles/serializers.py
# users/serializers.py
from .articles import ArticleSerializer
class UserSerializer(ModelSerializer):
articles = ArticleSerializer(many=True)
class Meta:
model = User
fields = ('__all__')
# articles/serializers.py
from .users import UserSerializer
class ArticleSerializer(ModelSerializer):
user = UserSerializer()
class Meta:
model = Article
fields = ('__all__')
Cependant, avec ce système, vous allez avoir une importation cyclic pour la simple et bonne raison que Python va exécuter le code des fichiers inclus lors de l'inclusion, et donc par conséquence faire les importations des fichiers importés !
Utiliser un seul fichier
Commençons par la solution la plus simple : utiliser un seul fichier pour tous les serializers de votre application.
Cependant c'est exactement ce qui est fait dans notre exemple, nous avons deux applications
users
et
articles
, avec chacun un serializer. Cette solution est en effet intéressante par exemple
si nous avions un modèle
Categorie
pour les articles. Son serializer serait alors définis dans
le même fichier que le serializer de
Article
évitant ainsi l'importation circulaire.
Mais cela ne résout pas notre problème, avec deux applications différentes, chacun ayant son
fichier
serializers.py
.
Importer localement
La seule solution trouvée est d'utiliser une importation locale en utilisant SerializerMethodField :
# serializers/users.py
class UserSerializer(ModelSerializer):
articles = serializers.SerializerMethodField()
def get_articles(self, o):
from .articles import ArticleSerializer # On import ici, ce qui évite une inclusion circulaire
return ArticleSerializer(o.articles).data
class Meta:
model = User
fields = ('__all__')
Je ne suis pas très fier de cette solution, mais je n'ai pas trouvé mieux pour l'instant.