django的.extra(where =子句被表重命名.filter(foo__in = ... subselects)破坏了

时间:2010-07-20 20:00:43

标签: django django-orm subquery

缺点是,过滤器内的所有查询的表名都被重命名为u0,u1,...,所以我的额外where子句将不知道要指向哪个表。我希望不必为我可能在这些数据上选择的每种方式手工制作所有查询,而我目前的解决方法是将我的额外查询转换为pk values_lists,但这些查询真的很慢而且令人厌恶。

以下是这一切的样子。除了第一个指向products_product.id的sql行之外,你几乎可以忽略这个管理器方法的额外细节:

def by_status(self, *statii):
    return self.extra(where=["""products_product.id IN                                                                                                                                                  
        (SELECT recent.product_id                                                                                                                                                                          
          FROM (                                                                                                                                                                                           
            SELECT product_id, MAX(start_date) AS latest                                                                                                                                                   
            FROM products_productstatus                                                                                                                                                                    
            GROUP BY product_id                                                                                                                                                                            
          ) AS recent                                                                                                                                                                                      
          JOIN products_productstatus AS ps ON ps.product_id = recent.product_id                                                                                                                           
          WHERE ps.start_date = recent.latest                                                                                                                                                              
            AND ps.status IN (%s))""" % (', '.join([str(stat) for stat in statii]),)])

对于仅涉及products_product表的所有情况都非常有效。

当我想要这些产品作为子选择时,我会这样做:

Piece.objects.filter(
    product__in=Product.objects.filter(
        pk__in=list(
            Product.objects.by_status(FEATURED).values_list('id', flat=True))))

如何保持查询集的通用功能,但仍然使用额外的where子句?

1 个答案:

答案 0 :(得分:3)

起初:这个问题对我来说并不完全清楚。问题中的第二个代码块是否是您要执行的实际代码?如果是这种情况,则查询应该按预期工作,因为没有执行子选择。

我假设您希望在子选择周围使用第二个代码块而不使用list()来阻止执行第二个查询。


django文档引用了此问题in the documentation about the extra method。然而,解决这个问题并不容易。

最简单但最“hakish”的解决方案是观察django为要在额外方法中查询的表生成哪个表别名。只要您始终以相同的方式构造查询(您不会更改导致连接的多个extra方法或filter调用的顺序),您可以依赖此别名的持久命名

您可以使用以下方法检查将在数据库查询集中执行的查询:

print Model.objects.filter(...).query

这将显示用于要查询的表的别名。