增量计数和计算在Django模型(incremental count and calculation

2019-10-19 01:34发布

比方说,我的模型是这样的:

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()}

我是新来的这一切,所以我觉得这是非常令人费解。 有没有更简单的方法??!

(二)如果可以做到这一点的数据库(例如带有某种模型属性的),这是不是作为数据库中获取大量的蟒蛇做更有效?

非常感谢

Answer 1:

对于纯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',
    }
)

请读了extra() Django的查询集的方法和count() over()的SQL。 因为数据库扫描3次,但它是一个开始,我想这是效率太低。



Answer 2:

其实,我结束了使用的出版商模型的模型方法; 如果有一个更好的办法,请让我知道!

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


文章来源: incremental count and calculation in django model