Как отфильтровать поле даты и времени по дате? - PullRequest
1 голос
/ 15 мая 2019

У меня есть модель:

class Account(models.Model):
    contract_date = models.DateTimeField()

Поле contract_date хранится в дБ в часовом поясе UTC. Мне нужно выбрать все аккаунты, где contract_date__date == дата. Но дата хранится в часовом поясе MSK (+3). Например:

Account.objects.create(contract_date='2010-01-01 21:00:00')
Account.objects.filter(contract_date__date=date(2010, 1, 2)).all()

Запрос возвращает пустой список.

Ответы [ 2 ]

1 голос
/ 15 мая 2019

Если вы включили часовые пояса (USE_TZ = True в ваших настройках), тогда django позаботится о том, чтобы все даты были сохранены в часовом поясе UTC и получены в часовом поясе UTC.

При отображении они будут использовать текущий часовой пояс (settings.TIME_ZONE или другой, если вы его активируете), чтобы отобразить их в соответствующем часовом поясе. При получении ввода из форм он преобразует их в UTC.

Также обратите внимание, что date (2019-01-02) не может быть привязан к часовому поясу, только datetime, поскольку без времени часовые пояса не имеют смысла.

Так что в вашем случае вам нужно сообщить Django, что вы хотите фильтровать по дате в часовом поясе MKS. Вы можете использовать Trunc для этого:

from django.db.models.functions import Trunc
from django.db.models import DateTimeField
import pytz
from datetime import datetime

mks_filter_day = pytz.timezone("Europe/Moscow").localize(datetime(2010, 1, 2))
Account.objects.exclude(contract_date__isnull=True).annotate(
    mks_day=Trunc('contract_date', 'day', output_field=DateTimeField(), tzinfo=pytz.timezone("Europe/Moscow")))\
    .filter(mks_day=mks_filter_day)
# or in Django 1.11 the above doesn't work due to a bug
Account.objects.exclude(contract_date__isnull=True).annotate(
    mks_day=Trunc('contract_date', 'day', output_field=DateTimeField(), tzinfo=pytz.timezone("Europe/Moscow")))\
    .filter(mks_day__contains=datetime.date(2010, 1, 2))

Указывает базе данных преобразовать дату и время в MKS и усекает день перед сравнением с контрольной датой. Я уверен, что contract_date не равно нулю, иначе вы получите ошибку.

0 голосов
/ 15 мая 2019

Вы запрашиваете использование даты без времени ... вместо нее используйте datetime:

datetime(2010,1,2,21,0,0)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...