Django ORM查询以限制特定键实例

2024-10-03 19:20:37 发布

您现在位置:Python中文网/ 问答频道 /正文

Projectfundingdetail具有project的外键。在

下面的查询给出了任何projectfundingdetail低于1000的所有项目的列表。我如何限制它只限于最新的项目资金细节。在

projects_list.filter(projectfundingdetail__budget__lte=1000).distinct()

我定义了以下函数

^{pr2}$

但我不能使用以下内容,因为latest_funding不是数据库字段

projects_list.filter(latest_funding__budget__lte=1000).distinct()

所以,我应该使用什么查询来获取所有只有最新的projectfundingdetail低于1000的项目。在


Tags: 项目project列表filterlatest外键listprojects
1条回答
网友
1楼 · 发布于 2024-10-03 19:20:37

这个查询比乍看起来难。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再到back,这是低效的(尽管可能足够满足您的需要)。在

另一种方法是编写原始SQL并将其封装在manager方法中。它看起来有点吓人,但效果很好。如果您在Projectfundingdetail上将manager指定为“objects”属性,则可以使用它来获取每个项目的最新资金详细信息:

^{pr2}$

它返回一个普通的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()])

其中大约一半的代码(“names”字典)只需要对可能出现的非标准数据库表和列名具有健壮性。如果您确信表和列名永远不会更改,也可以将它们硬编码到SQL中。在

相关问题 更多 >