#python #mysql #django #datetime
#python #mysql #django #дата и время
Вопрос:
Я некоторое время занимался отладкой, но не могу получить правильный результат. В моем приложении django я расширил auth_user для добавления дополнительных полей:
from django.contrib.auth.models import User
class Person(User):
api_id = models.CharField(max_length=255)
api_key = models.CharField(max_length=255)
Теперь я хочу подсчитать пользователей по годам и месяцам в соответствии с датой, когда они присоединились:
Person.objects.annotate(year=TruncYear("date_joined"), month=TruncMonth("date_joined")).values("year", "month").annotate(count=Count("pk"))
Однако все, что я получаю, это count = 1 для каждого пользователя в базе данных без группировки их по годам и месяцам.
Это фактический выполняемый запрос:
SELECT CAST(DATE_FORMAT(CONVERT_TZ(`auth_user`.`date_joined`, 'UTC', 'Europe/Madrid'), '%Y-01-01 00:00:00') AS DATETIME) AS `year`, CAST(DATE_FORMAT(CONVERT_TZ(`auth_user`.`date_joined`, 'UTC', 'Europe/Madrid'), '%Y-%m-01 00:00:00') AS DATETIME) AS `month`, COUNT(`mt_api_app_person`.`user_ptr_id`) AS `count` FROM `mt_api_app_person` INNER JOIN `auth_user` ON (`mt_api_app_person`.`user_ptr_id` = `auth_user`.`id`) GROUP BY CAST(DATE_FORMAT(CONVERT_TZ(`auth_user`.`date_joined`, 'UTC', 'Europe/Madrid'), '%Y-01-01 00:00:00') AS DATETIME), CAST(DATE_FORMAT(CONVERT_TZ(`auth_user`.`date_joined`, 'UTC', 'Europe/Madrid'), '%Y-%m-01 00:00:00') AS DATETIME), `auth_user`.`date_joined` ORDER BY `auth_user`.`date_joined` DESC
Кажется, что все count = 1 происходит из GROUP BY [...] 'auth_user'.'date_joined'
-за того, что группирует записи по целому datetime, а не только по месяцу и году.
Есть какие-либо подсказки о том, что здесь происходит? Если я выполняю тот же запрос, но с пользователем, я получаю то, что хочу.
SELECT CAST(DATE_FORMAT(CONVERT_TZ(`auth_user`.`date_joined`, 'UTC', 'Europe/Madrid'), '%Y-%m-01 00:00:00') AS DATETIME) AS `month`, COUNT(`auth_user`.`id`) AS `count` FROM `auth_user` GROUP BY CAST(DATE_FORMAT(CONVERT_TZ(`auth_user`.`date_joined`, 'UTC', 'Europe/Madrid'), '%Y-%m-01 00:00:00') AS DATETIME) ORDER BY NULL
Ответ №1:
Используйте TruncMonth и TruncYear
from django.db.models import Count
from django.db.models.functions import TruncMonth, TruncYear
Person.objects.annotate(month=TruncMonth('date_joined')).values('month').annotate(total=Count('pk'))
Person.objects.annotate(year=TruncYear('date_joined')).values('year').annotate(total=Count('pk'))
Комментарии:
1. Это не работает. Он возвращает count = 1 для каждого пользователя вместо группировки по месяцам и годам и возвращает количество, например, count = 251
Ответ №2:
Похоже, в вашем запросе опечатка. Вы используете TruncYear
для месяца и года, поэтому вы получаете только одно значение, и это за год.
За месяц:
Person.objects.annotate(month=TruncMonth("date_joined")).values("month").annotate(count=Count("pk"))
За год:
Person.objects.annotate(year=TruncYear("date_joined")).values("year").annotate(count=Count("pk"))
Комментарии:
1. Вы правы, я допустил опечатку при копировании сюда запроса. Но я сделал это правильно на Django. Я исправил свой вопрос. Спасибо
Ответ №3:
Я столкнулся с той же проблемой, но тот же запрос в другой модели работал просто отлично. Наконец-то выяснил, что эта проблема вызвана тем, что моя модель (в вашем случае Person
модель) имеет набор order_by по умолчанию. Если вы очистите порядок по запросу, он должен работать так, как ожидалось.
Person.objects.annotate(year=TruncYear('date_joined')).values('year').annotate(total=Count('pk')).order_by()