python - Django ORM 查询限制特定键实例

标签 python django orm django-models django-orm

Projectfundingdetail 有一个项目的外键。

以下查询为我提供了任何项目资金详细信息低于 1000 的所有项目的列表。如何将其限制为仅最新的项目资金详细信息。

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 的项目。

最佳答案

这个查询比乍一看要难。 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()

它返回一个普通的查询集,因此您可以添加更多过滤器:

>>> 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 中。

关于python - Django ORM 查询限制特定键实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/929468/

相关文章:

python - Django 过滤器 LIKE 数组 ORM 中的查询(图标)

python - Ubuntu 导入错误 : Could not import settings (works on Mac)

java - 存储盒装基元/字符串列表?

python - 使用最少数量的组件形成节点集

python - 如何让 socket.listen(1) 工作一段时间然后继续剩下的代码?

python - 非常简单的Python并发编程

python - 使用 Numpy 高效求和复杂矩阵乘积

python - 继承 celery 任务

java - 使用 Morphia 从 Mongo 获取文档时将值设置为非 DB 属性

java - Hibernate中带有命名查询的可选参数?