假设我的模型是这样的:
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
等
(a)到目前为止,我正在制作一个视图,该视图会生成一个查询集,其中包含每个发布者的图书总数
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 :(得分: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 QuerySet的extra()
方法和SQL的count()
,over()
。这样效率太低,因为数据库扫描了3次,但我认为这是一个开始。
答案 1 :(得分:0)
我实际上最终使用了Publisher模型的模型方法;如果有更好的方法,请告诉我!
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