Projectfundingdetail有一个外键项目。

下面的查询让我有 1000下的任何的projectfundingdetail如何把它限制在最新projectfundingdetail所有项目的列表只。

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

我已经定义下面的函数,

def latest_funding(self):
    return self.projectfundingdetail_set.latest(field_name='end_date')

但是我不能使用以下作为latest_funding不是数据库字段

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

所以,我应该用什么查询获取1000下只具有其最新projectfundingdetail的所有项目。

有帮助吗?

解决方案

此查询是比看起来难乍一看。据我所知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加入到项目,然后再返回,这是低效的(尽管可能满足您的需求)。

其他的方法来做到这是写入原始SQL,并在管理器方法将其封装。它看起来有点吓人,但伟大工程。如果分配经理作为“物”的属性上Projectfundingdetail,你可以使用它像这样以获得最新的资金细节每个项目:

>>> Projectfundingdetail.objects.latest_by_project()

和它返回一个正常查询集,以便可以添加进一步的过滤器:

>>> 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,如果你相信他们永远不会改变。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top