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

173

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

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

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

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

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

Xidobix
источник
5
Это одна из неприятностей Джанго. Учитывая, что это простой и распространенный вариант использования, простого способа добиться этого не существует.
Рубает
Связанный: stackoverflow.com/a/22085678/2859614
MackM

Ответы:

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, поэтому время в базе данных не совпадает.

Zalew
источник
спасибо за ответ! Первый вариант не работает с полями 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

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

Moreno
источник
Это решение кажется самым последним. Я удивлен, что он получил 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 в ближайшее время.

onurmatik
источник
Да, это было добавлено в 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))

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

kettlehell
источник
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))
mhost
источник
19
Похоже, что это превращает объект даты в строку и выполняет сравнение строк с датами, поэтому вынуждает db выполнять полное сканирование таблицы. для больших столов это убивает вашу производительность
yilmazhuseyin
8

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

next_day = active_on + datetime.timedelta(1)
queryset = queryset.filter(date_created__range=(active_on, next_day) )
davidj411
источник
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 |
+---------------------+

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

bbengfort
источник
Итак, похоже, это тот же ответ, что и у 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))
satels
источник
1
Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)
Скайлар Савленд
источник
0

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

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))
FACode
источник
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))
shahjapan
источник
5
в документации django это работает, потому что у datetimefiled есть время 00:00
Xidobix