3

I'm trying to obtain a list of persons whose birthday is in the next 15 days. I have this model:

class Cliente(models.Model):
    nombre                  = models.CharField(max_length=100)
    fecha_nacimiento        = models.DateField(default=datetime.date.today,blank=True,null=True)
    telefono_numero         = models.CharField(max_length=10, null=True)
    direccion               = models.CharField(max_length=100, null=True)
    otro_contacto           = models.CharField(max_length=150, null=True)

    def __unicode__(self):
        return u'%s' % self.nombre  

and my field "fecha_nacimiento" (date of birth) is a models.DateField. When I can obtain people whose birthday is in the current month by using that:

mes = date.today().month
cumplen_mes = Cliente.objects.filter(fecha_nacimiento__month=mes)

and I have a queryset with whom birthday in an specific month, but I want to see only those birthdays in the next 15 days. I tried with filters but I don't know how concatenate filters i.e.:

I can do that Cliente.objects.filter(fecha_nacimiento__day = a_day)

I read about gte & lte but can't combine with this filter over fecha_nacimiento field.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
Jaime
  • 311
  • 2
  • 12
  • 1
    [The answer on this question](http://stackoverflow.com/questions/29857236/getting-upcoming-birthdays-using-date-of-birth-datefield) might help. – Alasdair Nov 26 '15 at 16:39
  • thanks so much, this post is the solution i need! – Jaime Nov 27 '15 at 00:07

1 Answers1

4

In general, you can apply multiple filters by passing multiple keyword arguments to filter,

Cliente.objects.filter(field1='foo', field2='bar') 

or by chaining filter calls:

Cliente.objects.filter(field1='foo').filter(field2='bar') 

For your specific problem, you can calculate the date in 15 days' time.

If that date is in the current month, then the query is straight forward (note it will only work on Django 1.9+)

today = date.today()
fifteen_days = today + timedelta(days=15)
Cliente.objects.filter(
    fecha_nacimiento__month=today.month,
    fecha_nacimiento__day__gte=today.day, # we don't want birthdays that have already happened this month
    fecha_nacimiento__day__lte=fifteen_days.day,
)

If that date is next month, then it is harder. You either want dates this month, or dates next month within 15 days. In Django, you can do OR queries using Q() objects.

Cliente.objects.filter(
    Q(fecha_nacimiento__month=today.month, fecha_nacimiento__day__gte=fifteen_days.day) |
    Q(fecha_nacimiento__month=fifteen_days.month, fecha_nacimiento__day__lte=fifteen_days.day)
)

Putting it together, you have:

today = date.today()
fifteen_days = today + timedelta(days=15)
queryset = Cliente.objects.all()
if today.month == fifteen_days.month:
    queryset = queryset.filter(
        fecha_nacimiento__month=today.month,
        fecha_nacimiento__day__gte=fifteen_days.day,
        fecha_nacimiento__day__lte=fifteen_days.day,
    )
else:
    queryset = queryset.filter(
        Q(fecha_nacimiento__month=today.month, fecha_nacimiento__day__gte=fifteen_days.day) |
        Q(fecha_nacimiento__month=fifteendays.month, fecha_nacimiento__day__lte=fifteen_days.day)
    )

The queries above are untested, so there might be syntax errors or they might not be quite correct, but I think the approach will work.

nunos
  • 20,479
  • 50
  • 119
  • 154
Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • ok, but doesn't work cause today is 2015-11-26 and in 15 days will 2015-12-11 and in my DB i have 1985-11-27 stored in fecha_nacimiento, and doesn't match with the criterias in the filter. – Jaime Nov 26 '15 at 15:31
  • when i apply the first option i obtain all my clients, because all them were born before 2015-12-11, in the second option i obtain all whose birthday in november because the date of birth is less than 2015-12-11, and in the third case i obtain an empty queryset because none were born between 2015-11-26 and 2015-12-11. – Jaime Nov 26 '15 at 15:41
  • The problem is harder than I first thought, because you are storing date of birth, but searching for birthdays this year. I've updated my answer with a different approach. – Alasdair Nov 26 '15 at 15:53
  • still doesn't work, and giveme that error: FieldError: Unsupported lookup 'day' for DateField or join on the field not permitted. but when remove lte or gte, don't throw an error but doesn't work. – Jaime Nov 26 '15 at 16:22
  • 3
    Ah, I'd forgotten you can't do lookups like `day__gt` in Django 1.8. You'll be able to do it in Django 1.9. – Alasdair Nov 26 '15 at 16:38
  • well, i must upgrade my django version? – Jaime Nov 26 '15 at 23:32
  • 1
    You can either wait for Django 1.9, which should be out in December, or have a look at the [question I linked to above](http://stackoverflow.com/questions/29857236/getting-upcoming-birthdays-using-date-of-birth-datefield). – Alasdair Nov 26 '15 at 23:36
  • Thanks a lot Alasdair! – Jaime Nov 28 '15 at 01:05