聚合在带注释的& amp;分组Django ORM查询

时间:2010-04-01 08:11:47

标签: django django-models django-aggregation

我正在尝试构建查询以获取“每位用户购买的平均,最大和最小数量”。

数据源是这个简单的销售记录表:

class SalesRecord(models.Model):
    id           = models.IntegerField(primary_key=True)
    user_id      = models.IntegerField()
    product_code = models.CharField()
    price        = models.IntegerField()
    created_at   = models.DateTimeField()

对于用户购买的每件商品,都会在此表中插入新记录。 [注意]:user_id 是同一数据库中的表的外键,因为此后端系统不管理用户信息。该值由产品的前端部分提供。

这是我尝试构建查询:

q = SalesRecord.objects.all()
q = q.values('user_id').annotate(   # group by user and count the # of records
    count=Count('id'),              # (= # of items)
    ).order_by()
result = q.aggregate(Max('count'), Min('count'), Avg('count'))

当我尝试执行代码时,在最后一行引发ProgrammingError

  

(1064,“你的SQL中有错误   句法;检查手册   对应于您的MySQL服务器   用于正确语法的版本   靠近'FROM(选择   sales_recordsuser_id AS   user_id,COUNT(sales_records。`'   在第1行“)

Django的错误屏幕显示SQL是

SELECT FROM
  (SELECT
    `sales_records`.`user_id` AS `user_id`,
    COUNT(`sales_records`.`id`) AS `count`
  FROM `sales_records`
  WHERE (`sales_records`.`created_at` >= %s AND `sales_records`.`created_at` <= %s )
  GROUP BY `sales_records`.`user_id` ORDER BY NULL) subquery

它没有选择任何东西!有人可以告诉我正确的方法吗?

黑客Django

我发现清除django.db.models.sql.query.BaseQuery.get_aggregation()中所选字段的缓存似乎可以解决问题。虽然我不确定这是修复还是解决方法。

@@ -327,10 +327,13 @@
    # Remove any aggregates marked for reduction from the subquery
    # and move them to the outer AggregateQuery.
+   self._aggregate_select_cache = None
+   self.aggregate_select_mask = None
    for alias, aggregate in self.aggregate_select.items():
        if aggregate.is_summary:
            query.aggregate_select[alias] = aggregate
-           del obj.aggregate_select[alias]
+           if alias in obj.aggregate_select:
+               del obj.aggregate_select[alias]

...产生结果:

{'count__max': 267, 'count__avg': 26.2563, 'count__min': 1}

2 个答案:

答案 0 :(得分:2)

按原样使用模型(没有FK到用户),您可以获取user_id计数,然后自己进行数学运算:

counts = SalesRecord.objects.values('user_id').\
        annotate(count=Count('id')).values_list('count', flat=True)
(max(counts), min(counts), sum(counts) / float(len(counts)))

如果您能够更改表格以使用ForeignKey并使模型看起来更像这样:

class SalesRecord(model.Models):
    user = model.ForeignKey(User)
    product_code = models.CharField()
    price        = models.IntegerField()
    created_at   = models.DateTimeField()

然后,您可以从User对象处理问题并使用aggregate():

users_with_counts = Users.objects.annotate(count=Count('salesrecord'))
stats = users_with_counts.aggregate(Max('count'), Min('count'), Avg('count'))

无论哪种方式都可以通过单个数据库查询为您提供所需的信息。

答案 1 :(得分:0)

您的ORM查询确实是正确的,但该错误发生在Django 1.6中。显然它已在1.7中修复。资料来源:https://code.djangoproject.com/ticket/23669#comment:5