2013-11-25 161 views
1

比方說,我的模型是這樣的:增量計數和計算

class Publisher(models.Model):  
    name = models.CharField(max_length=30) 
    code = models.SmallIntegerField(unique=True) 

class Book(models.Model): 
    date = models.DateField(auto_now_add=True) 
    publisher = models.ForeignKey(Publisher) 
    hardback = models.BooleanField() 
    large_print = models.BooleanField() 

對於給定的日期範圍,我希望能夠輸出CSV其具有的每出版商書總數,每個布爾字段的百分比。

如:

Publisher-code Total %hardback %large_print: 

123 120 32 10 

(一)到目前爲止,我的工作與每個出版商的書籍總數生成一個查詢集

totalset = Publisher.objects.all() 
d1 = dict(totalset.annotate(total_books=Count('publisher')).values_list('code','total_books')) 

然後,視圖獲取每個布爾字段的字典轉換查詢集,例如

d2 = dict(totalset.filter(book__hardback=True).annotate(hardc=Count('book__hardback')).values_list('code','hardc')) 

然後得到了基於兩套

d3 = {k: round(float(d2[k])*100/d1[k]) for k in d1.viewkeys() & d2.viewkeys()} 

我是新來這一切的交集計算百分比一個新的字典,所以我覺得這是非常令人費解。有沒有更直接的方法??! (b)如果可以在數據庫中做到這一點(例如使用某種模型屬性),這是否比在Python中做數據庫變得更加高效?

非常感謝

回答

0

對於純SQL的解決方案,我可能會做一個查詢這樣的:

publishers = Publisher.objects.all().extra(
    select = { 
     'book_count': 'SELECT COUNT(*) FROM app_book \ 
         WHERE app_book.publisher_id = app_publisher.id', 
     'hardback_ratio': 'SELECT COUNT(*) * 100.0/SUM(COUNT(*)) OVER() \ 
          FROM app_book WHERE hardback = TRUE \ 
          AND app_book.publisher_id = app_publisher.id', 
     'largeprint_ratio': 'SELECT COUNT(*) * 100.0/SUM(COUNT(*)) OVER() \ 
          FROM app_book WHERE largeprint = TRUE \ 
          AND app_book.publisher_id = app_publisher.id', 
    } 
) 

請Django的查詢集的extra()方法和count()閱讀起來,over() SQL。這太低效了,因爲數據庫被掃描了3次,但這是我想的開始。

0

我實際上最終使用了發佈模型的模型方法;如果有更好的方法,請告訴我!

def get_percentage(self, d1, d2, choose): 
    kwargs = {'book__date__range':[d1,d2], 'book__publisher':self} 
    kwargs2 = {'book__date__range':[d1,d2], 'book__publisher':self, choose:True} 
    total_count = Publisher.objects.filter(**kwargs).count() 
    if total_count == 0: 
     #otherwise perc returns a ZeroDivisionError 
     return total_count 
    count = Publisher.objects.filter(**kwargs2).count() 
    perc = round(float(count) * 100/float(total_count)) 
    return perc