如何使用 Django 创建三联表
Posted
技术标签:
【中文标题】如何使用 Django 创建三联表【英文标题】:How to create a triple-join table with Django 【发布时间】:2010-09-09 12:47:07 【问题描述】:使用 Django 的内置模型,如何在三个模型之间创建三重连接。
例如:
用户、角色和事件是模型。 用户有很多角色,角色有很多用户。 (多对多) 事件有很多用户,用户也有很多事件。 (多对多) 但是对于任何给定的事件,任何用户可能只有一个角色。如何在模型中表示?
【问题讨论】:
【参考方案1】:zacherates 写道:
我将角色建模为用户和角色之间的关联类 (...)
我也推荐了这个解决方案,但您也可以使用 Django 提供的一些语法糖:ManyToMany relation 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)
【讨论】:
这在 Django 中是相当新的(从 1.0 开始)。【参考方案2】:我建议为此创建一个完全独立的模型。
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/) 在 Assignment 类中执行此操作
【讨论】:
unique_together = ('user', 'event')
对于每个事件约束的每个用户一个角色还不够吗?【参考方案3】:
我将角色建模为用户和角色之间的关联类,因此,
class User(models.Model):
...
class Event(models.Model):
...
class Role(models.Model):
user = models.ForeignKey(User)
event = models.ForeignKey(Event)
并在经理或 SQL 约束中为每个事件的每个用户强制执行一个角色。
【讨论】:
【参考方案4】:在尝试为我自己的 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()]
【讨论】:
以上是关于如何使用 Django 创建三联表的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Django Migrations 重新创建已删除的表?
如何使用不会将删除级联到其子级的 ForeignKeys 创建 Django 模型?
如何获取使用 django bulk_create 创建的对象的主键