这个查询比乍一看更难。AFAIK Django ORM 没有提供任何方法来为此查询生成有效的 SQL,因为有效的 SQL 需要相关的子查询。(我很乐意对此进行更正!)您可以使用此查询生成一些丑陋的 SQL:
Projectfundingdetail.objects.annotate(latest=Max('project__projectfundingdetail__end_date')).filter(end_date=F('latest')).filter(budget__lte==1000).select_related()
但这需要从 Projectfundingdetail 加入到 Project 并再次返回,这是低效的(尽管可能足以满足您的需求)。
另一种方法是编写原始 SQL 并将其封装在管理器方法中。它看起来有点吓人,但效果很好。如果您将经理分配为 Projectfundingdetail 上的“对象”属性,您可以像这样使用它来获取每个项目的最新资金详细信息:
>>> Projectfundingdetail.objects.latest_by_project()
它返回一个普通的 QuerySet,所以你可以添加更多的过滤器:
>>> Projectfundingdetail.objects.latest_by_project().filter(budget__lte=1000)
这是代码:
from django.db import connection, models
qn = connection.ops.quote_name
class ProjectfundingdetailManager(models.Manager):
def latest_by_project(self):
project_model = self.model._meta.get_field('project').rel.to
names = {'project': qn(project_model._meta.db_table),
'pfd': qn(self.model._meta.db_table),
'end_date': qn(self.model._meta.get_field('end_date').column),
'project_id': qn(self.model._meta.get_field('project').column),
'pk': qn(self.model._meta.pk.column),
'p_pk': qn(project_model._meta.pk.column)}
sql = """SELECT pfd.%(pk)s FROM %(project)s AS p
JOIN %(pfd)s AS pfd ON p.%(p_pk)s = pfd.%(project_id)s
WHERE pfd.%(end_date)s =
(SELECT MAX(%(end_date)s) FROM %(pfd)s
WHERE %(project_id)s = p.%(p_pk)s)
""" % names
cursor = connection.cursor()
cursor.execute(sql)
return self.model.objects.filter(id__in=[r[0] for r
in cursor.fetchall()])
大约一半的代码(“名称”字典)只需要对非标准数据库表和列名称的可能性保持健壮。如果您确信它们永远不会改变,您也可以将表和列名称硬编码到 SQL 中。