Django 1.9:为 QuerySet 创建复杂的自定义过滤器方法
Django 1.9: Create complex custom filter method for 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 实例进行分组,并且对于每个
根据 date
.
组 return 只有最新的实例
这种过滤器的原始 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,其中:
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
功能的最佳方法是什么?我哪里错了?非常感谢!
我认为您需要的是自定义管理器。在 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
这是另一种方法,但我想知道您是否只能使用 order_by
and distinct
的组合来达到预期的效果:
Apple.objects.order_by('a', 'b', '-date').distinct('a', 'b')
如果您在 order_by
和 distinct
.
中保持字段顺序相同,则此组合有效
而且,如果需要,您还可以通过这种方式预先使用链式 filter
。
一些解释:
使用following只会把所有a
和b
相似的对象放在一起
Apple.objects.order_by('a', 'b')
但是,您可以通过 -date
(降序)
进一步对组中的对象(具有相同的 a
和 b
值)进行排序
Apple.objects.order_by('a', 'b', '-date')
现在,所有具有相似 a
和 b
的对象都在一起,并且在每个组中第一个元素具有最新的 date
。因此,我们可以使用 distinct('a', 'b')
将它们保留在顶部
Apple.objects.order_by('a', 'b', '-date').distinct('a', 'b')
目标是创建一个可以链接到标准 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 实例进行分组,并且对于每个
根据 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,其中:
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
功能的最佳方法是什么?我哪里错了?非常感谢!
我认为您需要的是自定义管理器。在 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
这是另一种方法,但我想知道您是否只能使用 order_by
and distinct
的组合来达到预期的效果:
Apple.objects.order_by('a', 'b', '-date').distinct('a', 'b')
如果您在 order_by
和 distinct
.
而且,如果需要,您还可以通过这种方式预先使用链式 filter
。
一些解释:
使用following只会把所有a
和b
相似的对象放在一起
Apple.objects.order_by('a', 'b')
但是,您可以通过 -date
(降序)
a
和 b
值)进行排序
Apple.objects.order_by('a', 'b', '-date')
现在,所有具有相似 a
和 b
的对象都在一起,并且在每个组中第一个元素具有最新的 date
。因此,我们可以使用 distinct('a', 'b')
Apple.objects.order_by('a', 'b', '-date').distinct('a', 'b')