Django ORM 框架中的表关系,你真的弄懂了吗?
Django ORM 框架中的表关系
为了说清楚问题,我们设计一个 crm 系统,包含五张表:
1.tb_student 学生表
2.tb_student_detail 学生详情表
3.tb_salesman 课程顾问表
4.tb_course 课程表
5.tb_entry 报名表
表关系和字段如下图:

如果你想学习自动化测试,我这边给你推荐一套视频,这个视频可以说是B站播放全网第一的自动化测试教程,同时在线人数到达1000人,并且还有笔记可以领取及各路大神技术交流:798478386
【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)_哔哩哔哩_bilibili【已更新】B站讲的最详细的Python接口自动化测试实战教程全集(实战最新版)共计200条视频,包括:1、接口自动化之为什么要做接口自动化、2、接口自动化之request全局观、3、接口自动化之接口实战等,UP主更多精彩视频,请关注UP账号。
https://www.bilibili.com/video/BV17p4y1B77x/?spm_id_from=333.337
接下来,根据这几个表我们来看在 django 中如何编写对应的模型,以及在数据库层面的处理。
多对一
在 django 中要表达多对一的关系需要使用 django.db.models.ForeignKeyField 字段。上图中,报名表和学生表,课程表,课程顾问表是多对一的关系,模型代码如下:
from django.db import modelsclass Student(models.Model): # 必须继承name = models.CharField('姓名', max_length=20, help_text='姓名')age = models.SmallIntegerField('年龄', null=True, blank=True, help_text='年龄')sex = models.SmallIntegerField('性别', default=1, help_text='性别')qq = models.CharField('qq号码', max_length=20, null=True, blank=True, unique=True, help_text='qq号码')phone = models.CharField('手机号码', max_length=20, null=True, blank=True, unique=True, help_text='手机号码')c_time = models.DateTimeField('创建时间', auto_now_add=True)def __str__(self):return self.nameclass Meta:db_table = 'tb_student' # 设置创建表示的表名verbose_name = '学生信息'verbose_name_plural = verbose_name # django admin中显示模型的说明class Salesman(models.Model):# GroupChoice = [# ('电销', '电销'),# ('网销', '网销'),# ('班主任', '班主任'),# ]class GroupChoice(models.TextChoices):A = '电销', '电销'B = '网销', '网销'C = '班主任', '班主任'name = models.CharField('姓名', max_length=24, help_text='姓名')age = models.SmallIntegerField('年龄', null=True, blank=True, help_text='年龄')sex = models.SmallIntegerField('性别', default=1, help_text='性别')group = models.CharField('销售组', help_text='销售组', max_length=24, choices=GroupChoice.choices, default=GroupChoice.A )# group = models.CharField('销售组', help_text='销售组', max_length=24, choices=GroupChoice, default='电销')def __str__(self):return self.nameclass Meta:db_table = 'tb_salesman'verbose_name = '课程顾问表'verbose_name_plural = verbose_nameclass Course(models.Model):name = models.CharField('课程名称', max_length=24, help_text='课程名称', unique=True)price = models.IntegerField('价格', help_text='课程价格')period = models.SmallIntegerField('课时', help_text='课时,以小时为单位')def __str__(self):return self.nameclass Meta:db_table = 'tb_course'verbose_name = '课程表'verbose_name_plural = verbose_nameclass Entry(models.Model):student = models.ForeignKey(Student, verbose_name='学生', help_text='报名学生', on_delete=models.PROTECT)salesman = models.ForeignKey('Salesman', verbose_name='课程顾问', help_text='课程顾问', on_delete=models.PROTECT)course = models.ForeignKey(Course, verbose_name='课程', help_text='报名课程', on_delete=models.PROTECT, db_constraint=False)c_time = models.DateTimeField('报名时间', auto_now_add=True, help_text='报名时间')def __str__(self):return '{}-{}'.format(self.student.name, self.salesman.name)class Meta:db_table = 'tb_entry'verbose_name = '报名表'verbose_name_plural = verbose_name
定义 ForeignKeyField 字段时有如下注意事项
-
一般外键字段定义在多的一方
-
外键字段的第一个参数是一个位置参数,就是要关联的模型,可以是模型类本身,也可是字符串形式的导入路径(当引用其他应用的模型,和引入后定义的模型时很有用)
-
在数据库层面,django 会在字段名的后面附件 _id 来创建数据库列名。例如上面例子中的 Entry 模型的数据库表将有一个 student_id 列,然后为这个列创建一个外键约束,被引用的表为 tb_student,被引用的字段为 id.

