文章目录

    • 一、查询基础
      • QuerySet 详解
      • 一对多关联查询
      • 多对多关联查询
    • 二、N+1查询问题
      • 问题分析
      • 检测方法
      • 解决方案
    • 三、高级查询优化
      • values()
      • values_list()
      • values()和values_list()对比
      • Q() 对象复杂查询
      • 查看生成的 SQL
    • 四、项目实战
      • 场景
      • 实战


一、查询基础

QuerySet 详解

Django 中通过模型类的 Manager 构建 QuerySet 来检索数据库对象,其核心特性包括:

  • 代表数据库中对象的集合
  • 可通过过滤器缩小查询范围
  • 具有惰性执行特性(仅在需要结果时才执行 SQL)

常用过滤器

  • all():返回所有对象
  • filter(**kwargs):返回满足条件的对象
  • exclude(** kwargs):返回不满足条件的对象
  • get(**kwargs):返回单个匹配对象(无匹配或多匹配会抛异常)
  • 切片
# 切片操作示例:返回前5个对象(LIMIT 5)
Book.objects.all()[:5]

一对多关联查询

假设一个作者可以写多本书,但每本书只能属于一个作者。

from django.db import modelsclass Author(models.Model):first_name = models.CharField(max_length=100)last_name = models.CharField(max_length=100)def __str__(self):return f"{self.first_name} {self.last_name}"class Book(models.Model):title = models.CharField(max_length=100)publication_date = models.DateField()# 外键关联Author,级联删除,反向查询名为booksauthor = models.ForeignKey(Author, on_delete=models.CASCADE, related_name='books')def __str__(self):return self.title

正向查询(通过外键属性访问)

b = Book.objects.get(id=2)
b.author  # 获取关联的Blog对象,查询数据库
b.author = some_body  # 设置关联对象
b.save()  # 保存更改

使用 select_related() 预加载关联对象,避免额外查询

b = Book.objects.select_related().get(id=2)
print(b.author)  # 已预加载到缓存,使用缓存,不查询数据库

反向查询(通过关联管理器)

# 未定义related_name, 默认Manager名称为:<模型名称小写>_set
a = Author.objects.get(id=1)
a.book_set.all()  # 返回所有关联的Book# 定义了related_name='books'
a.books.all()  # 更直观的访问方式

关联对象操作方法如下。所有 “反向” 操作对数据库都是立刻生效,保存到数据库。

  • add(obj1, obj2):添加关联对象
  • create(**kwargs):创建并关联新对象
  • remove(obj1, obj2):移除关联对象
  • clear():清空所有关联
  • set(objs):替换关联集合
a = Author.objects.get(id=1)
a.books.set([b1, b2]) #  b1 和 b2 都是 Book 实例

多对多关联查询

假设一个作者可以写多本书,一本书也可以有多个作者。

from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=100)email = models.EmailField()def __str__(self):return self.nameclass Book(models.Model):title = models.CharField(max_length=200)publication_date = models.DateField()# 多对多关联Authorauthors = models.ManyToManyField(Author, related_name='books')def __str__(self):return self.title

正向与反向查询示例

# 正向查询
b = Book.objects.get(id=3)
b.authors.all() # 获取所有关联的Author
b.authors.count()
b.authors.filter(name__contains="张三")# 反向查询
a = Author.objects.get(id=5)
a.book_set.all()  # 获取所有关联的Book

多对多关联中,add()、set() 和 remove() 可直接使用主键

a = Author.objects.get(id=5)
a.book_set.set([b1, b2])
# 等价于
a.book_set.set([b1.pk, b2.pk])

二、N+1查询问题

问题分析

N+1 查询是常见的性能问题,表现为主查询后执行 N 次额外查询。例如:

books = Book.objects.all()
for book in books:print(book.author.first_name)

以上代码会产生 1 次查询获取所有 Book,加上 N 次查询获取对应的 Author(N 为 Book 数量),共 N+1 次查询。

