python - español - Django, filtre por mes y año especificado en el rango de fechas
django wikipedia (3)
Tengo los siguientes modelos
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"))
Estos son los datos reales en la tabla de partida_de_fecha
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
Me gustaría filtrar los Destination_Deals si un mes y año especificados se encuentran entre date_from y date_to.
Ejemplo 1
Mes: septiembre (09)
Año 2012
Se buscan fechas de salida resultantes:
ID 3: es el único rango de datos que toca 09/2012
Ejemplo 2
Mes: febrero (02)
Año 2013
Se buscan fechas de salida resultantes:
ID 1: 02/2012 es antes del 03/2012
Entonces, el día en realidad no importa. Si el mes y el año se encuentran entre date_from y date_to, aunque sea por un día, debe ser un filtro.
Creo que debo usar algo como this pero no estoy seguro de cómo hacerlo.
¡Gracias por adelantado! Miguel
---Editar---
Esta es la prueba para la respuesta de Aamir Adnan, pero no está funcionando como esperaba, ya que la identificación 1 también debe devolverse porque va de noviembre de 2012 a marzo de 2013, por lo que enero de 2013 está en el medio.
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>]
Consultar la documentation
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)
Método alternativo utilizando .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])
Hay un caso específico en el que la consulta anterior no produce un resultado deseado.
Por ejemplo:
date_from=''2012-11-01''
date_to=''2013-03-17''
and input is
year=2013
month=1
Entonces, la condición %(month)s >= MONTH(date_from)
es incorrecta porque el mes 1 es <mes 11 en date_from
pero el año es diferente, por lo que la condición de IF
MySQL se requiere aquí:
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])
Puede evitar la "falta de coincidencia de impedancia" causada por la falta de precisión en la comparación del objeto DateTimeField/date
(que puede ocurrir si usa el rango ) utilizando datetime.timedelta para agregar un día a la última fecha en el rango. Esto funciona como:
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])
Solución utilizando solo el código de Python. La idea principal es construir date_from y date_to con python. Entonces estas fechas se pueden usar en el filter
con __lte
y __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))
Ahora esto funcionará:
>>> 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>]