简体   繁体   English

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

[英]Django 1.9: Create complex custom filter method for QuerySet

The goal is to create a custom_filter method that can be chained to standard Django filter methods. 目标是创建一个可以链接到标准Django过滤器方法的custom_filter方法。 The custom_filter method likely requires some raw SQL code. custom_filter方法可能需要一些原始SQL代码。 In the best case, the QuerySet would still be evaluated lazy. 在最好的情况下, QuerySet仍然会被评估为惰性。

In the end, such a command would be great: 最后,这样的命令会很棒:

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

This is the model: 这是模型:

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

The goal of the custom_filter is to group the Apple instances by (a,b) , and for each group return only the newest instance according to date . custom_filter的目标是通过(a,b)对Apple实例进行分组,并且对于每个组,仅根据date返回最新实例。

The raw SQL code for such a filter is as follows: 这种过滤器的原始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;
"""

So far, in order to add the custom_filter functionality, I've tried (unsuccessfully) adding objects = AppleQuerySet.as_manager() to the Apple class, with: 到目前为止,为了添加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])

However, I'm not sure this approach stands a chance to work, as the custom query should not only work on all Apple instances ( Apple.objects. ), but it should be possible to chain it to a filtered queryset ( Apple.objects.filter() ) 但是,我不确定这种方法是否有效,因为自定义查询不仅适用于所有Apple实例( Apple.objects. ),而且应该可以将其链接到过滤的查询集( Apple.objects.filter()

What is the best approach to create this custom chainable, (lazy) custom_filter functionality? 创建此自定义可链接(懒惰) custom_filter功能的最佳方法是什么? Where am I going wrong? 我哪里错了? Thanks a lot! 非常感谢!

This is an alternative way, but I wonder if you could only use a combination of order_by and distinct to achieve the desired results: 这是一种替代方法,但我想知道你是否只能使用order_bydistinct的组合来实现所需的结果:

Apple.objects.order_by('a', 'b', '-date').distinct('a', 'b')

This combination works if you keep the ordering of fields same in order_by and distinct . 如果你保持在同一字段的顺序这种组合适用order_bydistinct

And, this way you can also user the chained filter beforehand if you need to. 并且,这样您也可以在需要时预先使用链式filter

Some explanation: 一些解释:

Using following will only put all the objects with similar a and b together 使用以下将仅将具有类似ab所有对象放在一起

Apple.objects.order_by('a', 'b')

But, you can order the objects in a group (with same a and b values) further by -date (in decreasing order) 但是,您可以通过-date (按递减顺序)对组中的对象(具有相同的ab值)进行排序

Apple.objects.order_by('a', 'b', '-date')

Now, all the objects which have similar a and b are together and in each group first element has the latest date . 现在,具有相似ab所有对象在一起,并且在每个组中,第一个元素具有最新date So, we can keep the ones at the top by using distinct('a', 'b') 所以,我们可以通过使用distinct('a', 'b')distinct('a', 'b')保持在顶部

Apple.objects.order_by('a', 'b', '-date').distinct('a', 'b')

I think what you need is a custom manager. 我认为你需要的是一个自定义经理。 Check it out on Django documentation 查看Django文档

Here you can see an example, using raw SQL code: 在这里,您可以看到一个示例,使用原始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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM