0

J'ai lu que les importations circulaires sont une «odeur de code» et sont fondamentalement un mauvais choix de conception. J'ai une application qui a des modèles, utilisateur, Deck, Hand. Je veux que l'utilisateur soit capable de créer une main sans avoir besoin de créer une plate-forme, mais donne également à l'utilisateur le choix de mettre la main dans la plate-forme si désiré. Donc, je me retrouve avec quelque chose comme ceci:Comment créer "proprement" cette relation de sérialisation Django/DRF entre modèles?

(< signifie ForeignKey relation)

utilisateur < Pont < main

& &

utilisateur < Pont

& &

utilisateur < main

models.py:

class User(AbstractUser): 
    pass 

class Deck(models.Model): 
    created = models.DateTimeField(auto_now_add=True) 
    name = models.CharField(max_length=100, unique=True, 
blank=False, null=False) 
    user = models.ForeignKey('users.User', related_name='decks', 
on_delete=models.CASCADE, null=False) 


class Hand(models.Model): 
    created = models.DateTimeField(auto_now_add=True) 
    deck = models.ForeignKey('goals.Deck', related_name='hands', on_delete=models.CASCADE, null=True) 
    name = models.CharField(max_length=100, blank=False, null=False) 
    user = models.ForeignKey('users.User', related_name='hands', on_delete=models.CASCADE, null=False) 

serializers.py:

class HandSerializer(serializers.HyperlinkedModelSerializer): 
    user = serializers.ReadOnlyField(source='user.username') 
    deck = serializers.CharField(required=False, source='deck.name') 

    class Meta: 
     model = Hand 
     fields = ('url', 'id', 'created', 
       'deck', 'name', 'user') 
     extra_kwargs = { 
      'url': { 
       'view_name': 'goals:hand-detail', 
      } 
     } 

class DeckSerializer(serializers.HyperlinkedModelSerializer): 
    user = serializers.ReadOnlyField(source='user.username') 
    hands = HandSerializer(many=True, read_only=True) 

    class Meta: 
     model = Deck 
     fields = ('url', 'id', 'created', 'name', 'user') 
     extra_kwargs = { 
      'url': { 
       'view_name': 'goals:deck-detail', 
      } 
     } 

class UserSerializer(serializers.HyperlinkedModelSerializer): 
    decks = DeckSerializer(many=True) 
    hands = HandSerializer(many=True) 

... 

Est-ce la bonne approche-sage API-conception afin d'obtenir ce que je veux application -conception-sage? Sinon, comment dois-je faire cela? Et si oui, comment contourner les erreurs d'importation circulaires lorsque je change d'utilisateur d'un champ ReadOnlyField à un champ UserSerializer()?

Edit:

Je pensais si cette approche était mauvaise, voire impossible, avec les importations circulaires, je pouvais créer une relation standard d'une façon comme:

utilisateur -> Pont -> main

et d'avoir une Deck par défaut cachée à l'utilisateur afin que l'Utilisateur puisse toujours créer une Main sans créer sa propre Deck car elle a déjà été faite par défaut (juste cachée). Mais cela ressemble à un hack aussi et je ne sais pas si cette approche sent plus que l'initiale.

Répondre

1

Ceci est correct. Supposons que je veuille demander une main avec l'ID 1. Je ferais une demande GET pour/api/hands/1 à droite? Est-ce que je m'attends vraiment à sérialiser un utilisateur complet avec toutes les mains de cet utilisateur? Peut être. Cela dépend juste.

Pour contourner vous définiriez quelque chose comme:

MinimalUserSerializer - Returns only email, username, and ID. - Does not return hands.

Et vous utiliseriez qu'au lieu de votre UserSerializer complet qui retourne tout le temps les mains.