检测方法

  • Django Debug Toolbar:直观显示请求中的 SQL 查询
  • 日志记录:配置日志记录 SQL 语句
  • 性能分析工具:如 Django Silk 分析查询性能

解决方案

方法 1:使用 select_related

适用于一对多(正向)和一对一关系,通过 SQL JOIN 预加载关联对象

  • 语法:select_related('related_field')related_field 是模型中定义的 ForeignKeyOneToOneField 字段
books = Book.objects.select_related('author').all()
for book in books:print(book.author.first_name) # 无额外查询 

可结合 only() 选择需要的字段

books = Book.objects.select_related('author').only('title', 'author__name')

支持多级关联

# 加载书籍、作者及作者家乡信息
books = Book.objects.select_related('author__hometown').all()
for book in books:print(book.author.hometown.name)  # 无额外查询

方法 2:使用 prefetch_related

适用于多对多和反向关系,通过批量查询后在 Python 中关联。适用场景:

  • 多对多关系(ManyToManyField)
  • 反向一对多关系
  • 反向一对一关系
books = Book.objects.prefetch_related('authors').all()
for book in books:print(book.authors.all())  # 无额外查询

参考资料:Django 数据库访问优化

三、高级查询优化

values()

返回字典形式的查询集(返回一个 ValuesQuerySet 对象,其中每个元素是一个字典),适合提取特定字段

books = Book.objects.values('title', 'author')
for book in books:print(book) # 输出示例
{'title': 'Book1', 'author': 'Author1'}
{'title': 'Book2', 'author': 'Author2'}

values_list()

返回元组形式的查询集(返回一个 ValuesListQuerySet 对象,其中每个元素是一个元组),内存占用更低

books = Book.objects.values_list('title', 'author')
for book in books:print(book)### 输出示例
('Book1', 'Author1')
('Book2', 'Author2')

使用 flat=True 获取单一字段值列表。如果有多个字段时,传入 flat 会报错。

titles = Book.objects.values_list('title', flat=True)
# <QuerySet ['红楼梦', '西游记', ...]>

使用 named=True ,结果返回 namedtuple()

books_info = Book.objects.values_list("id", "title", named=True)
# <QuerySet [Row(id=1, title='红楼梦'), ...]>

values()和values_list()对比

对比维度values()values_list()
返回值类型返回一个包含字典的查询集,字典的键为字段名,值为字段对应的数据返回一个包含元组的查询集,元组中的元素依次对应指定字段的值
内存占用相对较高,因为字典需要存储键值对信息通常更节省内存,元组是更轻量的数据结构,无需存储字段名
使用场景适合需要通过字段名访问字段值的场景,例如需要明确知道每个值对应的字段时适合仅需要获取字段值的场景,例如只需批量获取某个或某几个字段的具体数据时

Q() 对象复杂查询

Q() 对象用于构建复杂查询条件,支持逻辑运算

  • &:逻辑与(AND)
  • |:逻辑或(OR)
  • ~:逻辑非(NOT)
from django.db.models import Q# 标题含Python或作者为John的书籍
books = Book.objects.filter(Q(title__icontains="Python") | Q(author="John")
)# 复杂组合条件
books = Book.objects.filter((Q(title__icontains="Python") | Q(title__icontains="Django")) &~Q(author="John")
)

查看生成的 SQL

调试时可查看 QuerySet 生成的 SQL

queryset = Book.objects.filter(author="John")
print(queryset.query)  # 输出对应的SQL语句

四、项目实战

场景

Django+Vue 后台管理系统中,一般需要支持不同的数据权限

  • 仅本人数据权限
  • 本部门及以下数据权限
  • 本部门数据权限
  • 指定部门数据权限
  • 全部数据权限

在这里插入图片描述

数据权限与功能权限(基于RBAC实现)的区别

  • 功能权限:控制 “能做什么”(如新增、删除按钮的显示和执行)
  • 数据权限:控制 “能看到什么数据”(如销售经理只能查看自己团队的数据)

实战

使用Q() 对象构建复杂查询,实现灵活的数据权限计算

