Как я могу отфильтровать дату DateTimeField в Django?


173

Я пытаюсь отфильтровать DateTimeFieldсравнение с датой. Я имею в виду:

MyObject.objects.filter(datetime_attr=datetime.date(2009,8,22))

Я получаю пустой список наборов запросов в качестве ответа, потому что (я думаю) я не рассматриваю время, но хочу "в любое время".

Есть ли в Django простой способ сделать это?

У меня установлено время в datetime, это не так 00:00.


5
Это одна из неприятностей Джанго. Учитывая, что это простой и распространенный вариант использования, простого способа добиться этого не существует.
Рубает

Ответы:


114

Такие поиски реализованы django.views.generic.date_basedследующим образом:

{'date_time_field__range': (datetime.datetime.combine(date, datetime.time.min),
                            datetime.datetime.combine(date, datetime.time.max))} 

Поскольку это довольно многословно, есть планы улучшить синтаксис с использованием __dateоператора. Проверьте " # 9596 Сравнение DateTimeField с датой слишком сложно " для более подробной информации.


4
Использование с диапазоном: Q(created__gte=datetime.combine(created_value, time.min))
Динго

10
Похоже, он приземлится в Джанго 1.9: github.com/django/django/commit/…
amjoconn

14
Новое в Django 1.9:Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Non

102
YourModel.objects.filter(datetime_published__year='2008', 
                         datetime_published__month='03', 
                         datetime_published__day='27')

// редактировать после комментариев

YourModel.objects.filter(datetime_published=datetime(2008, 03, 27))

Doest не работает, потому что он создает объект datetime со значениями времени, установленными в 0, поэтому время в базе данных не совпадает.


спасибо за ответ! Первый вариант не работает с полями datetime. Вторая альтернатива работает;). Если кто-то знает другой метод, пожалуйста, ответьте
Xidobix

docs.python.org/library/datetime.html#datetime-objects с использованием datetime () из модуля datetime hrs, mins, secs не является обязательным. вторая из рабочего проекта с заменой vars, вы можете посмотреть в документах, что это правильно
zalew

я знаю, что это необязательно, проблема в том, что в моем поле datetime установлено время, а не 00:00
Xidobix

«Первый вариант не работает с полями datetime». было бы весьма удивительно, так как datetime.datetime () возвращает объект DateTime djangoproject.com/documentation/0.96/models/basic проверить определение модели и примеры: pub_date = models.DateTimeField () pub_date = дата - время (2005, 7, 30)
Залев

«Я знаю, что это необязательно, проблема в том, что в моем поле datetime установлено время, а не 00:00». О, теперь я понял. Да, без временных аргументов он устанавливает 00, поэтому он не возвращается :)
zalew

88

Вот результаты, которые я получил с помощью функции timeit ipython:

from datetime import date
today = date.today()

timeit[Model.objects.filter(date_created__year=today.year, date_created__month=today.month, date_created__day=today.day)]
1000 loops, best of 3: 652 us per loop

timeit[Model.objects.filter(date_created__gte=today)]
1000 loops, best of 3: 631 us per loop

timeit[Model.objects.filter(date_created__startswith=today)]
1000 loops, best of 3: 541 us per loop

timeit[Model.objects.filter(date_created__contains=today)]
1000 loops, best of 3: 536 us per loop

Содержится, кажется, быстрее.


Это решение кажется самым последним. Я удивлен, что он получил 4 отзыва, потому что, когда я пробую containsрешение, я получаю сообщение об ошибке:Unable to get repr for <class 'django.db.models.query.QuerySet'>
Houman

Я проверяю и обновляю результаты сегодня, и я не думаю, что ваша ошибка вызвана __containsфильтром. Но если вы работаете с проблемами , вы должны попробовать пример Джанго DOCS , который использует __gte.
Морено

4
Метод __contains отлично работает для меня. Я думаю, что это, вероятно, лучший ответ, поскольку он обеспечивает сравнение производительности. Я проголосовал больше, чем один, но я удивлен, что у него больше нет голосов.
RobotHumans

Я люблю startswithрешение ..
w411 3

46

Теперь у Django есть фильтр наборов запросов __date для запроса объектов datetime к датам в версии разработки. Таким образом, он будет доступен в 1.9 в ближайшее время.


Да, это было добавлено в 1.9 docs.djangoproject.com/en/1.9/ref/models/querysets/#date
guival

Лучший ответ, действительный для новых версий Django
serfer2

