Фильтр Django ORM по datetime понимает записи со смещением 'Z', но не со смещением '+0000'

У меня есть база данных MySQL, которая отражает базу данных salesforce. В моей таблице есть столбец «createddate», который содержит записи в формате ISO-8601 datetime. Некоторые записи имеют смещение «Z», а некоторые - смещение «+0000», например:

<

<

<

<

<

Когда я пытаюсь отфильтровать по определенной дате, фильтр возвращает ТОЛЬКО строки, имеющие смещение «Z». Строки с «+0000» не возвращаются.

Мой код фильтра выглядит следующим образом:

receipts = Receipt.objects.filter(createddate__date='2025-01-20').count()

Насколько я могу судить, оба формата соответствуют стандарту ISO-8601.

У меня в файле settings.py

установлено значение USE_TZ равное true.

Поле настраивается в models.py следующим образом:

createddate = models.CharField(db_column='CreatedDate', max_length=28, blank=True, null=True)

Относительно недавно я познакомился с django и его ORM, в настоящее время я работаю с необработанными SQL-запросами, но я бы предпочел сделать это нативно, если это возможно.

Если это не критически важно и вам нужно, чтобы все было вообще правильно, попробуйте следующее:

receipts = Receipt.objects.filter(createddate__contains='2025-01-20').count()

Это должно сработать, так как db возвращает какой-то элемент типа string/VARCHAR.

Это не учитывает смещения часовых поясов, поэтому будет содержать только объекты, созданные в указанную дату по времени UTC.

Лучшим методом будет определение QuerySet для включения некоторой логики разбора, например, использование strptime для преобразования объектов в объекты python datetime, а затем применение вашей логики к ним.

Вы можете преобразовать строковые объекты в реальные даты с помощью функции django ORM Cast. Я бы сделал что-то вроде этого.

import datetime
from django.db.models import functions

from_date = datetime.datetime.now().date() - datetime.timedelta(days=1)
to_date = datetime.datetime.now().date()

queryset = (
    Receipt.objects
    .alias(
        created_at=functions.Cast(
            expression='createddate',
            #  Or models.DateField().
            output_field=models.DateTimeField(),
        )
    )
    .filter(
        #  When converting to `models.DateField()`, remove `__date` lookup.
        created_at__date__lte=from_date,
        created_at__date__gte=to_date,
    )
)

Или с помощью range поиска:

queryset = (
    Receipt.objects
    .alias(
        created_at=functions.Cast(
            expression='createddate',
            output_field=models.DateTimeField(),
        )
    )
    .filter(
        created_at__date__range=(
            datetime.datetime.from_date,
            datetime.datetime.to_date,
        ),
    )
)

Или вы можете использовать только определенные фильтры: только gt, или только lte, и так далее. Тогда просто вызовите queryset.count(). Вы также можете прочитать этот раздел в документации.

Вернуться на верх