Django:从缓存本地过滤查询集

use*_*130 7 django django-models

如果我prefetch_related('toppings')对查询集执行 a 操作,并且稍后想filter(spicy=True)通过相关表中的字段进行操作,Django 会忽略缓存的信息并执行数据库查询。我发现这已记录在案(在“注释”框下),并且在执行select_related()另一个缓存时似乎会发生所有形式的缓存(已评估的查询集等) 。filter()

然而,是否有某种超级秘密的隐藏省时快捷方式可以在本地进行过滤(使用缓存而不是访问数据库),而无需编写Python代码来循环查询集(使用列表/字典理解等)?也许像一个filter_locally(spicy=True)

编辑:

列表/理解对我来说效果不佳的原因之一是因为列表/字典没有查询集方法。就我而言,第一级 M2M 字段toppings并不是我的最终目标,我需要检查第二个相关的 M2M 字段(我也已经预取了该字段)。虽然使用列表理解也可以做到这一点,但使用以下内容要简单得多,filter_locally(spicy=True, origin__country='Spain')因为:

  1. 它允许以最小的努力访问多个级别的相关领域
  2. 它允许链接其他查询集方法
  3. 它更容易阅读,因为它与熟悉的一致filter()
  4. 使用无需预取的方式修改现有代码会更容易,filter()无需进行太多更改即可添加此优化。

但从回复来看,Django没有这样的支持:(

小智 2

如果您要过滤布尔值,则列表理解非常容易。您还可以将 替换topping.spicy==True为字符串比较或其他内容。

我会做类似的事情:

qs = Pizza.objects.all().prefetch_related('toppings')
res = list(qs)

def get_spicy(qs):
    res = list(qs)
    return [pizza  for pizza in res if any(topping.spicy==True for 
                                topping in pizza.toppings.all())]
Run Code Online (Sandbox Code Playgroud)

也就是说,如果您想要返回比萨饼对象,如果它的任何配料是辣的。您还可以将 any() 替换为 all() 来检查所有内容,并使用此语法执行许多非常强大的查询。我有点惊讶的是,在 django 中没有简单的方法可以做到这一点。看起来很多这样的简单查询应该很容易以通用方式实现。

上面的代码假设了一个many2many。它应该很容易修改以处理简单的 FK 关系,例如 one2one 或 one2many。

希望这有帮助。