Отношение (x> 1) ко многим - PullRequest
       3

Отношение (x> 1) ко многим

1 голос
/ 26 февраля 2012

Вероятно, это более общий вопрос о базе данных, чем вопрос django, но давайте пойдем.

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

Сначала я использовал многие-ко-многим:

Match(Model):
  teams = ManyToManyField('Team', related_name='matches') #Always two teams

Это оказалось очень неэффективным для страниц, связанных с соответствием. Особенно в django 1.3, потому что нет эквивалента select_related для отношения many_to_many. И немного больно повторять, когда у вас есть ровно два элемента.

Тогда я перешел на эту модель:

Match(Model):
  teams = ManyToManyField('Team', related_name='matches') #Always two teams
  team1 = ForeignKey('Team')
  team2 = ForeignKey('Team')

Когда я хочу отобразить страницы, связанные с соответствием, я могу использовать select_related и очень эффективно отображать две команды. И когда я на странице команды, я могу следить за отношением "совпадения", чтобы получить все совпадения, как и раньше. Но я считаю, что три поля для работы с одним отношением совершенно ужасны.

Я правильно делаю? Что бы вы порекомендовали?

1 Ответ

1 голос
/ 26 февраля 2012

Я вижу там несколько решений.

1.

Если вы не ожидаете, что в будущем будет сыгран матч между другими командами, отличными от двух, лучше всего просто удалить поле ManyToMany из вашего второго дизайна:

Match(Model):
  team1 = ForeignKey('Team')
  team2 = ForeignKey('Team')

Это удалит избыточность в базе данных и упростит Match модификаций (вам не нужно беспокоиться о связности между полем team и соответствующими полями team1, team2). Это также делает невозможным создание соответствия с другим числом соответствующих команд, кроме двух, что приводит к согласованности базы данных.

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

2.

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

3.

Напишите свой собственный сборщик ManyToMany. Это не очень сложно сделать, но довольно уродливо. Вы должны выбрать команды, которые вас интересуют, и затем каким-то образом прикрепить их к объектам Match, например ::

matches # Match QuerySet
related_teams = Team.objects.filter(match__in=matches)
matches_map = {}
for t in related_teams:
    matches_map[t.match_id]= matches_map.get(t.match_id, []).append(t)

for m in matches:
    m.fetched_teams = matches_map[m.pk]

3,5.

Новая версия Django будет иметь метод prefetch_related(), предназначенный для работы с запросами ManyToMany, но, полагаю, у вас не так много времени.

...