Используя встроенные модели Django, как можно создать тройное соединение между тремя моделями.
Например:
Как это можно представить в модели?






Я бы рекомендовал просто создать для этого совершенно отдельную модель.
class Assignment(Model):
user = ForeignKey(User)
role = ForeignKey(Role)
event = ForeignKey(Event)
Это позволяет вам делать все обычные модельные вещи, такие как
user.assignment_set.filter(role__name = "Chaperon")
role.assignment_set.filter(event__name = "Silly Walkathon")
Осталось только ввести в действие ограничение «одна роль на пользователя для каждого события». Вы можете сделать это в классе Assignment, переопределив метод сохранения (http://docs.djangoproject.com/en/dev/topics/db/models/#overriding-predefined-model-methods) или используя сигналы (http://docs.djangoproject.com/en/dev/topics/signals/)
Я бы смоделировал роль как класс ассоциации между пользователями и ролями, таким образом,
class User(models.Model):
...
class Event(models.Model):
...
class Role(models.Model):
user = models.ForeignKey(User)
event = models.ForeignKey(Event)
И установите одну роль для каждого пользователя для каждого события в ограничениях менеджера или SQL.
зачерат пишет:
I'd model Role as an association class between Users and Roles (...)
Я также рекомендовал бы это решение, но вы также можете использовать некоторый синтаксический сахар, предоставляемый Django: Отношение ManyToMany с дополнительными полями.
Пример:
class User(models.Model):
name = models.CharField(max_length=128)
class Event(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(User, through='Role')
def __unicode__(self):
return self.name
class Role(models.Model):
person = models.ForeignKey(User)
group = models.ForeignKey(Event)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
Это довольно новая возможность в Django (начиная с версии 1.0).
Пытаясь найти более быстрое объединение трех таблиц для моих собственных моделей Django, я столкнулся с этим вопросом. По умолчанию Django 1.1 использует ВНУТРЕННИЕ СОЕДИНЕНИЯ, которые могут быть медленными на InnoDB. Для запроса вроде:
def event_users(event_name):
return User.objects.filter(roles__events__name=event_name)
это может создать следующий SQL:
SELECT `user`.`id`, `user`.`name` FROM `user` INNER JOIN `roles` ON (`user`.`id` = `roles`.`user_id`) INNER JOIN `event` ON (`roles`.`event_id` = `event`.`id`) WHERE `event`.`name` = "event_name"
ВНУТРЕННИЕ СОЕДИНЕНИЯ могут быть очень медленными по сравнению с ЛЕВЫМИ СОЕДИНЕНИЯМИ. Еще более быстрый запрос можно найти в ответе gimg1: Запрос mysql для объединения трех таблиц
SELECT `user`.`id`, `user`.`name` FROM `user`, `roles`, `event` WHERE `user`.`id` = `roles`.`user_id` AND `roles`.`event_id` = `event`.`id` AND `event`.`name` = "event_name"
Однако вам нужно будет использовать собственный SQL-запрос: https://docs.djangoproject.com/en/dev/topics/db/sql/
В этом случае это будет выглядеть примерно так:
from django.db import connection
def event_users(event_name):
cursor = connection.cursor()
cursor.execute('select U.name from user U, roles R, event E' \
' where U.id=R.user_id and R.event_id=E.id and E.name = "%s"' % event_name)
return [row[0] for row in cursor.fetchall()]
Разве
unique_together = ('user', 'event')не достаточно для одной роли на пользователя на каждое ограничение события?