[英]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_by
和distinct
的组合来实现所需的结果:
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_by
和distinct
。
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 使用以下将仅将具有类似a
和b
所有对象放在一起
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
(按递减顺序)对组中的对象(具有相同的a
和b
值)进行排序
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
. 现在,具有相似a
和b
所有对象在一起,并且在每个组中,第一个元素具有最新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.