在 Python 中,QuerySet 是 Django 框架中用于与数据库交互的核心对象,它代表从数据库中查询出来的一组记录(对象集合),并提供了丰富的方法来过滤、排序、聚合数据。
以下是关于 Django QuerySet 的全面指南:
什么是 QuerySet?
- 惰性加载(Lazy Evaluation):创建
QuerySet时不会立即执行数据库查询,只有在真正需要数据时(如迭代、切片、调用len()或list())才会执行 SQL 查询。 - 可链式调用:大多数查询方法返回新的
QuerySet,因此可以链式调用。 - 缓存机制:一旦
QuerySet被评估(即执行了查询),结果会被缓存,避免重复查询。
基本用法
假设有一个模型 Author:
from myapp.models import Author # 获取所有作者 all_authors = Author.objects.all() # 获取单个作者 author = Author.objects.get(id=1) # 获取满足条件的作者 young_authors = Author.objects.filter(age__lt=30)
常用查询方法
✅ 过滤(Filtering)
# 精确匹配 authors = Author.objects.filter(name="Alice") # 不等于 authors = Author.objects.exclude(name="Alice") # 范围查询 authors = Author.objects.filter(age__gte=18, age__lte=65) # 包含(模糊匹配) authors = Author.objects.filter(name__contains="Ali") # 以...开头 / 以... authors = Author.objects.filter(name__startswith="A") authors = Author.objects.filter(name__endswith="e") # 正则表达式 import re authors = Author.objects.filter(name__regex=r'^[A-Z]')
✅ 排序(Ordering)
# 升序
authors = Author.objects.order_by('name')
# 降序
authors = Author.objects.order_by('-name')
# 多字段排序
authors = Author.objects.order_by('name', '-age')
✅ 分页(Limiting)
# 前5条记录 first_five = Author.objects.all()[:5] # 跳过前10条,取接下来5条 page2 = Author.objects.all()[10:15]
⚠️ 注意:对
QuerySet进行切片会限制查询结果,但不会返回QuerySet(而是列表)。
✅ 聚合与统计
from django.db.models import Count, Avg, Max, Min, Sum
# 统计作者总数
total = Author.objects.count()
# 平均年龄
avg_age = Author.objects.aggregate(Avg('age'))['age__avg']
# 每个出版社的作者数量
from django.db.models import Count
pubs = Publisher.objects.annotate(num_authors=Count('author'))
✅ 连接查询(Join)
# 获取写过书且书名包含 "Python" 的作者 authors = Author.objects.filter(book__title__contains="Python") # 去重 authors = Author.objects.filter(book__title__contains="Python").distinct()
高级特性
✅ 选择特定字段(Select Only Fields)
减少数据传输量:
authors = Author.objects.values('name', 'email')
# 返回字典列表:[{'name': 'Alice', 'email': 'alice@example.com'}, ...]
✅ 排除特定字段
authors = Author.objects.exclude('password_hash')
✅ 使用 defer 和 only
延迟加载某些字段(节省内存):
# 只加载 name 和 email,其他字段延迟加载
authors = Author.objects.only('name', 'email')
# 排除加载 bio 字段
authors = Author.objects.defer('bio')
✅ 使用 select_related 和 prefetch_related 优化查询
避免 N+1 查询问题:
# 一对一或外键关系,使用 select_related
authors = Author.objects.select_related('publisher').all()
# 多对多或反向外键,使用 prefetch_related
books = Book.objects.prefetch_related('authors').all()
常见陷阱
| 问题 | 说明 |
|---|---|
| 未评估的 QuerySet | 创建后未使用,不会执行 SQL,可能导致逻辑错误 |
| 重复查询 | 多次调用 len() 或迭代会重新查询,建议使用缓存或 list() |
| N+1 查询 | 在循环中访问关联对象会导致多次数据库查询,使用 select_related 或 prefetch_related |
| 内存溢出 | 对大量数据使用 .all() 或 .values() 可能导致内存不足,建议使用分页或迭代器 |
示例:完整查询流程
from myapp.models import Author, Book
from django.db.models import Count
# 1. 获取所有写过至少一本书的作者
authors = Author.objects.filter(book__isnull=False).distinct()
# 2. 按书名数量排序
authors = authors.annotate(book_count=Count('book')).order_by('-book_count')
# 3. 只获取姓名和邮箱
authors = authors.values('name', 'email')
# 4. 评估查询(执行 SQL)
result = list(authors)
print(result)
调试查询
在开发环境中,可以查看生成的 SQL:
print(Author.objects.filter(name="Alice").query)
或使用 Django Debug Toolbar 查看每次请求的 SQL 执行情况。
首发原创文章,作者:世雄 - 原生数据库架构专家,如若转载,请注明出处:https://idctop.com/article/483513.html



