0

我读过的圆形进口是一个“代码味道”,是从根本上坏的设计选择。我有一个应用程序,有模型,用户,甲板,手。我希望用户能够创建一个手而不需要创建一个甲板,但如果需要,也可以让用户选择将手放在甲板上。所以,我最终是这样的:如何'干净地'在模型之间创建这个Django/DRF序列化关系?

(<意味着ForeignKey的关系)

用户<甲板<手

& &

用户<甲板

& &

用户<手

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设计明智,以达到我想要的应用程序 - 设计明智?如果不是,我该如何去做这件事?如果是这样,当我将用户从ReadOnlyField更改为UserSerializer()字段时,如何解决循环导入错误?

编辑:

我就在想,如果这种做法是不好的或不可能的圆形进口,我可以创建像一个标准的单向关系:

用户 - >甲板 - >手

,并会有从用户隐藏起来,用户仍然可以创建一个没有手,因为它已经被默认创建完成他/她自己的甲板(只是隐藏起来),默认的甲板。但是这种感觉也像是一种黑客,我不知道这种方法是否比最初的方法更有味道。

回答

1

这是正确的。假设我想要一个ID为1的手。我会为/ api/hands/1做一个GET请求吗?我真的期望它能够用一个用户的全部手来序列化一个完整的用户吗?也许。这取决于。

要解决它,你将定义是这样的:

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

你会使用而不是全UserSerializer返回手中所有的时间。

相关问题