我如何 'cleanly' 在模型之间创建这种 Django/DRF 序列化关系?

How do I 'cleanly' create this Django/DRF serialization relationship between models?

我读到循环导入是 'code smell' 并且从根本上说是一个糟糕的设计选择。我有一个包含模型、用户、甲板、手的应用程序。我希望用户能够创建 Hand 而无需创建 Deck,但如果需要,还可以让用户选择将 Hand 放入 Deck 中。所以我最终得到这样的结果:

(<表示外键关系)

用户<牌组<手

&&

用户<牌组

&&

用户<手

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)

...

这是正确的方法 API-design-wise 以实现我想要的 app-design-wise 吗?如果没有,我应该怎么做呢?如果是这样,当我将用户从 ReadOnlyField 更改为 UserSerializer() 字段时,如何解决循环导入错误?

编辑:

我在想如果循环导入这种方法不好或不可能,我可以创建一个标准的单向关系,如:

用户 --> 牌组 --> 手

并有一个对用户隐藏的默认牌组,这样用户仍然可以创建 Hand 而无需创建 his/her 自己的牌组,因为它已经默认完成(只是隐藏起来)。但这也感觉像是一种 hack,我不知道这种方法是否比最初的方法更难闻。

这是正确的。假设我想请求 ID 为 1 的 Hand。我会为 /api/hands/1 发出 GET 请求,对吧?我真的希望它能序列化一个完整的用户吗?可能是。这取决于。

要绕过它,您可以定义如下内容:

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

并且您将使用它而不是 returns 一直在处理的完整 UserSerializer。