2009-08-23 6 views
134

Я пытаюсь отфильтровать DateTimeField по сравнению с датой. Я имею в виду:Как я могу отфильтровать дату DateTimeField в Django?

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

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

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

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

+4

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

ответ

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)) 

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

+0

Это правильный путь. Документация Django ref? – hughdbrown

+0

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

+0

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

0

Смотрите статью Django Documentation

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

ur_data_model.objects.filter(ur_date_field=datetime(2005, 7, 27) 
+4

в документации Джанго это работает, потому что datetimefiled имеет время 00:00 – Xidobix

0
Model.objects.filter(datetime__year=2011, datetime__month=2, datetime__day=30) 
100

Такие поиски осуществляются в 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 Comparing a DateTimeField to a date is too hard» для получения более подробной информации.

+3

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

+9

Похоже, приземлится в Django 1.9: HTTPS : //github.com/django/django/commit/44f3ee77166bd5c0e8a4604f2d96015268dce100#diff-5e313dd49d68a0a867d830a7f442d2a6R2471 – amjoconn

+3

https://docs.djangoproject.com/en/1.9/ref/models/querysets/#date –

22

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

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

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

1

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

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

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

+2

Намного лучше, чем все остальные ответы здесь, спасибо! – Kin

+0

s-s-s-s-s-s-shazam! – dps

66

Вот результаты, которые я получил с функцией 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 

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

+0

Это решение кажется самым последним. Я удивлен, что он получил 4 upvotes, потому что, когда я пытаюсь найти решение 'contains', я получаю сообщение об ошибке:' Невозможно получить представление для ' – Houman

+0

Я перепроверяю и обновляю результаты сегодня, и я не думаю, что ваша ошибка вызвана фильтром '__contains'. Но если у вас проблемы, вы должны попробовать [django docs example] (https://docs.djangoproject.com/en/dev/ref/models/querysets/#filter), который использует '__gte'. – Moreno

+3

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

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 выше, но с более подробным описанием того, что происходит в бэкэнд. По крайней мере, у вас есть причина использовать contains или startswith вместе с атрибутом date() для datetime! – bbengfort

7

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

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

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

+0

Yup, он был добавлен в 1.9 https://docs.djangoproject.com/en/1.9/ref/models/querysets/#date – guival

+0

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

0

Там фантастический Блогпост, который охватывает это здесь: Comparing Dates and Datetimes in the Django ORM

Лучшее решение вывешены для Джанго> 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) 

EDIT

Это решение, безусловно, зависит от конца. Из статьи:

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

+0

- это конкретный MySQL? задаваясь вопросом о выборе имени класса. –

+0

@BinojDavid Да, это зависит от бэкэнда –

+0

Я тестировал его с помощью Django 1.8 и PostgreSQL 9.6.6, и он отлично работает. Фактически с помощью PostgreSQL вы также можете использовать этот синтаксис: 'return '{} :: date'.format (lhs), params' – maykel

16

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

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

1

В Django 1.7.6 работы:

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

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

Смежные вопросы