Django ORM详解:外键使用(外键逻辑关联)与查询优化
Django数据库迁移
# 创建迁移
python manage.py makemigrations your_app_name
# 应用迁移
python manage.py migrate
# 查看迁移状态
python manage.py showmigrations
# 回滚迁移
python manage.py migrate your_app_name 0001
# 修改表后,删除迁移记录和表删除迁移记录后重新迁移
python manage.py migrate --fake contract_manage zero
外键关系的定义
在 Django 模型(Models)中定义外键关系,意味着两个表之间的链接关系。例如,我们有一个博客应用,其中有Author
和Article
两个模型:
from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=100)class Article(models.Model):title = models.CharField(max_length=200)content = models.TextField()author = models.ForeignKey(Author, on_delete=models.CASCADE)
这里的Article
模型中的author
字段定义了一个外键关系,指向Author
模型。
外间删除操作的参数意思:
如果一个模型使用了外键。那么在对方那个模型被删掉后,该进行什么样的操作。可以通过on_delete来指定。可以指定的类型如下:
CASCADE:级联操作。如果外键对应的那条数据被删除了,那么这条数据也会被删除。
PROTECT:受保护。即只要这条数据引用了外键的那条数据,那么就不能删除外键的那条数据。如果我们强行删除,Django就会报错。
SET_NULL:设置为空。如果外键的那条数据被删除了,那么在本条数据上就将这个字段设置为空。如果设置这个选项,前提是要指定这个字段可以为空。
SET_DEFAULT:设置默认值。如果外键的那条数据被删除了,那么本条数据上就将这个字段设置为默认值。如果设置这个选项,== 前提是要指定这个字段一个默认值 ==。
SET():如果外键的那条数据被删除了。那么将会获取SET函数中的值来作为这个外键的值。SET函数可以接收一个可以调用的对象(比如函数或者方法),如果是可以调用的对象,那么会将这个对象调用后的结果作为值返回回去。== 可以不用指定默认值 ==
DO_NOTHING:不采取任何行为。一切全看数据库级别的约束。
以上这些选项只是Django级别的,数据级别依旧是RESTRICT!
数据库层面的约束有四种:
RESTRICT:默认的选项,如果想要删除父表的记录时,而在子表中有关联该父表的记录,则不允许删除父表中的记录;
NOACTION:同 RESTRICT效果一样,也是首先先检查外键;
CASCADE:父表delete、update的时候,子表会delete、update掉关联记录;
SET NULL:父表delete、update的时候,子表会将关联记录的外键字段所在列设为null,所以注意在设计子表时外键不能设为not null;
基本外键查询
假设我们想查询某位作者编写的所有文章,可以这样做:
# 假设我们已知作者的 ID
author_id = 1 articles = Article.objects.filter(author_id=author_id)# 这会生成一个查询集(QuerySet),包含了所有这位作者的文章。
反向查询
在 Django 中,每当你定义了一个外键关系,Django 会自动为相关联的模型添加一个反向查询的管理器。在上述例子中,Author
模型会有一个article_set
的管理器,允许我们从Author
的角度查询文章:
# 获取某个作者实例
author = Author.objects.get(id=author_id)
# 反向查询这个作者的所有文章
authors_articles = author.article_set.all()
自定义反向查询名称
使用related_name
属性可以自定义反向查询的名称,这会使你的代码更加清晰:
class Article(models.Model):# ...author = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='articles')
现在我们可以这样使用自定义的反向查询名称:
author = Author.objects.get(id=author_id)
authors_articles = author.articles.all()
查询优化
为了优化查询性能,Django 提供了select_related
和prefetch_related
两种不同的查询优化方法。select_related
适用于“一对多”的关系查询优化,而prefetch_related
适用于“多对多”和“多对一”的关系查询优化。
在我们的例子中,如果我们想一次性获取所有文章及其作者信息,可以这样做:
# 使用 select_related 获取所有文章和对应的作者信息
articles_with_authors = Article.objects.select_related('author').all()
如果我们想获取所有作者及其所有文章,那么可以使用prefetch_related
:
# 使用 prefetch_related 获取所有作者和他们所有的文章
authors_with_articles = Author.objects.prefetch_related('articles').all()
django orm数据表不设置外键进行关联查询
方法一: 修改books_book表 models字段定义,改为逻辑关联
Tips: django中的ForeignKey与数据库中FOREIGN KEY约束并不一样,ForeignKey是一种逻辑上的关联关系,是否使用数据库中的外键约束通过db_contraint参数设置。
class Book(models.Model):"""书籍表"""name = models.CharField('名称', max_length=50)price = models.IntegerField('价格', default=50)publisher = models.ForeignKey('Publisher',on_delete=models.DO_NOTHING, db_constraint=False)class Meta:db_table = 'books_book'class Publisher(models.Model):"""出版社表"""name = models.CharField('出版社名称', max_length=50)addr = models.CharField('出版社地址', max_length=50)class Meta:db_table = 'books_publisher'
查询语句:
queryset = Book.objects.values(‘id’, ‘name’, ‘price’, ‘publisher__name’)
方法二:通过extra api函数实现
queryset = Book.objects.extra(select={‘publisher_name’: ‘SELECT books_publisher.name FROM books_publisher WHERE books_publisher.id = books_book.publisher_id’})# 测试结果:
# 可以发现查询出的queryset中多了一个publisher_name属性,然后在序列化阶段将这个字段加上即可。
from books.models import Book, Publisher
queryset = Book.objects.extra(select={'publisher_name': 'SELECT books_publisher.name FROM books_publisher WHERE books_publisher.id = books_book.publisher_id'})
for item in queryset:print(item.__dict__){'_state': <django.db.models.base.ModelState object at 0x000002993198F208>, 'id': 1, 'name': '书本1', 'price': 20, 'publisher_id': 1, 'publisher_name': '工业出版社'}
方法三:执行原生sql实现(方法三与方法二比较类似)
queryset = Book.objects.raw( ‘select books_book.*, books_publisher.name as publisher_name from books_book left join books_publisher on books_book.publisher_id = books_publisher.id;’)# 测试结果queryset = Book.objects.raw( 'select books_book.*, books_publisher.name as publisher_name from books_book left join books_publisher on books_book.publisher_id = books_publisher.id;')
for item in queryset:print(item.__dict__){'_state': <django.db.models.base.ModelState object at 0x0000029931119748>, 'id': 1, 'name': '书本1', 'price': 20, 'publisher_id': 1, 'publisher_name': '工业出版社'}
方法四:在序列化阶段根据相关联的id字段再执行一次查询
# ProjectVersion model 序列化器class BookSerializer(serializers.ModelSerializer):publisher_name = serializers.SerializerMethodField()def get_publisher_name(self, obj):""":param obj: Book实例"""publisher = Publisher.objects.filter(id=obj.publisher_id).first()if publisher:return publisher.nameelse:return ''
查询优化
对于大型数据库,优化查询是非常重要的。Django ORM提供了几种工具来帮助你优化查询,包括select_related()
和prefetch_related()
。
from myapp.models import Blog# 获取所有Blog记录,并一次性获取每个Blog的author信息
# select_related()可以一次性获取与查询对象有ForeignKey关联的对象,这可以减少数据库查询次数
blogs = Blog.objects.select_related('author').all()# 输出Blog的标题和作者名
for blog in blogs:print(blog.title, blog.author.name)
prefetch_related()
对于ManyToMany关联和一对多关联也非常有用,它可以一次性获取所有相关对象,减少数据库查询次数。
利用数据库约束保证数据一致性
Django ORM提供了多种数据库约束,如unique
和check
等,可以帮助我们确保数据库的数据一致性。
# 例子:使用unique约束确保每个作者的email是唯一的
class Author(models.Model):name = models.CharField(max_length=100)email = models.EmailField(unique=True)
使用批量操作提升性能
Django ORM提供了bulk_create
和bulk_update
等方法,可以让我们以更高效的方式进行批量创建和更新。
# 例子:使用bulk_create方法批量创建对象
authors = [Author(name=f'Author {i}') for i in range(1000)]
Author.objects.bulk_create(authors) # 这个操作只需要一次数据库查询
使用原生SQL
尽管Django ORM提供了许多强大的查询工具,但有时候你可能需要直接执行SQL语句。Django ORM允许你执行原生SQL,你可以使用raw()
方法或者cursor()
方法来执行原生SQL:
from django.db import connection# 使用cursor()执行原生SQL
with connection.cursor() as cursor:cursor.execute("SELECT title FROM myapp_blog")row = cursor.fetchone()print(row)
或者
Author.objects.raw("SELECT name FROM author")
这段代码将直接执行SQL查询,并打印出第一个博客的标题。虽然Django ORM提供了.raw()方法允许我们直接执行SQL查询,但是这个方法应该尽量避免使用,因为它可能会引发SQL注入等安全问题,同时也失去了Django ORM的许多优点。
相关文章:

