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

123

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

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

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

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

У меня есть время в заданном времени, это не 00:00.

  • 4
    Это одна из неприятностей Джанго. Учитывая, что это простой и распространенный вариант использования, простого способа добиться этого не существует.
Теги:
datetime
filter
django-queryset

14 ответов

95

Такие поисковые запросы реализованы в 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
    Похоже, он попадет в Django 1.9: github.com/django/django/commit/…
Показать ещё 2 комментария
81
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, поэтому время в базе данных не совпадает.

  • 0
    Это правильный путь. Документация Django ссылка?
  • 0
    спасибо за ответ! Первый вариант не работает с полями datetime. Вторая альтернатива работает;). Если кто-то знает другой метод, пожалуйста, ответьте
Показать ещё 6 комментариев
65

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

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

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

  • 0
    Это решение кажется самым последним. Я удивлен , что получил 4 upvotes, потому что , когда я пытаюсь contains решение, я получаю сообщение об ошибке: Unable to get repr for <class 'django.db.models.query.QuerySet'>
  • 0
    Я проверяю и обновляю результаты сегодня и не думаю, что ваша ошибка вызвана фильтром __contains . Но если у вас __gte проблемы, вы должны попробовать пример django docs , использующий __gte .
Показать ещё 1 комментарий
28
Mymodel.objects.filter(date_time_field__contains=datetime.date(1986, 7, 28))

это то, что я использовал. Он не только работает, но и обладает некоторой логической поддержкой.

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

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

YourModel.objects.filter(your_datetime_field__startswith=datetime.date(2009,8,22))
  • 19
    Похоже, что это превращает объект даты в строку и выполняет сравнение строк с датами, поэтому вынуждает db выполнять полное сканирование таблицы. для больших столов это убивает вашу производительность
19

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

15

Как и в Django 1.9, способ сделать это - __date в объекте datetime.

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

7

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

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

Вот интересный метод. Я использовал процедуру startswith, реализованную с 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 |
+---------------------+

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

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

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

MyObject.objects.filter(datetime_attr__startswith=datetime.date(2009,8,22))
  • 2
    Это работает, только если вы ищете точную дату, вы не можете использовать __lte например.
1

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

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

Здесь есть фантастический блогпост: Сравнение дат и времени в ORM Django

Лучшее решение для 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 лично, но некоторый googling заставляет меня думать, что у него нет функции DATE(). Таким образом, реализация, эта простая, кажется, будет иметь определенную зависимость от бэкэнда.

  • 0
    это специфично для MySQL? интересно о выборе имени класса.
  • 0
    @BinojDavid Да, это зависит от сервера
Показать ещё 1 комментарий
0
Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30)
0

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

Его очень похоже на ответ JZ

ur_data_model.objects.filter(ur_date_field=datetime(2005, 7, 27)
  • 4
    в документации django это работает, потому что у datetimefiled есть время 00:00

Ещё вопросы

Сообщество Overcoder
Наверх
Меню