使用 Django 避免 O(n) 查询
我有这样的模型:
class PledgeItem(models.Model):
title = models.CharField(...)
usd_amount = models.DecimalField(...)
class Pledger(models.Model):
name = models.CharField(...)
...
class Pledge(models.Model):
pledger = models.ForeignKey(Pledger)
item = models.ForeignKey(PledgeItem)
usd_amount = models.DecimalField(...)
...
我的 PledgeItem
有一种方法可以计算出承诺的百分比(例如,一件物品可能花费 100 美元,并且有 3 个承诺,每个承诺 20 美元,这意味着它是 60%承诺):
class PledgeItem(models.Model):
...
def percentage_pledged(self):
pledge_total = Pledge.objects.filter(item = self).sum(usd_amount)
return (pledge_total / self.usd_amount) * 100
就本问题而言,请假设我正确处理了 self.usd_amount
为零,以及 PledgeItem< 上没有
Pledges
的情况/code> (尽管我不得不问,为什么 sum(field)
在这些情况下返回 None
?)。
问题是,如果我在 n
PledgeItems
列表中调用 percentage_pledged
,则每个 PledgeItem
都有一个查询。有没有一种优雅的方法可以解决此问题,而无需使用 save
信号来更新 percentage_pledged
字段?如果我能够以某种方式预取该数据(即一次性获取所有Pledges
,然后循环访问它们),那就太好了。
我不确定解决方案会是什么样子(例如,那一组Pledges
会放在哪里?),但我确信这是一个常见问题(也是一个困扰我的问题)之前),所以我想看看那些对 Django 更有经验的人是如何解决这个问题的。也许save
信号就是它所属的地方,特别是对于“低写入,高读取”类型的站点。
I've got models like this:
class PledgeItem(models.Model):
title = models.CharField(...)
usd_amount = models.DecimalField(...)
class Pledger(models.Model):
name = models.CharField(...)
...
class Pledge(models.Model):
pledger = models.ForeignKey(Pledger)
item = models.ForeignKey(PledgeItem)
usd_amount = models.DecimalField(...)
...
My PledgeItem
has a method to work out what percentage of it is pledged (e.g. an item might cost $100, and have 3 pledges of $20 each, meaning it is 60% pledged):
class PledgeItem(models.Model):
...
def percentage_pledged(self):
pledge_total = Pledge.objects.filter(item = self).sum(usd_amount)
return (pledge_total / self.usd_amount) * 100
For the purposes of this question, please assume I properly handle self.usd_amount
being zero, and the case where there are no Pledges
on the PledgeItem
(though I've got to ask, why does sum(field)
return None
in those cases?).
Problem is, if I call percentage_pledged
in a list of n
PledgeItems
, I have one query per PledgeItem
. Is there an elegant way to resolve this without using save
signals to update a percentage_pledged
field? It'd be nice if I could prefetch that data somehow (i.e. fetch all Pledges
in one go, and then loop through them).
I'm not sure what a solution would even look like (for example, where would that set of Pledges
live?), but I'm sure this is a common issue (and one that has bugged me before), so I thought I'd see how people more experienced with Django have solved it. Maybe save
signals are where this belongs, particularly for "low-write, high-read" type sites.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是 Django 1.1 中新聚合功能的工作。
您想要为查询集中的每个 PledgeItem“注释”pledge_sum 字段。这很容易做到:
显然你可以用你想要的任何过滤器替换
all()
。您仍然需要对每个 PledgeItem 进行百分比计算,但不会导致任何额外的查询。
This is job for the new aggregation features in Django 1.1.
You want to 'annotate' a pledge_sum field to every PledgeItem in a queryset. This is easily done:
Obviously you can replace
all()
with whatever filters you want.You'll still need to do the percentage calculation on each PledgeItem, but it won't result in any extra queries.