我开始在一个小型足球联赛管理网站上工作(主要用于学习目的)并且无法围绕Django模型关系。 为简单起见,假设我有两种类型的对象 - 玩家和团队。 当然,玩家属于一个团队,因此是玩家模型中的ForeignKey(团队)。 所以我去:

class Team(models.Model):
    name = models.CharField()
class Player(models.Model):
    name = models.CharField()
    team = models.ForeignKey(Team)

然后我希望每支球队都有一名队长,这将是球员模型中的一名外国球员(球员)。 但这会产生循环依赖。 虽然我的Django体验有限,但它似乎是一个简单的问题,虽然我无法弄清楚我在概念上做错了什么。

===============>>#1 票数:35

正如您在文档中看到的那样,正是由于这个原因,可以将外部模型指定为字符串。

team = models.ForeignKey('Team')

===============>>#2 票数:9 已采纳

这是解决这个问题的另一种方法。 我创建了一个存储玩家和团队之间关系的附加表,而不是创建循环依赖。 所以最后它看起来像这样:

class Team(Model):
    name = CharField(max_length=50)

    def get_captain(self):
        return PlayerRole.objects.get(team=self).player

class Player(Model):
    first_name = CharField(max_length=50)
    last_name = CharField(max_length=50, blank=True)

    def get_team(self):
        return PlayerRole.objects.get(player=self).team

PLAYER_ROLES = (
    ("Regular", "Regular"),
    ("Captain", "Captain")
    )

class PlayerRole(Model):
    player = OneToOneField(Player, primary_key=True)
    team = ForeignKey(Team, null=True)
    role = CharField(max_length=20, choices=PLAYER_ROLES, default=PLAYER_ROLES[0][0])
    class Meta:
        unique_together = ("player", "team")

它的存储效率可能略低于建议的解决方法,但它避免了循环依赖性并保持数据库结构清晰。 欢迎评论。

===============>>#3 票数:7

您可以在尚未定义的模型的外键中使用完整的应用程序标签,并使用related_name来避免名称冲突:

class Team(models.Model):
    captain = models.ForeignKey('myapp.Player', related_name="team_captain")

class Player(models.Model):
    team = models.ForeignKey(Team)

===============>>#4 票数:2

这就是你要找的东西:

class Team(models.Model):
    name = models.CharField()
    captain = models.ForeignKey('Player')
class Player(models.Model):
    name = models.CharField()
    team = models.ForeignKey(Team)

===============>>#5 票数:1

拥有一个队长表,其中包含球员/球队列以及其他表格,并使队长成为球队的一种方法:

class Team(models.Model):
    name = models.CharField()
    def captain(self):
      [search Captain table]
      return thePlayer

class Player(models.Model):
    name = models.CharField()
    team = models.ForeignKey(Team)

class Captain(models.Model):
    player = models.ForeignKey(Player)
    team = models.ForeignKey(Team)

你必须检查你在同一个团队中从来没有超过一个队长......但是你没有这样的循环引用。 你也可能最终得到一名不属于他被标记为队长的队长。 所以这有一些陷阱。

===============>>#6 票数:1

虽然对同一模型有两个引用没有任何问题,但也许有更好的方法来解决这个特定的问题。

Team模型中添加一个布尔值,以将玩家+团队组合标识为队长:

class Team(models.Model):
  player = models.ForeignKey(Player)
  name = models.CharField(max_length=50)
  is_captain = models.BooleanField(default=False)

要搜索团队的队长:

Team.objects.filter(is_captain=True)

我个人不喜欢这种方法,因为搜索语义没有意义(即“团队”不是“队长”)。

另一种方法是识别每个球员的位置:

class Player(models.Model):
   name = models.CharField(max_length=50)
   position = models.IntegerField(choices=((1,'Captain'),(2,'Goal Keeper'))
   jersey = models.IntegerField()

   def is_captain(self):
     return self.position == 1

class Team(models.Model):
   name = models.CharField(max_length=50)
   player = models.ForeignKey(Player)

   def get_captain(self):
      return self.player if self.player.position == 1 else None

搜索时这会更有意义:

Player.objects.filter(position=1) (返回所有队长)

Team.objects.get(pk=1).get_captain() (返回该团队的队长)

在任何一种情况下,你都必须做一些预先保存检查,以确保只有一个特定位置的玩家。

===============>>#7 票数:0

这里的答案都不是那么好 - 创建循环引用从来都不是一个好主意。 想象一下,如果您的数据库崩溃并且您必须从头开始创建 - 在创建团队之前如何创建播放器,反之亦然? 在这里看一个问题:几天前我问过的具有主要关系的ForeignKey字段 在播放器上放置一个指定队长的布尔值,并放置一些预保存挂钩,验证每个团队必须拥有一个且只有一个队长。

  ask by exfizik translate from so

未解决问题?本站智能推荐: