news 2026/6/10 15:43:22

Django QuerySet filter 完全指南:高效查询数据的核心技巧

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django QuerySet filter 完全指南:高效查询数据的核心技巧

Django QuerySet filter 完全指南:高效查询数据的核心技巧

Django 的QuerySet.filter()是 ORM 中最核心的查询方法,它能让开发者无需编写原生 SQL,就能精准过滤数据库中的数据。本文将结合 Django 5.2 官方文档,从基础用法、进阶技巧到性能优化,全面拆解filter()的使用场景和最佳实践。

一、filter() 核心原理:惰性查询与链式调用

filter()的核心优势在于“惰性执行”——调用时不会立即访问数据库,只有当迭代结果、调用len()list()等方法时,才会触发 SQL 查询。这种机制让链式调用成为可能,多个过滤条件会被合并为一条高效的 SQL 语句。

/* by 01022.hk - online tools website : 01022.hk/zh/escape.html */ # 链式调用:多个filter条件通过AND逻辑合并 from django.db.models import Q from myapp.models import Entry # 等效于 WHERE pub_date > '2023-01-01' AND headline LIKE '%Django%' entries = Entry.objects.filter( pub_date__gt='2023-01-01' ).filter( headline__contains='Django' )

二、基础用法:字段查找规则

filter()的参数遵循“字段名__查找类型=值”的格式,当省略查找类型时,默认使用exact(完全匹配)。以下是最常用的字段查找方式:

1. 精确匹配与模糊匹配

  • exact:完全匹配(默认),支持None对应 SQL 的NULL
    /* by 01022.hk - online tools website : 01022.hk/zh/escape.html */ # 查找id=10的文章,等效于 Entry.objects.filter(id=10) Entry.objects.filter(id__exact=10) # 查找headline为空的文章(SQL: headline IS NULL) Entry.objects.filter(headline__exact=None)
  • contains/icontains:包含匹配(icontains不区分大小写)
    # 查找标题包含"Python"的文章(区分大小写) Entry.objects.filter(headline__contains='Python') # 不区分大小写的包含匹配 Entry.objects.filter(headline__icontains='python')

2. 数值与日期范围查询

  • 比较运算:gt(大于)、gte(大于等于)、lt(小于)、lte(小于等于)
  • range:闭区间范围查询(适用于日期、数值)
    # 查找2023年发布的文章 from datetime import date Entry.objects.filter(pub_date__year=2023) # 查找阅读量在100-500之间的文章 Entry.objects.filter(read_count__range=(100, 500)) # 查找30天内发布的文章 Entry.objects.filter(pub_date__gte=date.today() - timedelta(days=30))

3. 其他常用查找类型

  • startswith/istartswith:以指定字符串开头
  • endswith/iendswith:以指定字符串结尾
  • in:匹配可迭代对象中的任意值
    # 查找标题以"教程"结尾的文章 Entry.objects.filter(headline__endswith='教程') # 查找id在[1,3,5,7]中的文章 Entry.objects.filter(id__in=[1,3,5,7])

三、进阶技巧:复杂查询场景

1. OR 逻辑查询(Q 对象)

默认情况下,filter()的多个条件是AND关系,若需实现OR逻辑,需使用Q 对象

# 查找标题包含"Python"或2023年后发布的文章 Entry.objects.filter( Q(headline__contains='Python') | Q(pub_date__gt='2023-01-01') ) # 组合AND与OR:使用括号分组 Entry.objects.filter( Q(pub_date__year=2023) & (Q(headline__contains='Django') | Q(headline__contains='Flask')) )

2. 跨模型关联查询

对于ForeignKeyManyToManyField等关联字段,可通过双下划线__跨模型查询:

# 模型关系:Entry -> ForeignKey -> Blog # 查找所属博客名称为"技术周刊"的文章 Entry.objects.filter(blog__name='技术周刊') # 查找标签包含"前端"的文章(ManyToManyField) Entry.objects.filter(tags__name='前端')

3. 排除条件(exclude())

exclude()filter()用法完全一致,但作用是“排除匹配条件的记录”,相当于 SQL 中的NOT

# 查找不是2023年发布且标题不包含"广告"的文章 Entry.objects.exclude( pub_date__year=2023 ).exclude( headline__contains='广告' )

四、性能优化:让查询更快更高效

1. 避免不必要的查询

  • exists()判断是否存在结果,而非if QuerySet
  • count()统计数量,而非len(QuerySet)
    # 高效判断:是否存在2023年后发布的文章 if Entry.objects.filter(pub_date__gt='2023-01-01').exists(): print("存在符合条件的文章") # 高效统计:符合条件的文章数量 count = Entry.objects.filter(headline__contains='Django').count()

2. 关联查询优化(select_related/prefetch_related)

  • select_related():预加载一对一/外键关联对象(SQL JOIN)
  • prefetch_related():预加载多对多/反向关联对象(Python 层面拼接)
    # 预加载文章所属的博客,避免N+1查询 entries = Entry.objects.filter(pub_date__year=2023).select_related('blog') for entry in entries: # 无需额外查询数据库 print(entry.blog.name) # 预加载文章的所有标签(多对多关系) entries = Entry.objects.filter().prefetch_related('tags')

3. 只查询需要的字段(values/values_list)

若只需部分字段,用values()(返回字典)或values_list()(返回元组)减少数据传输:

# 只查询id和标题,返回字典列表 Entry.objects.filter(pub_date__year=2023).values('id', 'headline') # 只查询标题,返回扁平列表(flat=True) Entry.objects.filter().values_list('headline', flat=True)

五、常见误区与避坑指南

  1. 混淆 AND/OR 逻辑:多个filter()AND,多个Q 对象|表示OR
  2. 在循环中使用 filter():会导致 N+1 查询,应批量查询或用in条件
  3. 忽略惰性查询的副作用:修改 QuerySet 后未重新执行,会使用缓存结果
  4. 过度使用all()后过滤:应先filter()再处理,避免加载全部数据
# 错误:循环中多次查询(N+1问题) for blog_id in [1,2,3]: entries = Entry.objects.filter(blog_id=blog_id) # 每次循环都触发查询 # 正确:批量查询 entries = Entry.objects.filter(blog_id__in=[1,2,3]) # 仅1次查询

六、总结

filter()是 Django ORM 查询的基石,掌握其字段查找规则、复杂逻辑组合和性能优化技巧,能大幅提升开发效率和系统性能。核心要点:

  • 遵循“字段__查找类型=值”的参数格式,灵活运用各类查找条件
  • Q 对象实现 OR 逻辑,双下划线实现跨模型查询
  • 结合select_related()prefetch_related()等方法优化关联查询
  • 避免常见误区,优先使用exists()count()等高效方法

如果需要快速上手,建议从基础字段查找开始,逐步尝试复杂查询场景,同时借助 Django 的explain()方法分析查询执行计划,持续优化查询性能。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 23:21:46

【开题答辩全过程】以 共享停车位系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人,语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华
网站建设 2026/6/10 14:35:46

【开题答辩全过程】以 高校贫困生资助管理系统为例,包含答辩的问题和答案

个人简介一名14年经验的资深毕设内行人,语言擅长Java、php、微信小程序、Python、Golang、安卓Android等开发项目包括大数据、深度学习、网站、小程序、安卓、算法。平常会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。感谢大家的…

作者头像 李华
网站建设 2026/6/8 4:52:36

网易云音乐用户脚本完全手册:解锁网页版终极体验

网易云音乐用户脚本完全手册:解锁网页版终极体验 【免费下载链接】myuserscripts 油猴脚本:网易云音乐:云盘歌曲快传(含周杰伦),歌曲下载,转存云盘,云盘匹配纠正,听歌量打卡,本地上传云盘 咪咕音乐:歌曲下载 项目地址: https://gitcode.com/gh_mirrors/my/myusers…

作者头像 李华
网站建设 2026/6/9 19:03:05

MooaToon终极突破:在UE5中实现电影级卡通渲染的完整指南

MooaToon终极突破:在UE5中实现电影级卡通渲染的完整指南 【免费下载链接】MooaToon The Ultimate Solution for Cinematic Toon Rendering in UE5 项目地址: https://gitcode.com/gh_mirrors/mo/MooaToon 为什么传统卡通渲染总是达不到理想效果? …

作者头像 李华
网站建设 2026/6/9 22:06:51

《小岛经济学》第四章:经济到底是如何发展的

《小岛经济学》第四章:经济到底是如何发展的 渔网的普及让艾伯、贝克和查理彻底摆脱了“手停口停”的困境。每人每天只需1小时捕鱼就能收获两条鱼,多余的鱼被晒成鱼干储存起来,小岛的储蓄池日渐充盈。但贝克很快发现新的问题:“我…

作者头像 李华