Django ORM详解:外键使用(外键逻辑关联)与查询优化
Django数据库迁移 # 创建迁移 python manage.py makemigrations your_app_name # 应用迁移 python manage.py migrate # 查看迁移状态 python manage.py showmigrations # 回滚迁移 python manage.py migrate your_app_name 0001 # 修改表后,删除迁移记录和表删除迁移记录后重…...

【Python】实战:使用input()从键盘获取一个字符串,判断这个字符串在列表中是否存在(函数体不能使用in),返回结果为True或False
使用input()从键盘获取一个字符串,判断这个字符串在列表中是否存在(函数体不能使用in),返回结果为True或False def exists_in_list(input_string, str_list):# 遍历列表中的每个元素for item in str_list:if item input_string: # 如果当前元素等于输…...

【YApi】接口管理平台
一、简介 YApi 是一个用于前后端开发团队协作的 API 管理平台,帮助团队更加高效地进行 API 接口的设计、测试、文档管理和版本控制等工作。 YApi 主要功能: API 设计和管理:提供 API 设计和文档生成工具,使开发者能够轻松创建、…...

QNAP威联通NAS忘记密码怎么办?
创作立场:原创不易,拒绝搬运~ hello 大家好,我是你们的老伙伴,稳重的大王~ 如题:在使用QNAP 威联通NAS期间,如果忘记密码,怎么去找回密码呢? 每台QNAP 威联通NAS,在机器…...

