Django使用filter()时是否缓存关联表?示例场景疑问
Django Filter与关联表缓存的疑问解答
嘿,这问题问到点子上了,刚好是Django ORM里容易踩的N+1查询坑点,我给你掰扯清楚:
1. Django使用filter()时,会缓存关联表吗?
答案是不会,得拆成两点理解:
- 首先,
filter()本身只是构建一个查询集(QuerySet),这时候根本没触发数据库查询,更别说缓存关联表了。只有当你实际遍历查询集、调用len()或者取具体元素(比如e[0])时,才会执行SQL语句。 - 其次,就算执行了查询,默认情况下Django ORM只会拉取主表(比如这里的Entries)的数据,不会主动把关联表(Blog)的内容同步缓存下来。如果之后你再访问每个Entry对象的
blog属性,Django会单独给每个Entry发一次查询去取对应的Blog数据——这就是烦人的N+1查询问题。
2. 示例场景:e = Entries.objects.filter(blog__name='Something')的情况
这个语句里,blog__name='Something'只是用来筛选Entries的条件,Django会生成带JOIN的SQL来找出符合要求的Entry,但不会把Blog表的字段数据返回并缓存。具体来说:
- 如果你只需要Entry本身的数据,完全不用访问关联的Blog,那加不加
select_related都没影响; - 但如果你之后要用到每个Entry的
blog属性(比如e[0].blog.name),那必须加上select_related('blog')!这样Django会一次性把Entry和对应的Blog数据都查询出来,避免后续的N次额外数据库请求。
举个直观对比:
- 不加预加载:执行
e = Entries.objects.filter(blog__name='Something')后,第一次查询拿到所有符合条件的Entry;当你遍历e并访问每个item的blog时,每访问一次就会发一次新查询。 - 加预加载:
e = Entries.objects.select_related('blog').filter(blog__name='Something'),这时候只会发一次SQL查询,把Entry和关联的Blog数据都取回来,之后访问item.blog直接用缓存的数据,不会再碰数据库。
内容的提问来源于stack exchange,提问作者Utumbu
相关产品推荐
相关产品推荐

