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.
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 : serializers/users.py et serializers/articles.py
# serializers/users.py from .articles import ArticleSerializer class UserSerializer(ModelSerializer): articles = ArticleSerializer(many=True) class Meta: model = User fields = ('__all__') # serializers/articles.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’inclusions, et donc par conséquence faire les importations des fichiers importés !
La solution la plus élégante 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__')
Donc, si vous avez des solutions plus propres, plus élégantes, et bien je suis preneur !
pourquoi ne pas utiliser __all__ dans le fichier init?
Je ne suis pas certain de l’utilisation de __all__ dans le fichier __init__.py change grand chose. Normalement on utilise __all__ pour définir ce qui sera importé quand on fait un from .mymodule import *
Mais de toute façon, en relisant ce post aujourdh’ui je me rend compte que le vrai problème n’est pas tant l’import cyclique, mais le design des serializers qui est cyclique.
Ce post ayant 3 ans, il faudrait que je prenne le temps de repasser sur les vieux articles que j’ai fais pour les corriger.