操作系统: 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执行:

  1. python manage.py makemigrations common
  2. 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执行:

  1. python manage.py makemigrations common
  2. 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. 数据库表的关联相关推荐

  1. mysql 查询两张表结构相同的数据库_利用反射处理多个表结构相同的数据的查询和数据库表的关联...

    最近做一个项目,需要对人口数据进行查询,但是人口数据分布在不同的街道表中,首先进行了数据表结构的统一,每个数据表以街道名开头,然后其他的名字都一样 前期将各个表中的字段也进行了统一 抽象出一张字典表 ...

  2. Camstar开发常用数据库表及其关联

    大概常用的表涉及到20个,目前学习用到的就这么多,还有很多还是会用到的只是目前经常用的就这么多. 站在巨人的肩膀上真的会看的更远更清晰! -----用志不分,乃凝于神 转载于:https://www. ...

  3. 听说,他用报表关联数据库表,运维效率提升70%?

    在"互联网+"的时代,以实体为基础.辅助电商与物流已经成为了零售行业"数字化转型"的必经之路.转型带来的数据激增不仅给数据人员带来了报表制作与维护压力,也给业务 ...

  4. 数组数据通过sql语句转为数据库表衔接到from或join后进行直接或关联查询

    Mybatis之数组数据通过sql语句转为数据库表衔接到from或join后进行直接或关联查询 外部数据 当前项目表格数据(表名:service_info) 将外部数据转为Table表格,与servi ...

  5. a表两个字段都与b表一个字段关联_数据库表的主键实例分析

    主键(PRIMARY KEY):数据库表通常具有包含唯一标识表中每一行的值的一列或一组列.这样的一列或多列称为表的主键 (PK),用于强制表的实体完整性. 业务主键(自然主键):在数据库表中把具有业务 ...

  6. SAP ABAP bcset激活时,关联的数据库表条目是如何插入的

    本文介绍SAP ABAP bcset激活时,关联的数据库表条目是如何插入的. 要获取更多Jerry的原创文章,请关注公众号"汪子熙":

  7. 数据库表的软硬关联_Jimmy的关系型数据库设计心得 第一版

    欢迎关注Jimmy的公众号:Jimmy嘚啵嘚,每周都有很多干货文章分享(最近比较懒,先保证每周写几篇,等忙完了再每日更新) 最近在梳理以前设计关系型数据库的心得体会,或者斗胆说是方法论,梳理出一些感觉 ...

  8. 6、数据库表的关系、Java对象的关系、关联查询(一对多)、延迟加载访问

    文章目录 关联查询.多表 数据库表关系 Java对象之间的关系 前提条件 一对多 单向关联 延迟加载 双向关联 延迟加载 延迟加载中传递多个参数 关联查询.多表 数据库表关系 表->约束(主键约 ...

  9. sql与mysql中2个表数据进行匹配_SQL语言中把数据库中两张表数据关联起来的语句...

    展开全部 1.创建32313133353236313431303231363533e59b9ee7ad9431333431373864两张测试表, create table test_cj(name ...

最新文章

  1. AI自动评审论文,CMU这个工具可行吗?
  2. 为什么重写equals一定要重写hashCode方法?
  3. docker删除本地所有镜像
  4. struts2核心配置
  5. android studio读写txt,Android Studio从.txt文件读取/写入,保存路径?
  6. mysql性能优化学习笔记
  7. 【缩点】洛谷P3387
  8. 全球区域区号plist列表(跟微信区号列表数据一致)
  9. oracle oaf界面个性化,OAF—个性化和扩展维护
  10. QQ计数器统计器使用教程
  11. Antv X6 动态连线
  12. 快手-开眼快创 Flutter 实践
  13. Apple Catching
  14. 跟小博老师一起学习MyBatis ——MyBatis搭建运行环境
  15. 优秀课程案例:使用Scratch制作扫雷插旗排雷完整版
  16. 给图片加水印--手把手教新码农如何把技术变成产品
  17. EXCEL表格-VLOOKUP函数场景应用详解
  18. 关于移动端在cubeui中cube-scroll(以及better-scroll)里面写click会触发两次的问题
  19. 阿里“看”AI + “ET大脑”战略启动
  20. 安防摄像头已分别接入乐橙云、萤石云,如何实现私有云平台的统一管理与向上级联?

热门文章

  1. android中的ellipsize
  2. DES、3DES 加密算法的调用
  3. Anaconda安装pytorch——清华镜像源不稳定
  4. iPhone 12全系四款曝光:售价、内存有惊喜
  5. qt mac 打包dmg
  6. mysql知识点大全
  7. Android 判断手机有没有安装该应用的工具类
  8. 读懂系列 | 10个例子带你了解机器学习中的线性代数
  9. 详解ETL银行数据仓储抽取和加载流程概述
  10. 几种常用的程序命名方法(规则)