级联操作
当一个由 ForeignKey 引用的对象被删除时,django 将模拟 on_delete 参数指定的 SQL 约束行为。
注意是模拟,在数据库层面创建的外键的级联操作是 restrict。
-
注意:有时候为了效率,在数据库不会创建外键,而是通过代码逻辑来保证数据的完整性。在 django 中可以通过 ForeignKey 字段中指定 db_constraint=False 来控制不创建外键约束。所以上图中没有 course_id 的外键。
级联操作
当一个由 ForeignKey 引用的对象被删除时,django 将模拟 on_delete 参数指定的 SQL 约束行为。
注意是模拟,在数据库层面创建的外键的级联操作是 restrict。

on_delete 的可能值有:
-
CASCADE
-
级联删除
-
-
PROTECT
-
通过引发 ProtectedErro 防止删除被引用字段
-
-
RESTRICT
-
通过引发 RestrictErro 防止删除被引用字段
-
-
SET_NULL
-
设置外键为空,只有当 null=true 才可以
-
ForeignKey 字段必须指定 on_delete。
一对一
在 django 中要表达一对一的关系需要使用 django.db.models.OneToOneField 字段,概念上类似于 ForeignKey 与 unique=True 的组合。
在 crm 中,学生详情表与学生表就是一个一对一的关系,创建模型如下:
class StudentDetail(models.Model):STATION_CHOICES = [('功能测试工程师', '功能测试工程师'),('自动化测试工程师', '自动化测试工程师'),('测试开发工程师', '测试开发工程师'),('测试组长', '测试组长'),('测试经理', '测试经理'),]class SalaryChoice(models.TextChoices):FIRST = '5000以下', '5000以下'SECOND = '5000-10000', '5000-10000'THIRD = '10000-15000', '10000-15000'FOURTH = '15000-20000', '15000-20000'FIFTH = '20000以上', '20000以上'student = models.OneToOneField(Student, verbose_name='学生', on_delete=models.CASCADE, help_text='学生')city = models.CharField('所在城市', max_length=24, help_text='所在城市', null=True, blank=True)company = models.CharField('任职公司', max_length=48, help_text='任职公司', null=True, blank=True)station = models.CharField('岗位', max_length=24, help_text='岗位', choices=STATION_CHOICES, default='功能测试工程师' )salary = models.CharField('薪资', max_length=24, help_text='薪资区间', choices=SalaryChoice.choices, default=SalaryChoice.FIRST)def __str__(self):return self.student.nameclass Meta:db_table = 'tb_student_detail'verbose_name = '学生详情表'verbose_name_plural = verbose_name

多对多
在 django 中要表达多对多的关系需要使用 django.db.models.ManyToManyField 字段,例如 Pizza 含有多种 Topping(配料),一种配料也可能存在于多个 pizza 中,每个 pizza 含有多种 topping 的关系,可以用下面的模型来表示:
class Topping(models.Model):name = models.CharField('名称', max_length=24)class Pizza(models.Model):name = models.CharField('名称', max_length=24)toppings = models.ManyToManyField(Topping)
定义 ManyToManyField 字段时有如下注意事项
-
建议设置多对多字段名为一个复数名词,表示所要管理的模型对象的集合。
-
多以多对多关联的两个模型,可以在任何一个模型中添加多对多字段,但是只能选择一个模型设置,即不能在两个模型里都添加。
-
一般来讲,应该把多对多字段放到需要在表单中编辑的对象里。跟业务相关,具体情况具体对待。
-
在数据库层面,django 会自动创建一张中间表来表示多对多的关系。默认情况下,这个表名是使用多对多字段的名字和包含它的模型名生成(上面的例子,会生成 pizza_toppins),然后包含两个字段,分别是以两个关系模型的名字和 _id 组成(pizza_id,topping_id),并创建外键引用对应的表的 id。