Это не работает для меня, не знаю почему :( Я нахожусь на django 1.11. Мое исключение: NotImplementedError: для подклассов basedatabaseoperations может потребоваться метод datetime_cast_date ()
AbdurRehman Khan

44
Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))

выше то, что я использовал. Он не только работает, но и имеет некоторую внутреннюю логическую поддержку.


3
Гораздо лучше, чем все остальные ответы здесь, спасибо!
Кин

SSSSS-Shazam! D
дпс

30

Начиная с Django 1.9, способ сделать это - использовать __dateобъект datetime.

Например: MyObject.objects.filter(datetime_attr__date=datetime.date(2009,8,22))


27

Это дает те же результаты, что и при использовании __year, __month и __day, и, похоже, работает для меня:

YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))

19
Похоже, что это превращает объект даты в строку и выполняет сравнение строк с датами, поэтому вынуждает db выполнять полное сканирование таблицы. для больших столов это убивает вашу производительность
yilmazhuseyin

8

предполагая, что active_on является объектом даты, увеличьте его на 1 день, затем сделайте диапазон

next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )

2

Вот интересная техника - я использовал процедуру стартов с помощью Django на MySQL, чтобы добиться результата только поиска даты и времени только по дате. По сути, когда Django выполняет поиск в базе данных, он должен выполнить преобразование строк для объекта хранения DATETIME MySQL, так что вы можете отфильтровать его, оставив часть даты с отметкой времени - таким образом,% LIKE% соответствует только дате объект, и вы получите каждую отметку времени на указанную дату.

datetime_filter = datetime(2009, 8, 22) 
MyObject.objects.filter(datetime_attr__startswith=datetime_filter.date())

Это выполнит следующий запрос:

SELECT (values) FROM myapp_my_object \ 
WHERE myapp_my_object.datetime_attr LIKE BINARY 2009-08-22%

LIKE BINARY в этом случае будет соответствовать всему для даты, независимо от отметки времени. Включая такие значения, как:

+---------------------+
| datetime_attr       |
+---------------------+
| 2009-08-22 11:05:08 |
+---------------------+

Надеюсь, это поможет всем, пока Джанго не выйдет с решением!


Итак, похоже, это тот же ответ, что и у mhost и kettlehell выше, но с большим описанием того, что происходит в бэкэнде. По крайней мере, у вас есть причина для использования содержит или запускается вместе с атрибутом date () даты и времени!
bbengfort

2

Вот фантастический пост, который освещает это здесь: сравнение дат и времени в Django ORM

Лучшее решение для Django> 1.7, <1.9 - зарегистрировать преобразование:

from django.db import models

class MySQLDatetimeDate(models.Transform):
    """
    This implements a custom SQL lookup when using `__date` with datetimes.
    To enable filtering on datetimes that fall on a given date, import
    this transform and register it with the DateTimeField.
    """
    lookup_name = 'date'

    def as_sql(self, compiler, connection):
        lhs, params = compiler.compile(self.lhs)
        return 'DATE({})'.format(lhs), params

    @property
    def output_field(self):
        return models.DateField()

Затем вы можете использовать его в своих фильтрах следующим образом:

Foo.objects.filter(created_on__date=date)

РЕДАКТИРОВАТЬ

Это решение определенно зависит от сервера. Из статьи:

Конечно, эта реализация зависит от вашего специфического вида SQL, имеющего функцию DATE (). MySQL делает. Как и SQLite. С другой стороны, я лично не работал с PostgreSQL, но некоторые поиски в Google заставляют меня поверить, что в нем нет функции DATE (). Таким образом, такая простая реализация кажется, что она обязательно будет зависеть от серверной части.


это специфично для MySQL? интересно о выборе имени класса.
Биной ​​Дэвид

@BinojDavid Да, это зависит от сервера
Дэн Гейл

Я протестировал его с использованием Django 1.8 и PostgreSQL 9.6.6, и он отлично работает. На самом деле, используя PostgreSQL, вы также можете использовать этот синтаксис:return '{}::date'.format(lhs), params
michal-michalak

1

Хм .. Мое решение работает:

Mymodel.objects.filter(date_time_field__startswith=datetime.datetime(1986, 7, 28))


0

В Django 1.7.6 работает:

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))

2
Это работает, только если вы ищете точную дату, вы не можете использовать, __lteнапример.
Гиваль

-1

Смотрите статью Django Документация

ur_data_model.objects.filter(ur_date_field__gte=datetime(2009, 8, 22), ur_date_field__lt=datetime(2009, 8, 23))

5
в документации django это работает, потому что у datetimefiled есть время 00:00
Xidobix
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.