4

如果我对查询集执行prefetch_related('toppings')查询,并且我想稍后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 没有这样的支持:(

4

2 回答 2

3

您必须编写 python 代码来循环查询集(列表/字典理解是理想的)。所有filter()代码都知道如何将过滤语言添加到发送到数据库的 SQL 中。本地过滤与远程过滤是完全不同的问题,因此这两个独立问题的解决方案将无法共享任何逻辑。

不过,单行列表理解将非常简单;语法可能不会比 with 复杂得多filter()

于 2013-11-04T20:20:54.610 回答
1

如果您要过滤布尔值,则列表理解非常容易。您还可以将 替换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())]

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

上面的代码假设是many2many。它应该很容易修改以使用简单的 FK 关系,例如 one2one 或 one2many。

希望这会有所帮助。

于 2013-11-04T21:29:48.287 回答