自定义中间表
当表示多对多关系的中间表需要包含其他字段的时候,需要自定义中间表,然后再定义多对多字段的时候,通过 through 参数指定第三张表。
例如 crm 中的学生表和课程表的关系,通过报名表来表达,其中还包含了销售,创建时间字段。注意:创建学生,或者是创建课程的时候,都不需要去编辑彼此,这个时候建立多对多字段,主要是为了查询方便。然后通过课程查包名的学生表业务上可能用的更多,所以把多对多的字段定义在课程表中,代码如下:
class Course(models.Model):name = models.CharField('课程名称', max_length=24, help_text='课程名称', unique=True)price = models.IntegerField('价格', help_text='课程价格')period = models.SmallIntegerField('课时', help_text='课时,以小时为单位')students = models.ManyToManyField(Student, through='Entry', verbose_name='学生', help_text='包名课程的学生')def __str__(self):return self.nameclass Meta:db_table = 'tb_course'verbose_name = '课程表'verbose_name_plural = verbose_name相关文章:
Django ORM 框架中的表关系,你真的弄懂了吗?
Django ORM 框架中的表关系 为了说清楚问题,我们设计一个 crm 系统,包含五张表: 1.tb_student 学生表 2.tb_student_detail 学生详情表 3.tb_salesman 课程顾问表 4.tb_course 课程表 5.tb_entry 报名表 表关系和字段如下图:…...
第五课:C++实现加密PDF文档解密
请注意,未经授权的加密PDF文件解密是非法的,本文仅为学术和研究目的提供参考。 打开加密的PDF文件并获取密钥 在C++中,可以使用pdfium库打开加密的PDF文件。使用pdfium库中的FPDF_LoadCustomDocument函数可以打开具有自定义访问权限的加密文件。该函数接受一个IFX_FileRead*…...
罗马数字转整数
罗马数字转整数 题目: 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M …...
processflow流程图多人协作预热
前言 在线上办公如火如荼的今天,多人协作功能是每个应用绕不开的门槛。processflow在线流程图(前身基于drawio二次开发)沉寂两年之久,经过长时间设计开发,调整,最终完成了多人协作的核心模块设计。废话不多…...
PCL点云处理之快速计算多个点到同一直线的距离(二百零五)
PCL点云处理之快速计算多个点到同一直线的距离(二百零五) 一、算法简介二、具体实现1.代码2.结果一、算法简介 点到直线的距离计算,是一种常用的算法,在点云处理中,经常遇到需要计算多个点云到同一条直线的距离计算需求,此时若是逐点计算将耗费大量的时间,熟悉点到直线…...
xxl-job 任务调度搭建及简单使用
xxl-job是开源架构,可以通过它实现调度中心和执行器。 git地址和 官网中进行了详细的技术说明。 xxl-job支持单机部署和集群式部署,在集群式部署中又可以实现调度中心集群式部署和执行器集群式部署。本文主要针对调度中心和执行器分离单机部署方式进…...
mysql数据库使用技巧整理
查看当前数据库已建立的client连接 > SHOW VARIABLES LIKE max_connections; -- 查看数据库允许的最大连接数,不是实时正在使用的连接数 > SHOW STATUS LIKE Threads_connected; -- 查看当前数据库client的连接数 > SHOW PROCESSLIST; -- 查看具体的连接...
车规微控制器的ECC机制及EMU外设
车规微控制器的ECC机制及EMU外设 文章目录 车规微控制器的ECC机制及EMU外设引言ECC的基本原理ECC RAM的访问方式ECC RAM的初始化SRAM ECC错误注入及EMU外设Flash ECC校验参考文献 引言 ECC是微控制器系统中,用于保障信息安全的常用机制,主要是避免存储设…...
Less的强大变量用法
less中的变量应用十分强大,可以灵活的应用到各种不同需求的场景。 一,属性值变量 声明:sass声明变量是用$符号,而less声明变量是用符号 作用域:也区分为全局变量和局部变量,如果引用的变量有定义局部变量&…...
【相机标定】opencv python 标定相机内参时不计算 k3 畸变参数
文章目录 1. 背景2. 完整的 opencv python 标定相机内参过程3. 选择是否计算畸变参数 k3 1. 背景 畸变参数 k3 通常用于描述径向畸变的更高阶效应,即在需要高精度的应用中可以用到,一般的应用中 k1, k2 足矣。 常见的应用中, orbslam3 中是否…...
html 标签简介
概述 标签的效果不重要,重要的是标签的语义。 文本标签 文本标签用于包裹:词汇、短语等。排版标签,比如div,p,h1等。排版标签更宏观(大段的文字),文本标签更微观(词汇、短语)。文…...
dos汇编总结
前言: 计组课本需要学习汇编,可惜自己看不太懂。这里发现一个学习方法交给大家。其实新手可能一些抽象表示难理解,这里我把我学习的疑问点以及思路记录一下。 要点: 这里我以题为例给大家分析 输出输入对应大写字母的小写字母 …...
四川玖璨电子商务有限公司:短视频有什么运营
根据短视频有什么运营,短视频的拍摄工具多种多样。无论是在手机上拍摄还是使用专业摄影设备,拍摄短视频的目的都是为了吸引观众的注意力和提升内容的质量。从小花费到高投入,在不断发展的短视频行业中,拍摄方法也得到了不断创新和…...
混合查询多家快递,快速掌握物流信息
在现代社会,快递服务已成为我们日常生活的重要组成部分。无论是购物还是文件传递,我们都需要快递服务的帮助。然而,不同的快递公司需要不同的查询方法,这无疑增加了我们的查询难度。因此,有没有一种方法可以让我们一次…...
独立站新手引流,谷歌SEO工具汇总
俗话说“工欲善其事,必先利其器”,做谷歌SEO也一样,要想做好并提升SEO效果,卖家就需要了解并利用好SEO工具。那我们今天就来盘点一下,常用的SEO工具有哪些吧~ 网站检测工具 1、PageSpeed Insights:这是谷…...
SpringMvc 与 Lombok 碰撞导致 JSON 反序列化失败
SpringMvc 与 Lombok 中 JSON 反序列化失败 错误复现_1 Data public class User{private Long id;private boolean isOk; }RequestMapping public R<User> getUser(RequestBody User user){return R.success(user); }// 前端传参 - {"id": 123456789,"i…...
怎么样显卡叠加,什么是NVIDIA 显卡 非公、公版、涡轮卡
1、显存叠加的问题,因为这个跟是否是深度学习无关: 先说一下显存叠加的问题,因为这个跟是否是深度学习无关:一台机器有多张显卡,显存不会叠加!显卡里面包含了显存、cache、计算单元、通信等,每…...
CentOS安装Elasticsearch集群
前言 之前使用的ES集群是其他公司维护,没有机会安装,后来做其他项目,终于有机会安装ES集群,简单记录一下备用 一、安装jdk 安装jdk1.8就可以,可以参考另一篇文章,这里就不细说了 二、修改系统参数 如果在…...
计算机专业毕业生指南
在大四毕业时,完成计算机毕业设计需要一定的计划和组织。以下是一些建议,帮助你在三个月内快速完成毕业设计: 选择一个合适的主题: 选择一个你感兴趣的主题,这将激发你的热情,使你更有动力完成项目。 确保…...
Springboot集成Docker并将镜像推送linux服务器
案例使用springboot项目,在IDEA 中集成Docker生成镜像,并将镜像发布到linux服务器 具体步骤如下: 1、Centos7安装Docker 更新系统的软件包列表 sudo yum update安装Docker所需的软件包和依赖项: sudo yum install docker完成…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
DAY 47
三、通道注意力 3.1 通道注意力的定义 # 新增:通道注意力模块(SE模块) class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
服务器--宝塔命令
一、宝塔面板安装命令 ⚠️ 必须使用 root 用户 或 sudo 权限执行! sudo su - 1. CentOS 系统: yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh2. Ubuntu / Debian 系统…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
深入理解Optional:处理空指针异常
1. 使用Optional处理可能为空的集合 在Java开发中,集合判空是一个常见但容易出错的场景。传统方式虽然可行,但存在一些潜在问题: // 传统判空方式 if (!CollectionUtils.isEmpty(userInfoList)) {for (UserInfo userInfo : userInfoList) {…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...
Selenium 查找页面元素的方式
Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素,以下是主要的定位方式: 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…...
第22节 Node.js JXcore 打包
Node.js是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 本文主要介绍JXcore的打包功能。 JXcore 安装 下载JXcore安装包&a…...
linux设备重启后时间与网络时间不同步怎么解决?
linux设备重启后时间与网络时间不同步怎么解决? 设备只要一重启,时间又错了/偏了,明明刚刚对时还是对的! 这在物联网、嵌入式开发环境特别常见,尤其是开发板、树莓派、rk3588 这类设备。 解决方法: 加硬件…...
