Django 1.9:为QuerySet创建复杂的自定义过滤器方法

时间:2016-03-07 13:55:50

标签: python sql django filter django-queryset

目标是创建一个可以链接到标准Django过滤器方法的custom_filter方法。 custom_filter方法可能需要一些原始SQL代码。在最好的情况下, QuerySet 仍然会被评估为懒惰。

最后,这样的命令会很棒:

apple_query_set = Apple.objects.filter(<any standard filtering>).custom_filter()

这是模型:

class Apple(models.model):
    a = models.IntegerField()
    b = models.IntegerField()
    date = models.DateField()

custom_filter的目标是按(a,b)对每个Apple实例进行分组 group仅根据date返回最新实例。

此类过滤器的原始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;
"""

到目前为止,为了添加custom_filter功能,  我已尝试(未成功)将objects = AppleQuerySet.as_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()

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

2 个答案:

答案 0 :(得分:1)

这是一种替代方式,但我想知道您是否只能使用order_bydistinct的组合来达到预期效果:

 auto x = Proxy().method1().method2(); // no
 Proxy p; // no
 Target x = Proxy(); //yes
 Target x = Proxy().method1().method2(); //yes

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

并且,通过这种方式,如果需要,您还可以事先使用链式distinct

一些解释:

使用以下内容只会将所有具有相似filtera的对象放在一起

b

但是,您可以按Apple.objects.order_by('a', 'b') (按递减顺序)对组中的对象(具有相同的ab值)进行排序

-date

现在,所有具有相似Apple.objects.order_by('a', 'b', '-date') a的对象都在一起,并且在每个组中,第一个元素具有最新的b。因此,我们可以使用date

将这些内容保持在最顶层
distinct('a', 'b')

答案 1 :(得分:-1)

我认为您需要的是自定义经理。在Django documentation

上查看

在这里,您可以看到一个使用原始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