MySQL FIND_IN_SET 函数详解
文章目录 1. 基本语法2. 使用场景3. 实战示例3.1 基础查询示例3.2 与其他函数结合使用3.3 动态条件查询 4. 性能考虑5. 常见问题和解决方案5.1 大小写敏感问题5.2 空值处理5.3 模糊匹配 6. 总结 1. 基本语法 FIND_IN_SET 函数的基本语法如下: FIND_IN_SET(str, st…...

【零售和消费品&厨房】厨房食材检测图像分割系统源码&数据集全套:改进yolo11-goldyolo
改进yolo11-RepNCSPELAN等200全套创新点大全:厨房食材检测图像分割系统源码&数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.10.30 注意:由于项目一直在更新迭代,上面“1.图片效果展示”和“2.视频效果展示”展示的系…...

自制田字格word
背景 孩子上小学要开始学认字了,每周有好多字要打印,要是直接拿一张A4纸去打印,字的排版就显得尤为重要,排过来排过去,总感觉不够正式。就想去网上搜一个可以下载的田字格模板。某度搜了半天,倒是搜到一堆…...

微软官方 .NET 混淆软件 Dotfuscator
微软官方 .NET 混淆软件 Dotfuscator 1、前言2、Dotfuscator 特色2.1、强大的保护2.2、不需要顾问2.3、世界一流的支持2.4、广泛的平台支持 3、Dotfuscator 功能介绍3.1、.NET Obfuscator3.2、篡改防御和提示3.3、监控性能和使用情况3.4、Silverpght XAML Obfuscatio3.5、WPF B…...

19 Docker容器集群网络架构:二、etcd 集群部署
文章目录 Docker容器集群网络架构:二、etcd集群离线部署2.1 准备工作2.1.1 上传etcd2.1.2 解压etcd2.1.3 拷贝文件到/usr/local/bin2.1.4 创建相关目录并赋权2.2 创建etcd集群2.2.1 创建etcd配置文件2.2.2 配置etcd服务文件2.2.3 启动ectd服务2.3 查看etcd集群成员2.3.1 查看e…...

React + SpreadJS 开发时常见问题
在使用React与SpreadJS进行开发时,可能会遇到各种各样的问题。以下是一些常见的问题及其解决建议: 1. SpreadJS初始化失败 问题描述: 有时候SpreadJS的初始化可能会失败,特别是在React组件的生命周期内不当的初始化时机。 解决…...

docker 调用宿主机实现关机
Docker调用宿主机关机命令或调用宿主机程序,这涉及到了Docker容器与宿主机之间的通信和资源共享技术。具体来说,这种技术或通讯方式主要通过以下几种方法实现: 一、使用数据卷 Docker允许使用-v或--volume选项将宿主机上的目录或文件挂载到…...

51单片机--- 16*32点阵滚动显示
实验目标:51单片机驱动74LS183控制16*32点阵滚动显示 实验步骤: 在Proteus里画出原理图 在Keil里用C语言编写程序 在Proteus中导入HEX文件,启动仿真 74LS138 简介...

渗透测试-百日筑基—文件上传篇特征截断渲染%00绕过——下篇
目录 day10-渗透测试文件上传篇&绕过&特征&截断&渲染 一、黑名单大小写绕过代码分析 1、获取文件后缀名进行判断,如果后缀在这个字典里就禁止上传。 2、黑名单大小写绕过攻击 二、利用 windows 系统特征绕过上传 1、windows 系统特征绕过漏洞…...

深度学习基础—循环神经网络(RNN)
引言 从本系列博客开始,我们将来一起学习一下NLP领域的相关基础知识,NLP领域重要的模型是RNN,在此之前,先来了解一些符号的含义。 1.符号定义 (1)符号定义 假设建立一个能够自动识别句中人名位置的序列模型…...

一二三应用开发平台自定义查询设计与实现系列2——查询方案功能实现
查询方案功能实现 上面实现了自定义查询功能框架,从用户角度出发,有些条件组合可以形成特定的查询方案,对应着业务查询场景。诸多查询条件的组合,不能每次都让用户来设置,而是应该保存下来,下次可以直接使…...

Redis 集群 问题
前言 相关系列 《Redis & 目录》《Redis & 集群 & 源码》《Redis & 集群 & 总结》《Redis & 集群 & 问题》 什么是Redis集群?为什么要集群?Redis集群的优/缺点是什么? Redis集群是指将多台Redis实例进行协…...

PyQt入门指南二十九 QListView列表视图组件
在PyQt中,QListView 是一个用于显示项目列表的视图组件。它可以与 QStandardItemModel 或其他模型一起使用,以显示和编辑数据。以下是一个简单的入门指南,介绍如何使用 QListView 组件。 安装 PyQt 首先,确保你已经安装了 PyQt5…...

cisco网络安全技术第4章测试及考试
测试 以下 ACE 将放置在何处? permit icmp any any nd-na 试题 1选择一项: 在连接到另一个路由器并已启用 IPv6 的路由器接口上 使用下一代防火墙而不是状态防火墙的一个好处是什么? 试题 2选择一项: 主动而不是被动防护互…...

vue下载安装
目录 vue工具前置要求:安装node.js并配置好国内镜像源下载安装 vue 工具 系统:Windows 11 前置要求:安装node.js并配置好国内镜像源 参考:本人写的《node.js下载、安装、设置国内镜像源(永久)ÿ…...

C++ | Leetcode C++题解之第516题最长回文子序列
题目: 题解: class Solution { public:int longestPalindromeSubseq(string s) {int n s.length();vector<vector<int>> dp(n, vector<int>(n));for (int i n - 1; i > 0; i--) {dp[i][i] 1;char c1 s[i];for (int j i 1; j…...

Python中的`update`方法详解及示例
Python中的update方法详解及示例 1. update方法简介2. update方法的应用场景3. 代码示例示例代码代码解释运行结果 4. 总结 在Python编程中,update方法是一个非常实用的工具,尤其是在处理集合(Set)数据类型时。本文将详细介绍upda…...

Docker本地安装Minio对象存储
Docker本地安装Minio对象存储 1. 什么是 MinIO? MinIO 是一个开源的对象存储服务器。这意味着它允许你在互联网上存储大量数据,比如文件、图片、视频等,而不需要依赖传统的文件系统。MinIO 的特点在于它非常灵活、易于使用,同时…...

vuex、vue-router实现原理
文章目录 Vuex 实现原理1. 状态管理2. 核心概念3. 数据流4. 实现细节 Vue Router 实现原理1. 路由管理2. 核心概念3. 数据流4. 实现细节 总结 Vuex 和 Vue Router 是 Vue.js 生态系统中非常重要的两个库,分别用于状态管理和路由管理。它们各自的实现原理如下&#x…...

我在命令行下剪辑视频
是的,你不需要格式工厂,你也不需要会声会影,更不需要爱剪辑这些莫名其妙的流氓软件,命令行下视频处理,包括剪辑,转码,提取,合成,缩放,字幕,特效等…...

Rust 力扣 - 643. 子数组最大平均数 I
文章目录 题目描述题解思路题解代码题解链接 题目描述 题解思路 我们遍历长度为k的窗口,我们只需要记录窗口内的最大和即可,遍历过程中刷新最大值 结果为窗口长度为k的最大和 除以 k 题解代码 impl Solution {pub fn find_max_average(nums: Vec<…...

流场主动流动控制
对于流场的主动控制而言,其难点主要集中在强化学习的环境搭建过程,如何建立数值仿真与强化学习的信息交互是研究过程中的拦路虎。经过几个星期的研究,已基本实现由pycharm程序数据端向star ccm端的数据传递。其主要过程包括如下过程ÿ…...

BOOST电感选型(参数详细计算)
上一篇文章我们介绍了BUCK电路中电感的计算与选型,与BUCK类似,这篇来介绍下BOOST BOOST电路原理简析 上图是一个异步BOOST电路拓扑图,我们先来简单回忆一下它是如何工作的: 1.Q闭合,Vin为Rload供电,Vin为L…...

EfficientNet-B6模型实现ISIC皮肤镜图像数据集分类
项目源码获取方式见文章末尾! 回复暗号:13,免费获取600多个深度学习项目资料,快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【基于opencv答题卡识别判卷】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【G…...

Elasticsearch分词器基础安装
简介 Elasticsearch (ES) 是一个基于 Lucene 的搜索引擎,分词器是其核心组件之一,负责对文本数据进行分析和处理。 1. 文本分析 分词器将输入的文本拆分成一个个单独的词(tokens),以便后续的索引和搜索。例如&#x…...

Django-邮件发送
邮件相关协议: SMTP(负责发送): IMAP(负责收邮件): POP3(负责收邮件): 两者区别: Django发邮件: 邮箱相关配置: settings中&…...