Django TruncDate дает ноль - PullRequest
       4

Django TruncDate дает ноль

0 голосов
/ 23 марта 2020

Я использую Django 2.2

Я фильтрую записи, используя Django запрос, подобный

from datetime import datetime
from django.db.models.functions import TruncDate

start_date = datetime.strptime('2020-02-01', '%Y-%m-%d').date()
end_date = datetime.strptime('2020-03-31', '%Y-%m-%d').date()

lead_list = LeadList.objects.all()

# Filter query
query = LeadListEntry.objects.filter(
    lead_list__in=lead_list
  )

# Filter by start date
query = query.filter(
    created__gte=start_date
  )

# Filter by end date
query = query.filter(
    created__lte=end_date
  )

# Annotate date
query = query.annotate(
     created_date=TruncDate('created')
   ).order_by(
     'created_date'
   ).values('created_date').annotate(
     **{'total': Count('created')}
   )

Сгенерированный запрос SQL

SELECT 
    DATE(CONVERT_TZ(`lead_generation_leadlistentry`.`created`, 'UTC', 'UTC')) AS `created_date`, 
    COUNT(`lead_generation_leadlistentry`.`created`) AS `total`
FROM `lead_generation_leadlistentry` 
WHERE (
    `lead_generation_leadlistentry`.`lead_list_id` IN (
        SELECT 
            U0.`id` FROM `lead_generation_leadlist` U0 
        WHERE 
            U0.`deleted` IS NULL
    )
    AND `lead_generation_leadlistentry`.`created` >= '2020-02-01 00:00:00' 
    AND `lead_generation_leadlistentry`.`created` <= '2020-03-31 00:00:00'
)
GROUP BY DATE(CONVERT_TZ(`lead_generation_leadlistentry`.`created`, 'UTC', 'UTC'))
ORDER BY `created_date` ASC

Это ведет себя по-разному на локальном и промежуточном сервере

Локальный сервер разработки

+--------------+-------+
| created_date | total |
| ------------ | ----- |
| 2020-02-25   | 15    |
| 2020-02-27   | 10    |
+--------------+-------+

промежуточный сервер

+--------------+-------+
| created_date | total |
| ------------ | ----- |
| null         | 15    |
+--------------+-------+

Столбец даты null

ПРИМЕЧАНИЕ : Django имеет часовой пояс с включенным USE_TZ=True

LeadListEntry модель

class LeadListEntry(models.Model):
    lead_list = models.ForeignKey(LeadList, on_delete=models.CASCADE, related_name='lead_list_entry')
    data = models.TextField(help_text='Lead List entry data. (JSON data)', blank=False)

    created = models.DateTimeField(auto_now_add=True)
    modified = models.DateTimeField(auto_now=True)

Ответы [ 2 ]

0 голосов
/ 25 марта 2020

Вот решение для пользователей, получающих ту же ошибку

Ошибка была не с Django, а с MySQL настройка базы данных.

Поле даты возвращает null, поскольку CONVERT_TZ не работает. Это может быть связано с отсутствием данных о часовом поясе в базе данных MySQL.

Чтобы импортировать данные о часовом поясе, выполните следующую команду

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql

После импорта перезапустите сервер mysql.

0 голосов
/ 25 марта 2020

Проблема разных результатов от локального до промежуточного может возникать из-за разного DateTime компьютера, я получил это раньше, когда разрабатывал на windows, но промежуточный этап был ubuntu, оказалось, что strptime() параметры даты были другими и продолжал показывать ошибки.

Для фильтрации даты и в качестве примера кода вам не нужно создавать объект даты, достаточно будет использовать правильный формат даты строки

start_date = '2020-02-01'
end_date = '2020-03-31'

Тогда go как обычно.

Я хотел бы сделать что-то вроде этого,

# As you only need LeadList id's for foreginkey filtering, this is more optimized
lead_list = LeadList.objects.all().values_list('id')

# Filter query
query = LeadListEntry.objects.filter(
    lead_list__in=lead_list, created__date__gte = start_date, created__date__lte=end_date
  )

и сгруппировать по дате

query = query.values('created__date').annotate(count=Count('created__date')).order_by('created__date')
...