Django通过过滤器在相关字段上聚合

时间:2019-10-01 09:38:07

标签: django filter annotations

以下问题:
我有包含产品的产品组。这些产品在前端是否可见。我用frontend()方法(包含一个过滤器)确定它们的可见性,如下所示:

product_groups.first().products.frontend()

现在,我要确定是否要在首页中包含四个或更多产品的情况下才在首页上放置产品组的链接。
有了注释,我会做:

product_groups.annotate(num_products=Count('products')).filter(num_products__gte=4)

但是,这使我成为所有产品数量的原因,而不是前端可见产品的数量。

那么如何将附加过滤器frontend()放入查询中?需要明确的是,我希望Count()不在'products'上,而在products.frontend()上。

修改:
这不是建议问题的重复项。如果过滤器功能frontend()很简单,可以拉出过滤器并将其粘贴在聚合函数中,则建议的问题将回答我的问题。

我的frontend()函数非常复杂,并且包含多个其他过滤器函数。所以我真的很想使用frontend()函数。

修改:
这需要在Django 1.8中工作。

1 个答案:

答案 0 :(得分:1)

如果要在frontend()模型的Product上重用Queryset方法,则可以使用Subquery aggregate expressions

# assumption: `Product` has a fk to `ProductGroup`
# assumption 2: frontend() returns a `Queryset` of `Product` and is a method of `Product` model's default `Queryset`
frontend_products = Product.objects.filter(product_group=OuterRef('pk')).frontend().values('product_group')
total_products = frontend_products.annotate(total=Count('pk')).values('total')
q = product_groups.annotate(num_frontend_products=Subquery(total_products, output_field=IntegerField()))

请注意,对于没有任何对应产品的组,这将用num_frontend_products填充None而不是0。您可能希望进一步使用条件注释来修改查询集,以将None替换为0。