2009-09-29 104 views
0

我有模型是這樣的:避免爲O(n)和Django查詢

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,並且有每$ 20,3個認捐這意味着它是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的情況下我必須問,爲什麼sum(field)在這些情況下返回None?)。

問題是,如果我在nPledgeItems的列表中呼叫percentage_pledged,我有每個PledgeItem一個查詢。有沒有一種優雅的方式來解決這個問題,而不使用save信號來更新percentage_pledged字段?如果我能夠以某種方式預取數據(例如,一次獲取所有Pledges,然後遍歷它們),那就好了。

我不知道什麼解決方案甚至看起來像什麼(例如,哪一套Pledges住在哪裏?),但我確定這是一個常見問題(以前有過竊聽我的問題),所以我想我會看到人們對Django有更多的經驗已經解決了它。也許save信號是屬於哪裏的,特別是對於「低寫入,高讀取」類型的站點。

回答

3

這是Django 1.1中新聚合功能的工作。

您希望'註釋'pledge_sum字段到查詢集中的每個PledgeItem。這是很容易做到:

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

很明顯,你可以替換all()與任何你想要的過濾器。

您仍然需要對每個PledgeItem執行百分比計算,但不會導致任何額外的查詢。

+0

工程魅力,真棒! – 2009-09-29 17:11:35