如何在Django中预取聚合的@property? [英] How to prefetch aggregated @property in Django?

查看:214
本文介绍了如何在Django中预取聚合的@property?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有两个模型(简化版本):

We have two models (simplified versions):

class Contestant(models.Model):
    email = models.EmailField(max_length=255, unique=True)
    # plus some other fields

    @property
    def total_points(self):
        return self.points.aggregate(total=Sum('value'))['total'] or 0

class Points(models.Model):
    contestant = models.ForeignKey(Contestant, related_name='points')
    value = models.PositiveIntegerField()
    # plus some other fields which determine based on what we
    # awarded ``Points.value``

当我们显示参赛者名单以及 total_points 值时,它
导致对每个结果的额外查询 - 即执行以下查询:

When we display a list of contestants along with their total_points value, it results in an extra query for each result - i.e. the following queries are performed:


  1. 获取参赛者列表

  2. 获取 total_points 第一参赛者的价值

  3. 获取 total_points v第二名参赛者的评价


  1. fetch list of contestants
  2. fetch total_points value of 1st contestant
  3. fetch total_points value of 2nd contestant
  4. etc

我尝试改变查询集,以便如下预取数据:

I tried altering the queryset to prefetch the data as follows:

Contestant.objects.filter(...).prefetch_related('points')

...,但是即使它有效,当
列出参赛者时,预取数据也不会被使用(所以每个结果仍然会尝试在单独的查询中获取 total_points

..., however even though it works, the prefetched data is not utilized when listing contestants (so each result still tries to fetch total_points in a separate query).

是否可以:



  • 为单个模型对象填充数据,以某种方式告诉ORM为@property字段使用预取值(例如访问 Contestant.total_points @property方法中的预取值)

  • 或以不同的方式预取它们(而不是或者使用完全不同的方法实现相同的结果?

  • somehow tell the ORM to use prefetched values for the @property field when populating data for individual model objects (e.g. access the prefetched value inside the Contestant.total_points @property method)?
  • or to prefetch them in a different way (as opposed to the example above)?
  • or to use a completely different approach achieving the same result?

(我在 tastypie 中列出结果,如果重要)。

(I'm listing results in tastypie, if it matters.)

谢谢。

推荐答案

当您的目的是为每个项目添加聚合值时,您应该使用 annotate / a>,而不是聚合

When your aim is to add aggregated values to each item, you should use annotate, instead of aggregate.

例如(一个简单的查询,不需要额外的方法):

For example (a simple query, no additional methods required):

Contestant.objects.filter(...).annotate(total_points=Sum('points__value'))






如果你真的想把这个代码放出您的查询:您可以,但是一种模型方法不是正确的方法。模型上的方法用于单个实例的操作。如果您想在整个QuerySet上执行某些操作,请使用 ORM管理器

有一个经理这样看起来像这样:

With a Manager this would look like this:

class TotalPointsManager(models.Manager):
    def get_queryset(self):
        return super(TotalPointsManager, self).get_queryset().annotate(total_points=Sum('points__value'))

class Contestant(models.Model):
    email = models.EmailField(max_length=255, unique=True)

    objects = TotalPointsManager() # You are overriding the default manager!

然后你将像往常一样构造你的查询(你可以删除 prefetch_related ):

and then you would construct your query as usual (you can drop prefetch_related):

Contestant.objects.filter(...)

...和 total_points 字段将成为神奇可用于每个对象。

...and total_points field would become "magically" available for every object.

这篇关于如何在Django中预取聚合的@property?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