【问题标题】:Using django prefetch_related() to get the time of last activity使用 django prefetch_related() 获取上次活动的时间
【发布时间】:2025-12-05 12:40:01
【问题描述】:

我升级到 Django 1.7,所以我可以得到 Prefetch objects,但我很难让它们按预期运行。

我有一个这样的 Employee 模型:

class Employee(Human):
  ... additional Employee Fields ...

  def get_last_activity_date(self):
    try:
        return self.activity_set.all().order_by('-when')[0:1].get().when
    except Activity.DoesNotExist:
        return None

还有这样的活动

class Activity(models.Model):
  when = models.DateTimeField()
  employee = models.ForeignKey(Employee, related_name='activity_set')

我想使用 prefetch_related 来获取该员工的最后活动日期。我尝试过多种方式来表达,但无论我怎么做,它最终都会生成另一个查询。我的另外两个 prefetch_related 部分按预期工作,但这一个似乎并没有为我节省任何查询。

我将它与 Django Rest Framework 一起使用,所以我真的需要 prefetch_related 部分才能工作,因为我无法进入 DRF 内部以在查询集之外进行映射。

这是不起作用

的方法之一
def get_queryset(self):

    return super(EmployeeViewSet, self).get_queryset()\
           .prefetch_related('phone_number_set', 'email_address_set')\
           .prefetch_related(Prefetch('activity_set', Activity.objects.all().order_by('-when')))\
           .order_by('last_name', 'first_name')

请注意,在 activity_set 预取查询中,我不能切片以仅获取最新条目,这在这将消耗多少内存方面是一个问题。

我确实看到发生了预取查询,但随后每个员工都获得了针对该信息的单独查询,这意味着我有一个更大的浪费查询,但仍然得到了我试图阻止的约 200 个查询。

在这种情况下,您如何让 prefetch_related 为我工作?

【问题讨论】:

    标签: django


    【解决方案1】:

    我怀疑你错过了prefetch_related 的意思。文档state 这是预期的行为:许多查询和 python 中的“加入”。如果您想要更少的查询,您应该使用select_related 另外我不确定它是否适用于您的特定模型(问题中未说明),因为 select_related 确实适用于多对多关系。

    更新 - 文档:

    另一方面,prefetch_related 对每个关系进行单独的查找,并在 Python 中进行“连接”

    【讨论】:

    • selected_related 不适用于这种关系。 select_related 仅在 ForeignKey 在 Employee 上时才有效。不是反向关系。当prefetch_related 工作时,您会获得所有员工的查询,然后从该查询中提取他们的数据。
    • 我怀疑你们的模型在这里不支持 select_related。但是你对prefetch_related的含义是错误的。它会做很多查询,它在文档中是明确的..
    • 仔细阅读,它对每个关系进行一次查询,而不是每个关系的每个模型。就像我上面说的,另外 2 个 prefetch_related 工作得很好。这个不同之处在于它试图获取最新的。我还使用 DjDT 来查看查询,它们都是我所期望的,除了围绕最后一个活动的每个模型实例的额外查询。