8. 数据库表的关联
操作系统: windows
IDE: Pycharm
后端系统开发中, 数据库设计是重中之重。特别是前后端分离的系统, 后端的职责基本就是数据管理, 开发的代码几乎都是围绕数据操作的。
因此,常用的数据库表和表之间的关系的设计就很重要。
目前使用的数据库系统主要还是关系型数据库(建立在关系模型基础上的数据库) 。
- 常见的关系型数据库:mysql、oracle、 sqlserver、SQLite ;
- 常见的非关系型数据库:mongodb;
而关系型数据库,设计的一个难点就是各种表之间的关联关系 。
常见的3种关联关系就是: 一对多 , 一对一 , 多对多
一对多:
表之间一对多的关系,就是外键关联关系
现在系统中, 已经定义了客户(Customer)这张表 :
class Customer(models.Model):# 客户名称name = models.CharField(max_length=200)# 联系电话phonenumber = models.CharField(max_length=200)# 地址address = models.CharField(max_length=200)
还需要定义药品(Medicine)这张表,包括药品名称、编号和描述 这些信息。
添加如下的类定义:
class Medicine(models.Model):# 药品名name = models.CharField(max_length=200)# 药品编号sn = models.CharField(max_length=200)# 描述desc = models.CharField(max_length=200)
接下来我们还要定义 订单(Order)这张表,这个Order表包括创建日期、客户、药品、数量。
其中:
客户字段对应的客户 只能是 Customer 中的某个客户记录,也就是说Order表里面的一条订单记录的客户对应 Customer表里面的一条客户记录。
而且一个客户记录可以对应多条订单记录。
这就是一对多的关系:
像这种一对多的关系,数据库中是用外键来表示的。
如果一个表中的某个字段是外键,那就意味着这个外键字段的记录的取值,只能是它关联表的某个记录的主键的值。
我们定义表的 Model类的时候,如果没有指定主键字段,migrate
的时候 Django 会为该Model对应的数据库表自动生成一个id
字段,作为主键。
比如,我们这里,Customer、Medicine表均没有主键,但是在migrate
之后,查看数据库记录就可以发现有一个id字段,且该字段是主键 (primary key)。
Django中用models.ForeignKey()
方法实现一对一的关系,如下:
common/models.py:
from django.db import models
import datetime# Create your models here.#存放数据库表对象class Customer(models.Model):#客户名称name = models.CharField(max_length=200) #对应数据库中的varchar#联系电话phonenumber = models.CharField(max_length=200)#地址address = models.CharField(max_length=200)class Medicine(models.Model):# 药品名name = models.CharField(max_length=200)# 药品编号sn = models.CharField(max_length=200)# 描述desc = models.CharField(max_length=200)class Order(models.Model):# 订单名name = models.CharField(max_length=200, null=True, blank=True)# 创建日期create_date = models.DateTimeField(default=datetime.datetime.now)# 客户 customer字段是外键, 和Customer类的主键关联customer = models.ForeignKey(Customer, on_delete=models.PROTECT)
补充:
on_delete
参数指定了当我们删除外键指向的主键记录时, 系统的行为。
on_delete 不同取值对应不同的做法,常见的做法如下:
- CASCADE:删除主键记录和相应的外键表记录
比如,我们要删除客户张三,在删除了客户表中张三记录同时,也删除Order表中所有这个张三的订单记录。
- PROTECT:禁止删除记录
比如,我们要删除客户张三,如果Order表中还有张三的订单记录,Django系统就会抛出ProtectedError
类型的异常,当然也就禁止删除客户记录和相关的订单记录了。
除非我们将Order表中所有张三的订单记录都先删除掉,才能删除该客户表中的张三记录。
- SET_NULL:删除主键记录,并且将外键记录中外键字段的值置为null
前提是外键字段要设置为值允许是null。
比如,我们要删除客户张三时,在删除了客户张三记录同时,会将Order表里面所有的 张三记录里面的customer字段值置为 null。 但是上面我们并没有设置 customer 字段有 null=True 的参数设置,所以,是不能取值为 SET_NULL的。
定义完之后,还是老方法,在根目录cmd执行:
python manage.py makemigrations common
python manage.py migrate
数据库中就多了两个表,
注意:
- 定义的时候如果没有声明主键,Django会自动多一个id字段作为主键
- 可以看到common_order表中的
customer_id
字段,比定义的时候多了一个_id
,因为这是作为外键和common_customer表的主键id关联了
一对一:
外键是一对多的关系,有的时候,表之间是一对一的关系。
比如,某个学校的学生表和学生的地址表,就形成一对一的关系,即一条主键所在表的记录只能对应一条外键所在表的记录。
Django中用OneToOneField()
方法实现一对一的关系,如下:
class Student(models.Model):# 姓名name = models.CharField(max_length=200)# 班级classname = models.CharField(max_length=200)# 描述desc = models.CharField(max_length=200)class ContactAddress(models.Model):# 一对一 对应学生表 student = models.OneToOneField(Student, on_delete=models.PROTECT)# 家庭homeaddress = models.CharField(max_length=200)# 电话号码phone = models.CharField(max_length=200)
Django发现这样一对一定定义,它会在migrate
的时候,在数据库中定义该字段为外键的同时, 加上unique=True
约束(在底层数据库实现),表示在此表中,所有记录的该字段取值必须唯一,不能重复。
多对多:
数据库表还有一种多对多的关系。
在当前系统中, 一个订单可以采购多种药品,就对应Medicine表里面的多种药品;
而一种药品也可以被多个订单采购, 那么Order表和Medicine表 之间就形成了多对多的关系。
Django是通过 ManyToManyField
对象 表示 多对多的关系。
修改models.py中的Order类:
class Order(models.Model):# 订单名name = models.CharField(max_length=200, null=True, blank=True)# 创建日期create_date = models.DateTimeField(default=datetime.datetime.now)# 客户customer = models.ForeignKey(Customer, on_delete=models.PROTECT)# 订单购买的药品,和Medicine表是多对多的关系medicines = models.ManyToManyField(Medicine, through='OrderMedicine')class OrderMedicine(models.Model):order = models.ForeignKey(Order, on_delete=models.PROTECT)medicine = models.ForeignKey(Medicine, on_delete=models.PROTECT)# 订单中药品的数量amount = models.PositiveIntegerField()
像这样:
medicines = models.ManyToManyField(Medicine, through='OrderMedicine')
指定Order表和 Medicine 表的多对多关系, 其实Order表中并不会产生一个叫 medicines 的字段。
Order表和 Medicine 表的多对多关系是通过另外一张表, 也就是through参数 指定的 OrderMedicine表来确定的,
migrate
的时候,Django会自动产生一张新表 (这里就是 common_ordermedicine)来 实现 order 表 和 medicine 表之间的多对多的关系。
同样的,在根目录cmd执行:
python manage.py makemigrations common
python manage.py migrate
可以看到数据库中多了一张common_ordermedicine表,用来实现订单表和药品表的多对多关系。
外键medicine_id关联了common_medicine表,外键order_id关联了common_order表。
比如一个order表的订单id 为 1, 如果该订单中对应的药品有3种,它们的id分别 为 3,4,5。 那么就会有类似这样的这样3条记录在 common_order_medicine 表中。
order_id | medicine_id |
---|---|
1 | 3 |
1 | 4 |
1 | 5 |
因为要多一个字段,例如药品的数量,所以要用through='OrderMedicine'
,也就是说如果不需要额外字段的话,through可以省略
8. 数据库表的关联相关推荐
- mysql 查询两张表结构相同的数据库_利用反射处理多个表结构相同的数据的查询和数据库表的关联...
最近做一个项目,需要对人口数据进行查询,但是人口数据分布在不同的街道表中,首先进行了数据表结构的统一,每个数据表以街道名开头,然后其他的名字都一样 前期将各个表中的字段也进行了统一 抽象出一张字典表 ...
- Camstar开发常用数据库表及其关联
大概常用的表涉及到20个,目前学习用到的就这么多,还有很多还是会用到的只是目前经常用的就这么多. 站在巨人的肩膀上真的会看的更远更清晰! -----用志不分,乃凝于神 转载于:https://www. ...
- 听说,他用报表关联数据库表,运维效率提升70%?
在"互联网+"的时代,以实体为基础.辅助电商与物流已经成为了零售行业"数字化转型"的必经之路.转型带来的数据激增不仅给数据人员带来了报表制作与维护压力,也给业务 ...
- 数组数据通过sql语句转为数据库表衔接到from或join后进行直接或关联查询
Mybatis之数组数据通过sql语句转为数据库表衔接到from或join后进行直接或关联查询 外部数据 当前项目表格数据(表名:service_info) 将外部数据转为Table表格,与servi ...
- a表两个字段都与b表一个字段关联_数据库表的主键实例分析
主键(PRIMARY KEY):数据库表通常具有包含唯一标识表中每一行的值的一列或一组列.这样的一列或多列称为表的主键 (PK),用于强制表的实体完整性. 业务主键(自然主键):在数据库表中把具有业务 ...
- SAP ABAP bcset激活时,关联的数据库表条目是如何插入的
本文介绍SAP ABAP bcset激活时,关联的数据库表条目是如何插入的. 要获取更多Jerry的原创文章,请关注公众号"汪子熙":
- 数据库表的软硬关联_Jimmy的关系型数据库设计心得 第一版
欢迎关注Jimmy的公众号:Jimmy嘚啵嘚,每周都有很多干货文章分享(最近比较懒,先保证每周写几篇,等忙完了再每日更新) 最近在梳理以前设计关系型数据库的心得体会,或者斗胆说是方法论,梳理出一些感觉 ...
- 6、数据库表的关系、Java对象的关系、关联查询(一对多)、延迟加载访问
文章目录 关联查询.多表 数据库表关系 Java对象之间的关系 前提条件 一对多 单向关联 延迟加载 双向关联 延迟加载 延迟加载中传递多个参数 关联查询.多表 数据库表关系 表->约束(主键约 ...
- sql与mysql中2个表数据进行匹配_SQL语言中把数据库中两张表数据关联起来的语句...
展开全部 1.创建32313133353236313431303231363533e59b9ee7ad9431333431373864两张测试表, create table test_cj(name ...
最新文章
- AI自动评审论文,CMU这个工具可行吗?
- 为什么重写equals一定要重写hashCode方法?
- docker删除本地所有镜像
- struts2核心配置
- android studio读写txt,Android Studio从.txt文件读取/写入,保存路径?
- mysql性能优化学习笔记
- 【缩点】洛谷P3387
- 全球区域区号plist列表(跟微信区号列表数据一致)
- oracle oaf界面个性化,OAF—个性化和扩展维护
- QQ计数器统计器使用教程
- Antv X6 动态连线
- 快手-开眼快创 Flutter 实践
- Apple Catching
- 跟小博老师一起学习MyBatis ——MyBatis搭建运行环境
- 优秀课程案例:使用Scratch制作扫雷插旗排雷完整版
- 给图片加水印--手把手教新码农如何把技术变成产品
- EXCEL表格-VLOOKUP函数场景应用详解
- 关于移动端在cubeui中cube-scroll(以及better-scroll)里面写click会触发两次的问题
- 阿里“看”AI + “ET大脑”战略启动
- 安防摄像头已分别接入乐橙云、萤石云,如何实现私有云平台的统一管理与向上级联?