Django, фильтр по указанному месяцу и году в диапазоне дат - программирование
Подтвердить что ты не робот

Django, фильтр по указанному месяцу и году в диапазоне дат

У меня есть следующие модели

class Destination_Deal(models.Model):
    name = models.CharField(_("Nombre"),max_length=200)

class Departure_Date(models.Model):
    date_from= models.DateField(_('Desde'))    
    date_to= models.DateField(_('Hasta'))
    destination_deal = models.ForeignKey(Destination_Deal,verbose_name = _("Oferta de Destino"))

Это фактические данные в таблице departure_date

id  date_from   date_to     destination_deal_id
1   2012-11-01  2013-03-17  1
2   2012-11-01  2012-12-16  2
3   2012-09-16  2012-10-31  3
4   2012-11-01  2012-12-16  3
5   2013-01-04  2013-01-11  4

Я хотел бы отфильтровать Destination_Deals, если указанный месяц и год находится между date_from и date_to.

Пример 1

Месяц: Сентябрь (09)
Год: 2012

Требуемые даты вылета:
ID 3: Это единственный диапазон данных, который касается 09/2012

Пример 2

Месяц: Февраль (02)
Год: 2013

Требуемые даты вылета:
ID 1: 02/2012 до 03/2012

Итак, день на самом деле не имеет значения. Если месяц и год между date_from и date_to, даже если он на один день, он должен быть фильтром.

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

Спасибо заранее! Miguel

--- Edit ---
Это тест для ответа от Aamir Adnan, но он не работает так, как я ожидал, поскольку идентификатор 1 также должен быть возвращен, поскольку он идет с ноября 2012 года по март 2013 года, поэтому январь 2013 года находится между ними.

Departure_Date.objects.all()
[<Departure_Date: id: 1 - from: 2012-11-01 - to: 2013-03-17>,
<Departure_Date: id: 2 - from: 2012-11-01 - to: 2012-12-16>,
<Departure_Date: id: 3 - from: 2012-09-16 - to: 2012-10-31>,
<Departure_Date: id: 4 - from: 2012-11-01 - to: 2012-12-16>,
<Departure_Date: id: 5 - from: 2013-01-04 - to: 2013-01-11>]


month:1
year:2013
where = '%(year)s >= YEAR(date_from) AND %(month)s >= MONTH(date_from) \
    AND %(year)s <= YEAR(date_to) AND %(month)s <= MONTH(date_to)' % \
    {'year': year, 'month': month}
Departure_Date.objects.extra(where=[where])
[<Departure_Date: id: 5 - from: 2013-01-04 - to: 2013-01-11>]
4b9b3361

Ответ 1

Проверьте документацию

year = 2012
month = 09
Departure_Date.objects.filter(date_from__year__gte=year,
                              date_from__month__gte=month,
                              date_to__year__lte=year,
                              date_to__month__lte=month)

Альтернативный метод с использованием .extra:

where = '%(year)s >= YEAR(date_from) AND %(month)s >= MONTH(date_from) \
        AND %(year)s <= YEAR(date_to) AND %(month)s <= MONTH(date_to)' % \
        {'year': year, 'month': month}
Departure_Date.objects.extra(where=[where])

Существует конкретный случай, когда указанный выше запрос не дает желаемого результата.

Например:

date_from='2012-11-01'
date_to='2013-03-17'
and input is
year=2013
month=1

Тогда условие %(month)s >= MONTH(date_from) неверно, поскольку месяц 1 равен < месяц 11 в date_from, но год отличается, поэтому здесь требуется условие MySQL IF:

where = '%(year)s >= YEAR(date_from) AND IF(%(year)s > YEAR(date_from), \
     IF(%(month)s > MONTH(date_from), %(month)s >= MONTH(date_from), %(month)s < MONTH(date_from)), \
     IF(%(month)s < MONTH(date_from), %(month)s < MONTH(date_from), %(month)s >= MONTH(date_from))) \
     AND %(year)s <= YEAR(date_to) \
     AND %(month)s <= MONTH(date_to)' % \
     {'year': year, 'month': month}
Departure_Date.objects.extra(where=[where])

Ответ 2

Решение, использующее только код Python. Основная идея - построить date_from и date_to с помощью python. Затем эти даты можно использовать в filter с __lte и __gte:

import calendar
from datetime import datetime
from django.db.models import Q

def in_month_year(month, year):
    d_fmt = "{0:>02}.{1:>02}.{2}"
    date_from = datetime.strptime(
        d_fmt.format(1, month, year), '%d.%m.%Y').date()
    last_day_of_month = calendar.monthrange(year, month)[1]
    date_to = datetime.strptime(
        d_fmt.format(last_day_of_month, month, year), '%d.%m.%Y').date()
    return Departure_Date.objects.filter(
        Q(date_from__gte=date_from, date_from__lte=date_to)
         |
        Q(date_from__lt=date_from, date_to__gte=date_from))

Теперь это будет работать:

>>> Departure_Date.objects.all()
[<Departure_Date: id: 1 - from: 2012-11-01 - to: 2013-03-17>,
<Departure_Date: id: 2 - from: 2012-11-01 - to: 2012-12-16>,
<Departure_Date: id: 3 - from: 2012-09-16 - to: 2012-10-31>,
<Departure_Date: id: 4 - from: 2012-11-01 - to: 2012-12-16>,
<Departure_Date: id: 5 - from: 2013-01-04 - to: 2013-01-11>]


>>> in_month_year(month=1, year=2013)
[<Departure_Date: id: 1 - from: 2012-11-01 - to: 2013-03-17>,
<Departure_Date: id: 5 - from: 2013-01-04 - to: 2013-01-11>]

Ответ 3

Вы можете обойти "несоответствие импеданса", вызванное отсутствием точности в сравнении с объектом DateTimeField/date, которое может возникнуть при использовании диапазона - с использованием datetime. timedelta​​strong > , чтобы добавить день к последней дате в диапазоне. Это работает как:

import datetime

start = date(2012, 12, 11)
end = date(2012, 12, 18)
new_end = end + datetime.timedelta(days=1)

ExampleModel.objects.filter(some_datetime_field__range=[start, new_end])