Джанго круговая модель - PullRequest
       1

Джанго круговая модель

14 голосов
/ 11 декабря 2011

Я начинаю работать над небольшим веб-сайтом по управлению футбольной лигой (в основном в учебных целях) и не могу сосредоточиться на отношениях моделей Django.Для простоты, скажем, у меня есть 2 типа объектов - игрок и команда.Естественно, игрок принадлежит к одной команде, так что это ForeignKey (Команда) в модели Player.Итак, я говорю:

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

Затем я хочу, чтобы у каждой команды был капитан, который был бы одним из игроков, чтобы он был ForeignKey (игрок) в модели команды.Но это создаст круговую зависимость.Конечно, мой опыт работы с Django ограничен, но это кажется простой проблемой, хотя я не могу понять, что я делаю неправильно в концептуальном плане.

Ответы [ 7 ]

34 голосов
/ 11 декабря 2011

Как вы можете видеть в документах , именно по этой причине можно указать стороннюю модель в виде строки.

team = models.ForeignKey('Team')
9 голосов
/ 18 декабря 2011

Вот еще один способ решения этой проблемы. Вместо создания круговой зависимости я создал дополнительную таблицу, в которой хранятся отношения между игроками и командами. В итоге это выглядит так:

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")

Может быть немного менее эффективным с точки зрения хранения, чем предложенный обходной путь, но он избегает циклической зависимости и сохраняет структуру БД чистой и ясной. Комментарии приветствуются.

6 голосов
/ 11 декабря 2011

Вы можете использовать полную метку приложения во внешнем ключе для модели, которая еще не определена, и использовать related_name, чтобы избежать конфликта имен:

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

class Player(models.Model):
    team = models.ForeignKey(Team)
2 голосов
/ 28 января 2013

Это то, что вы искали:

class Team(models.Model):
    name = models.CharField()
    captain = models.ForeignKey('Player')
class Player(models.Model):
    name = models.CharField()
    team = models.ForeignKey(Team)
1 голос
/ 12 декабря 2011

Хотя нет ничего плохого в том, чтобы иметь две ссылки на одну и ту же модель, возможно, есть лучший способ решения этой конкретной проблемы.

Добавьте логическое значение к модели 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() (вернуть капитана этой команды)

В любом случае, однакоВы должны выполнить некоторые проверки перед сохранением, чтобы убедиться, что на определенную позицию есть только один игрок.

1 голос
/ 12 декабря 2011

Иметь стол капитана, в котором есть столбцы игрока / команды вместе с другими вашими столами, и сделать капитаном метод Команды:

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)

Вам нужно убедиться, что у вас никогда не было более одного капитанахотя в той же команде ... Но у вас нет круговых ссылок таким образом.Вы также можете получить капитана, который не входит в команду, в которой он помечен как капитан.Таким образом, есть несколько ошибок.

0 голосов
/ 12 декабря 2011

Ни один из ответов здесь не настолько хорош - создание круговых ссылок никогда не было бы хорошей идеей.Представьте себе, если ваша база данных потерпела крах, и вам пришлось создавать ее с нуля - как бы вы создали игрока до создания команды, и наоборот?Посмотрите вопрос здесь: Поле ForeignKey с основным отношением поле, которое я задал несколько дней назад.Установите Boolean на Player, который определяет капитана, и установите несколько хуков перед сохранением, которые подтверждают, что каждая команда должна иметь одного-только-одного капитана.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...