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

В модели «введено» поле даты и времени. Я хочу запросить данные, чтобы найти все записи, которые были сделаны между полуднем (время начала) и 17:00 (время окончания).

selected = Entry.objects.filter(entered__gte=start_time, entered__lte=end_time)

(как я и ожидал) я получаю ошибку:

"ValidationError: Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format."

Итак, я знаю, что могу использовать __год, поэтому я попробовал.

selected = Entry.objects.filter(entered__time__gte=start_time, entered__time__lte=end_time)

Я получаю ошибку:

"FieldError: Join on field 'start' not permitted. Did you misspell 'time' for the lookup type?"

Ответы [ 7 ]

5 голосов
/ 28 мая 2009

Я не верю, что есть встроенная поддержка для этого, но вы можете передать дополнительные условия where параметры (предупреждение: некоторая возможность введения DB-зависимого поведения здесь).

Например, на Postgres что-то вроде:

Entry.objects.extra(where=['EXTRACT(hour from entered) >= 12 and '\
                    'EXTRACT(hour from entered) < 17'])

Если вы используете потенциально небезопасный ввод для определения значений 12 и 17, обратите внимание, что вы также можете указать параметр params для extra, который обеспечит правильное цитирование и экранирование, а затем использовать стандартный sql %s заполнители в вашем утверждении where.

3 голосов
/ 28 мая 2009

Используя SQLite в качестве примера, относительно чистое и универсальное решение будет:

Entry.objects.extra(where=["time(entered) between '%s' and '%s'"],
                    params=[start_time.strftime("%H:%M"), end_time.strftime("%H:%M")])
2 голосов
/ 28 мая 2009

Вместо этого вы можете фильтровать в python, используя механизмы БД:

for e in Entry.objects.all():
   if i.entered.hour>= 9 and i.entered.hour < 17 :# or break down to minutes/seconds
        list.append(e)

но оба решения уродливы, я думаю.

Стив, ты должен решить, что для тебя менее уродливо:

  • обработка большого количества данных в цикле for,
  • или используйте .extra (..) и минуя систему orm
0 голосов
/ 11 марта 2016

Я только что нашел решение для подобного варианта использования - возможно, кто-то найдет это полезным:

В моем случае, у меня есть модели доступности и ограничения, например (упрощенно):

class Availability(...):
    start = models.DateTimeField()
    end = models.DateTimeField()

class Constraint(...):
    from = models.TimeField()
    to = models.TimeField()

Я хотел найти возможности, которые не нарушают никаких ограничений.

С Postgres это сработало для меня:

Availability.objects.extra(
    where=['NOT (start::time, "end"::time) OVERLAPS (\'{0}\'::time, \'{1}\'::time)'.format(
        from.strftime("%H:%M"), to.strftime("%H:%M")
    )]
)

Обратите внимание, как вы можете привести DateTime к Time (точнее timestamp к time without timezone в терминах Postgres) с ::time и затем использовать OVERLAPS для сравнения временных диапазонов.

А что касается исходного вопроса, вы также можете сделать:

Availability.objects.extra(
    where=['start::time BETWEEN \'{0}\'::time AND \'{1}\'::time AND
            "end"::time BETWEEN \'{0}\'::time AND \'{1}\'::time'.format(
        from.strftime("%H:%M"), to.strftime("%H:%M")
    )]
)
0 голосов
/ 18 февраля 2014

Вы можете использовать диапазон для фильтрации между ними. Я нашел, что это лучший способ фильтрации, так как SQL делает фильтрацию лучше, чем Django.

fromRange=datetime.datetime.strptime(request.GET.get('from'),'%Y-%m-%dT%H:%M:%S.%fZ')
toRange=datetime.datetime.strptime(request.GET.get('to'),'%Y-%m-%dT%H:%M:%S.%fZ')

entry = Entry.objects.filter(entryTime__range=(fromRange,toRange))
0 голосов
/ 15 декабря 2012

Я предлагаю фильтр x<=arg и исключаю x>=arg2.

0 голосов
/ 28 мая 2009

Предоставили ли вы объекты даты и времени для start_time и end_time?

Быстрый тест:

class Entry(models.Model):
    entered = models.DateTimeField()

>>> from datetime import datetime
>>> Entry(entered = datetime.now()).save()
>>> Entry.objects.filter(entered__lte = datetime.now())
[<Entry: Entry object>]
>>> Entry.objects.filter(entered__gte = datetime.now())
[]
>>> Entry.objects.filter(entered__gte = datetime.now(), entered__lte=datetime(2009,11,1,0,0))
[<Entry: Entry object>]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...