代码之家  ›  专栏  ›  技术社区  ›  Dominic Rodger

使用django避免O(N)查询

  •  0
  • Dominic Rodger  · 技术社区  · 15 年前

    我有这样的模型:

    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 是零,如果没有 Pledges 质押物 (尽管我不得不问,为什么 sum(field) 返回 None 在这些情况下?).

    问题是,如果我打电话 percentage_pledged 在一览表中 n PledgeItems ,我有一个查询每个 质押物 . 有没有优雅的方法不用 save 更新A的信号 质押百分比 字段?如果我能以某种方式预取数据(即获取所有数据),那就太好了 誓言 一次完成,然后循环通过它们)。

    我不确定一个解决方案会是什么样子(例如,在哪里 誓言 生活?)但是我相信这是一个常见的问题(也是一个以前困扰我的问题),所以我想我会看到更多有经验的人是如何解决这个问题的。也许吧 节约 信号是它所属的地方,特别是对于“低写,高读”类型的站点。

    1 回复  |  直到 15 年前
        1
  •  3
  •   Daniel Roseman    15 年前

    这是Django1.1中新聚合功能的工作。

    您需要为查询集中的每个认捐项“注释”一个认捐金额字段。这很容易做到:

    from django.db.models import Sum
    PledgeItems.objects.all().annotate(pledge_sum=Sum(pledge__usdamount))
    

    很明显你可以替换 all() 用任何你想要的过滤器。

    您仍然需要对每个认捐项进行百分比计算,但不会导致任何额外的查询。