【问题标题】:incremental count and calculation in django modeldjango模型中的增量计数和计算
【发布时间】:2013-11-25 19:24:23
【问题描述】:

假设我的模型是这样的:

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 中执行此操作更有效?

非常感谢

【问题讨论】:

    标签: django django-models django-queryset


    【解决方案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',
        }
    )
    

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

    【讨论】:

      【解决方案2】:

      我实际上最终使用了 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
      

      【讨论】:

        猜你喜欢
        • 2021-12-26
        • 2012-05-07
        • 1970-01-01
        • 2020-05-19
        • 2018-10-04
        • 1970-01-01
        • 1970-01-01
        • 2017-06-24
        • 1970-01-01
        相关资源
        最近更新 更多