values_list() 更省内存是因为返回元组或扁平列表,无字段名和字典开销;values() 每条记录构造 dict,字段名重复存储且哈希表额外占内存,百万级数据时内存差异达 2–3 倍。

values_list() 为什么比 values() 更省内存?
因为 values_list() 返回的是元组或扁平列表,不带字段名和字典开销;而 values() 每条记录都构造一个 dict,字段名重复存储、哈希表结构额外占内存。尤其查百万级数据时,内存差异可达 2–3 倍。
- 默认行为返回元组:
qs.values_list('name')→[('Alice',), ('Bob',), ...] - 加
flat=True才得扁平列表:qs.values_list('name', flat=True)→['Alice', 'Bob', ...] - 多个字段不加
flat=True会报错 ——flat=True只支持单字段
flat=True 的使用限制和替代方案
flat=True 看似方便,但只适用于单字段查询。一旦需要两个字段(比如 id 和 slug),就必须放弃 flat=True,否则 Django 报错:TypeError: flat=True is not valid when values_list() is called with more than one field.
- 双字段正确写法:
qs.values_list('id', 'slug')→ 返回[(1, 'a'), (2, 'b'), ...] - 想转成
dict?别在 Python 层循环转:dict(qs.values_list('id', 'slug'))更快且仍保持惰性求值 - 如果后续要频繁按 id 查 slug,用
dict()构建一次比每次.get()查库强得多
values_list() + iterator() 防止内存爆掉
即便用了 values_list(),Django 默认仍把全部结果缓存在内存里。查 10 万行以上数据时,必须搭配 iterator()。
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 错误示范:
list(MyModel.objects.values_list('email', flat=True))—— 全部加载进内存 - 正确做法:
for email in MyModel.objects.values_list('email', flat=True).iterator(chunk_size=2000): -
chunk_size建议设为 1000–5000:太小增加数据库往返次数,太大抵消流式优势 -
iterator()会禁用查询集缓存,不能重复遍历 —— 需要多次用就存成 list 或用itertools.tee
values_list() 在聚合和 distinct 场景下的坑
distinct() 和 values_list() 组合时,字段顺序影响去重逻辑,容易漏数据。
-
qs.values_list('category').distinct()→ 按 category 去重,没问题 -
qs.values_list('category', 'status').distinct()→ 是按 (category, status) 元组去重,不是只看 category - 想只按 category 去重又取 status?得用
annotate()或子查询,values_list().distinct()不够用 - 聚合函数如
Count必须配合values(),values_list()不支持 —— 想统计数量就得换写法
真正省内存的关键不在函数名,而在是否理解它返回什么、是否被惰性执行、以及字段组合是否真符合你的去重或映射意图。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










