django模型中的增量计数与计算

django模型中的增量计数与计算,django,django-models,django-queryset,Django,Django Models,Django Queryset,假设我的模型是这样的: 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(P

假设我的模型是这样的:

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()
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',
    }
)
对于给定的日期范围,我希望能够输出一个CSV,其中包含每个出版商的图书总数以及每个布尔字段的百分比

例如:

(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中执行更有效


非常感谢提供纯SQL解决方案,我可能会执行以下查询:

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()
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()
方法和SQL的
count()
over()
。这太低效了,因为数据库被扫描了3次,但我想这只是一个开始。

我实际上最终使用了一种模型方法作为发布者模型;如果有更好的办法,请告诉我

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