Я пытаюсь создать запрос, чтобы получить «среднее, максимальное и минимальное количество предметов, приобретенных на пользователя».
Источник данных - это простая таблица записей продаж:
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
версия для правильного использования синтаксиса
рядом с (ВЫБРАТЬ
sales_records
. user_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.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}