Python Django 1.9:为QuerySet创建复杂的自定义筛选器方法

Python Django 1.9:为QuerySet创建复杂的自定义筛选器方法,python,sql,django,filter,django-queryset,Python,Sql,Django,Filter,Django Queryset,我们的目标是创建一个定制的_filter方法,该方法可以链接到标准的Django filter方法。custom_filter方法可能需要一些原始SQL代码。在最好的情况下,QuerySet的计算结果仍然是惰性的 最终,这样的命令将是伟大的: apple_query_set = Apple.objects.filter(<any standard filtering>).custom_filter() 自定义过滤器的目标是按(a,b)对Apple实例进行分组,并针对每个实例进行分组

我们的目标是创建一个
定制的_filter
方法,该方法可以链接到标准的Django filter方法。
custom_filter
方法可能需要一些原始SQL代码。在最好的情况下,QuerySet的计算结果仍然是惰性的

最终,这样的命令将是伟大的:

apple_query_set = Apple.objects.filter(<any standard filtering>).custom_filter()
自定义过滤器的目标是按
(a,b)
对Apple实例进行分组,并针对每个实例进行分组 组仅根据
日期返回最新实例

此类筛选器的原始SQL代码如下所示:

custom_filter_raw_sql = """
SELECT t1.id
FROM app_apple AS t1
INNER JOIN (SELECT a, b, max(date) AS max_date
            FROM app_apple
            GROUP BY a, b) AS t2
ON t1.a = t2.a AND t1.b = t2.b AND t1.date = t2.max_date;
"""
到目前为止,为了添加
自定义过滤器
功能, 我已尝试(未成功)将
objects=AppleQuerySet.as\u manager()
添加到Apple类,包括:

 class AppleQuerySet(models.QuerySet):
    def custom_filter(self):
        subquery = """
        SELECT t1.id
        FROM app_apple AS t1
        INNER JOIN (SELECT a, b, max(date) AS max_date
                    FROM app_apple
                    GROUP BY a, b) AS t2
        """
        condition = "t1.a = t2.a AND t1.b = t2.b AND t1.date = t2.max_date"
        return self.extra(tables=[subquery], where=[condition])
但是,我不确定这种方法是否有可能像自定义查询那样起作用 不仅应适用于所有Apple实例(
Apple.objects.
),还应能够将其链接到已筛选的查询集(
Apple.objects.filter()


创建此自定义可链接(惰性)
自定义过滤器
功能的最佳方法是什么?我哪里做错了?非常感谢

我想你需要的是一个定制经理。请在

这里您可以看到一个使用原始SQL代码的示例:

from django.db import models

class PollManager(models.Manager):
    def with_counts(self):
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("""
            SELECT p.id, p.question, p.poll_date, COUNT(*)
            FROM polls_opinionpoll p, polls_response r
            WHERE p.id = r.poll_id
            GROUP BY p.id, p.question, p.poll_date
            ORDER BY p.poll_date DESC""")
        result_list = []
        for row in cursor.fetchall():
            p = self.model(id=row[0], question=row[1], poll_date=row[2])
            p.num_responses = row[3]
            result_list.append(p)
        return result_list

这是另一种方法,但我想知道您是否只能使用和的组合来实现预期的结果:

Apple.objects.order_by('a', 'b', '-date').distinct('a', 'b')
如果在
order\u by
distinct
中保持字段的顺序相同,则此组合有效

这样,如果需要,您还可以提前使用链接的
过滤器

一些解释:

使用以下命令只会将具有类似
a
b
的所有对象放在一起

Apple.objects.order_by('a', 'b')
但是,您可以按
-date
(降序)对组中的对象(具有相同的
a
b
值)进一步排序

现在,所有具有类似
a
b
的对象都在一起,并且在每个组中,第一个元素具有最新的
日期。因此,我们可以使用
distinct('a','b')


有没有具体的原因让你不能直接使用查询本身的所有过滤条件?@AKS这可能是一个解决方案,但我不知道如何确保SQL代码可以任意链接到查询集(而不是对整个Apple表进行过滤)。我很高兴看到一些代码如何做到这一点。(另外,我不确定这个解决方案是否允许延迟计算。)如果返回的值应该是QuerySet,这个解决方案会是什么样子?该方法是否可以作为链式过滤器应用(而不是在整个Apple表上重新运行查询?)。此解决方案是否允许延迟评估?这里展示了如何从自定义管理器创建自定义查询集,它应该回答前两个问题。我不知道你说的“允许惰性评估”是什么意思这是一个优雅的答案@AKS,您认为(在本例中当然)通过自定义SQL添加过滤器链步骤的笨拙方法在技术上是可行的吗?在这种情况下,是否有示例代码?谢谢@elke,您坚持使用您提到的方法有什么特别的原因吗?我之所以这样说,是因为使用上述现有的django功能可以很容易地实现您想要的结果。@AKS,对于上面的示例,您的方法绝对是首选。我的想法是,如果另一个用户偶然发现本文,“如何将类似复杂的sql查询插入queryset筛选器”的答案可能是她要搜索的,而不是我的特定示例问题的解决方案。然而,也许所有的问题最终都有如此优雅的解决方案?
Apple.objects.order_by('a', 'b')
Apple.objects.order_by('a', 'b', '-date')
Apple.objects.order_by('a', 'b', '-date').distinct('a', 'b')