在这里插入图片描述

点击查看完整代码


您正在阅读的是《Django从入门到实战》专栏!关注不迷路~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/917321.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917321.shtml
英文地址,请注明出处:http://en.pswp.cn/news/917321.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PyTorch 中 Tensor 统计学函数及相关概念

文章目录PyTorch 中 Tensor 统计学函数及相关概念一、引言二、基础统计学函数&#xff08;一&#xff09;torch.mean()——均值计算&#xff08;二&#xff09;torch.sum()——总和计算&#xff08;三&#xff09;torch.prod()——元素积计算&#xff08;四&#xff09;torch.m…

浅拷贝与深拷贝的区别

浅拷贝和深拷贝是两种不同的对象复制方式&#xff0c;主要区别在于它们如何处理对象内部的引用类型字段。浅拷贝 (Shallow Copy)特点&#xff1a;只复制对象本身&#xff08;基本类型字段&#xff09;和对象中的引用&#xff08;地址&#xff09;不复制引用指向的实际对象原始对…

脚本统计MongoDB集合表数据量

脚本&#xff1a; #!/bin/bashipxxx.xx.xx.xx portxxxx dbxxxdb #user #passwmongo -host ${ip}:${port} <<EOF 2>/dev/null|grep -vE version|not match|session|compressors||Warning|delivers|upcoming|installation|https|switched|bye >collec use ${db}; sho…

图漾AGV行业常用相机使用文档

文章目录1.图漾相机设置IP1.1 前期准备2.FM851-E2相机2.1 FM851-E2适用场景2.2 FM851-E2 IO线和数据线定义2.2.1 IO接口定义2.2.2 数据接口线2.2.3 相机正面安装方向2.2.4 相机IO指示灯2.3 FM851-E2/FM855-E2-7相机RGB颜色异常【解决措施1】&#xff1a;【解决措施2】&#xff…

电力系统分析学习笔记(二)- 标幺值计算与变压器建模

电力系统分析学习笔记&#xff08;二&#xff09;- 标幺值计算与变压器建模 1. 电力系统参数计算的基本原理 1.1 基本级的概念与选择 基本级定义&#xff1a; 在多电压等级的电力系统中&#xff0c;需要将所有参数归算到同一个电压等级这个统一的电压等级称为基本级 基本级选择…

防火墙相关技术内容

防火墙的状态检测和会话技术一、防火墙的检测机制早期包过滤防火墙采用逐包检测机制&#xff0c;对每个报文独立检测其源地址、目的地址、端口等信息&#xff0c;根据预设规则决定转发或丢弃。安全隐患&#xff1a;仅基于单包信息判断&#xff0c;无法识别连接状态。例如&#…

在 Mac 上用 Vagrant 安装 K8s

文章目录&#x1f4cb; 1. 环境准备1.1 系统要求1.2 软件清单&#x1f680; 2. 安装步骤2.1 安装Parallels Desktop2.2 配置网络代理&#xff08;可选&#xff09;2.3 安装Homebrew2,4 准备项目目录2.5 安装Vagrant及插件2.6 配置Python环境2.6.1 安装Python管理工具2.6.2 配置…

【AI学习】RadioDiff:代码学习

之前学习了RadioDiff这篇论文&#xff0c;最近在复刻相关代码。 这段代码实现了一个基于潜在扩散模型&#xff08;Latent Diffusion Model, LDM&#xff09;的训练框架。借助DeepSeek总体学习一下&#xff1a; 1. 整体结构 代码主要分为以下几个部分&#xff1a; 参数解析和…

【专题十七】多源 BFS

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的基础算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&#xff…

京东零售在智能供应链领域的前沿探索与技术实践

近日&#xff0c;“智汇运河 智算未来”2025人工智能创新创业大会在杭州召开。香港工程科学院院士、香港大学副校长、研究生院院长、讲座教授、京东零售供应链首席科学家申作军教授与供应链算法团队技术总监戚永志博士受邀出席并担任《AI智慧物流与供应链分享会》联席主席&…

MyBatisPlus之CRUD接口(IService与BaseMapper)

MyBatisPlus之CRUD接口—IService与BaseMapper一、BaseMapper与IService的关系二、BaseMapper核心方法详解2.1 新增操作&#xff08;Insert&#xff09;2.2 查询操作&#xff08;Select&#xff09;2.3 更新操作&#xff08;Update&#xff09;2.4 删除操作&#xff08;Delete&…

axios请求的取消

axios请求的取消解决&#xff1a;axios请求的取消解决&#xff1a;axios请求的取消 在使用 Axios 发起请求时&#xff0c;有时候你可能需要取消这些请求&#xff0c;比如当组件销毁时或者用户操作导致不再需要获取之前发起的请求结果。Axios 支持通过 Cancel Token 取消请求。 …

深入理解C++中的Lazy Evaluation:延迟计算的艺术

在编程世界里&#xff0c;“最好的运算就是从未执行的运算” —— 这句话深刻揭示了性能优化的核心思路。如果一个计算过程最终不会被使用&#xff0c;那么提前执行它就是纯粹的资源浪费。这种思想衍生出了 Lazy Evaluation&#xff08;缓式评估&#xff09; 技术&#xff1a;延…

php完整处理word中表单数据的方法

使用php基础方式实现word中表单处理<?php/*** zipFile 类用于处理 .docx 文件的解压、修改和重新打包*/ class zipFile {/** var ZipArchive ZIP 文件对象 */private $zipFile;/** var string 临时目录路径 */private $tempDir;/** var string 嵌入的 Excel 文件临时目录路…

Node.js 操作 MongoDB

目录 Node.js 操作 MongoDB 一、什么是 MongoDB&#xff1f; 二、MongoDB 的功能概览 三、MongoDB 的安装与启动 安装 MongoDB&#xff08;以本地安装为例&#xff09; 启动 MongoDB 四、Node.js 如何连接 MongoDB&#xff1f; 使用 Mongoose ODM 工具 建立连接 五、…

先学Python还是c++?

选择先学Python还是C&#xff0c;取决于你的学习目标、应用场景和职业规划。以下是两者的对比分析和建议&#xff0c;帮助你做出更适合自己的选择&#xff1a;一、核心差异对比维度PythonC学习曲线简单易上手&#xff08;语法接近自然语言&#xff09;复杂&#xff08;需理解指…

Trae + Notion MCP:将你的Notion数据库升级为智能对话机器人

前言 Notion作为一款功能强大的信息管理工具&#xff0c;被广泛用于项目跟踪、知识库构建和数据整理。然而&#xff0c;随着数据量的增长&#xff0c;我们常常会发现自己陷入了重复和繁琐的操作中。比如&#xff0c;为了找到符合特定条件的几条数据&#xff0c;需要在庞大的数…

【iOS】retain/release底层实现原理

文章目录前言前情知识retain和release的实现原理&#xff08;MRC手动管理&#xff09;retain&#xff08;MRC手动管理&#xff09;retain源码内联函数rootRetain源码相关的sidetable_tryRetain()方法retain底层工作流程总结releaserelease源码内联函数rootRelease源码小结前言 …

文件同步神器-rsync命令讲解

rsync 是一个强大的文件同步与传输工具&#xff0c;广泛用于本地或远程服务器之间的高效文件备份、镜像或同步。其核心优势是通过增量传输​&#xff08;仅传输文件差异部分&#xff09;和压缩减少数据传输量&#xff0c;同时支持保留文件元数据&#xff08;如权限、时间戳、所…

Rust: 工具链版本更新

遇到 cargo build --release 错误&#xff0c;比如&#xff0c;当前 Rust 工具链版本&#xff08;1.78.0&#xff09;低于依赖项所需的最低版本&#xff08;部分依赖要求 ≥1.82.0&#xff09;。以下是系统化的解决方案&#xff1a; &#x1f527; 一、升级 Rust 工具链&#x…