Фильтр 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()
. Вы также можете прочитать этот раздел в документации.