【问题标题】:Modern methods for filtering a Django annotation?过滤 Django 注释的现代方法?
【发布时间】:2015-12-09 23:12:27
【问题描述】:

我想使用 Django ORM 过滤注释。我在 SO 上找到的很多文章都过时了,目标是 1.2 到 1.4 天内的 Django:

Django 1.8 添加了conditional aggregation,这似乎是我想要的,但我不能完全弄清楚我最终需要的语法。这是我的模型和我试图达到的场景(为简洁起见,我简化了模型):

class Project(models.Model):
    name = models.CharField()
    ... snip ...

class Milestone_meta(models.Model):
    name = models.CharField()
    is_cycle = models.BooleanField()

class Milestone(models.Model):
    project = models.ForeignKey('Project')
    meta = models.ForeignKey('Milestone_meta')
    entry_date = models.DateField()

我想获取每个 Project(及其所有字段),以及每个关联 MilestoneMax(entry_date)Min(entry_date),但仅适用于关联 Milestone_meta 的那些 Milestone 记录is_cycle 标志设置为 True。换句话说:

  • 对于每个项目记录,给我最大和最小里程碑 entry_dates,但仅当关联的 Milestone_meta 的给定标志设置为 True 时。

目前,我正在获取项目列表,然后在循环中获取 MaxMin 里程碑,导致 N+1 数据库命中(如您所料,这会变慢):

pqs = Projects.objects.all()

for p in pqs:
    (theMin, theMax) = getMilestoneBounds(p)
    # Use values from p and theMin and theMax

...

def getMilestoneBounds(pid):
    mqs = Milestone.objects.filter(meta__is_cycle=True)
    theData = mqs.aggregate(min_entry=Min('entry_date'),max_entry=Max('entry_date'))

    return (theData['min_entry'], theData['max_entry'])

如何将其减少到一两个查询?

【问题讨论】:

  • 我认为这绝对是真正应该使用额外甚至原始 sql 的情况。
  • 文档表明 extra 最终将被弃用。理想情况下,我想在某种程度上使用一些面向未来的东西。
  • 那么使用更强大甚至更好的原始sql

标签: django django-models orm


【解决方案1】:

据我所知,您无法在一次查询中获得所有必需的 project 对象。

但是,如果您不需要这些对象并且可以只使用它们的 id,那么一种方法是 -

Milestone.objects.filter(meta__is_cycle=True).values('project').annotate(min_entry=Min('entry_date')).annotate(max_entry=Max('entry_date'))

它将给出一个包含不同项目数据的字典列表,然后您可以在需要时使用它们的 'id' 来查找对象。

【讨论】:

    猜你喜欢
    • 2019-08-17
    • 1970-01-01
    • 2015-04-07
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 2012-04-05
    • 2012-03-07
    • 2017-11-13
    相关资源
    最近更新 更多