使用 Django 的内置模型,如何在三个模型之间创建三重连接。
例如:
- 用户、角色和事件是模型。
- 用户有很多角色,角色也有很多用户。(多对多)
- 事件有很多用户,用户也有很多事件。(多对多)
- 但是对于任何给定的事件,任何用户可能只有一个角色。
这如何在模型中表示?
使用 Django 的内置模型,如何在三个模型之间创建三重连接。
例如:
这如何在模型中表示?
zacherates写道:
我将角色建模为用户和角色之间的关联类(...)
我也推荐了这个解决方案,但您也可以使用 Django 提供的一些语法糖:ManyToMany relationship with extra fields。
例子:
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)
我建议为此创建一个完全独立的模型。
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")
剩下的唯一一件事就是强制执行您的一个角色每个用户每个事件的限制。您可以通过覆盖保存方法(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 约束中为每个事件的每个用户强制执行一个角色。
在尝试为我自己的 Django 模型找到更快的三表连接时,我遇到了这个问题。默认情况下,Django 1.1 使用 INNER JOIN,这在 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"
与 LEFT JOIN 相比,INNER JOIN 可能非常慢。在 gimg1 的回答下可以找到更快的查询:Mysql query to join three tables
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()]