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…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
