介绍一种最常见的数据库关系:在Django中理解多对一。
什么是多对一关系?
在数据库设计中,多对一(或一对多)是指一个或多个实体之间的关系,其中一个实体可以连接多个实体。
让我们举个例子。考虑两个实体:母亲和女儿。正如我们从现实生活中所知,这两个实体在大多数情况下都是这样联系在一起的:
所以我们这里有多对一,多是女儿,一是母亲。
用形似“乌鸦脚”的实体关系图可以这样描述:
在母亲那一边,你可以看到两条线,代表有且仅有一个。这是关系的“一面”。对应的,在女儿那边你可以看到鱼尾纹和一个圆圈。
圆圈是指任意数量的,也就是说,可以有零个、一个或多个女儿。严格地说,一个母亲至少应该有一个女儿才符合她的身份,但我想让你了解这种表示方法。
一只乌鸦的脚上面有一条直线(横线),这意味着至少有一个或多个,也就是说,关系的多面不能是空的。
现在,在用实体关系图对数据库建模之后,是时候编写实际的SQL指令了。在这个时代,你经常不想手动来做。
然而,通过实践来了解多对一关系是如何实现的很重要。让我们看看。
实践中的多对一关系
要在多对一关系中连接两个实体,我们需要在数据库中至少有两个表。以母亲为例,我们将有一个母亲表(示例用PostgreSQL方言显示):
女儿呢?这是“多”的一面。当然,我们可以创造另一张表,就像我们的母亲表一样:
但现在,我们该如何连接这两张表呢?这是用外键完成的。外键就像它的字面意思一样:它是一个从一个表指向另一个表的键(外键)。在添加之前,让我们删除旧表并创建一张包含名为mother_id列的新表:
mother_id 将为每个女儿提供相应的母亲。现在我们也准备好了添加约束:
通过这条语句我们向数据库发出指令:向列mother_id添加一个新外键,并让它指向mother表中的id列。
有了这些知识,现在让我们把注意力集中在Django的多对一上。
在Django中了解多对一
在测试之前,您需要创建一个新的Django项目和一个名为address_book的Django应用程序。
为了演示Django中的多对一,让我们再举一个例子。考虑两个实体:用户和联系人。对于这些实体,我们说:
想像一个地址簿,其中有许多用户通过昵称标识,每个用户的地址簿中可以有许多联系人:
joel89的通讯簿中有abc@abc.dev、jules@jules.io、joe@joe.dev
jules84的通讯簿中有def@abc.dev、vale@vale.io、john@john.dev
等等。转换为实体关系图,它变成:
现在要在Django应用程序中创建这些实体(模型),我们可以使用Django.db.models。我们创建了两个模型,每个模型都有相应的字段:
下一步,在Django配置中注册应用程序之后,我们运行python manage.py makemigrations和python manage.py migrate来在数据库中创建新表。
这将创建两个尚未连接的表。是时候添加外键了!
在Django理解多对一:外键
为了将这两个实体连接起来,以便将多个联系人连接到单个用户,Django提供了ForeignKey。可以在模型中添加以下字段:
在这里,我们添加一个名为user的新列,该列使用ForeignKey引用用户模型。确保运行python manage.py makemigrations和python manage.py migrate以应用更改。
需要注意的是,ForeignKey至少需要两个参数:
To描述要指向的实体。相应的,on_delete描述当关系的“一”被删除时数据库的行为。当“一”实体被删除时,“多”实体也被删除。
另一件需要注意的事情是,Django做的事情与其他框架有些不同。有些框架允许您有一对多关系,其中“多”的一面可以在“一”中定义。举个例子,拉雷维尔一对多就是这样。
最后的结果是相同的:“多”表将始终与“一”的外键相连接。
现在我们可以使用Django的ORM进行查询了。
在Django中理解多对一:创建相关对象
要测试结果,请进入Django控制台:
接下来导入两个模型,用户和联系人:
现在用一个用户填充数据库:
并创建一组与该用户相关的联系人:
创建新联系人是通过传递用户来作为create方法的参数,以将这两个实体绑定在一起。有了这些实体,我们现在可以进行查询了。
在Django中理解多对一:获取相关对象
要从我们的数据库访问用户,我们可以运行:
如果在我们的示例中只有一个用户,可以运行:
现在,获取与该用户相关的每个联系人该怎么做?使用Django ORM,我们可以使用表单下的查找功能,形式是.related_set,其中related是我们要访问的实体的名称。
因此,要获取用户的所有联系人(用户有许多联系人),我们可以运行:
此查询返回:
还有一种反向的查询:从联系人返回到相关用户(联系人有一个用户):
此查询返回我们联系人的相应用户:
英文原文:https://www.valentinog.com/blog/many-to-one/
译者:QL