1

This is a pretty straight-forward question:

I have two models, each with a DateField. I want to query Model-A based on the date in Model-B. I want a query that returns all the objects of Model-A that have a date within 2 years, plus or minus, of the date in one object of Model-B. How can this be done?

  • Form the range (highest and lowest wanted dates) from the date in your model B, then use date__range=['earliest_date', 'latest_date'] in a filter on your objects. – Ambroise May 08 '14 at 21:54

1 Answers1

1

Assuming you have a date value from model B, calculate two dates: one - 2 years in the past and another - 2 years in the future by the help of python-dateutil module (taken partially from here). Then, use __range notation to filter out A records by date range:

from dateutil.relativedelta import relativedelta

def yearsago(from_date, years):
    return from_date - relativedelta(years=years)


b_date = b.my_date
date_min, date_max = yearsago(b_date, 2), yearsago(b_date, -2)
data = A.objects.filter(my_date__range=(date_min, date_max))

where b is a B model instance.

Also see: Django database query: How to filter objects by date range?

Hope that helps.

Community
  • 1
  • 1
alecxe
  • 462,703
  • 120
  • 1,088
  • 1,195
  • If you're not using `dateutil` you can use `date_min = b_date.replace(year=(b_date.year-2))` - except that you'll have to think about February 29th in leap years. – Peter DeGlopper May 08 '14 at 21:57
  • @PeterDeGlopper yeah, I found `dateutil` more robust. Thanks. – alecxe May 08 '14 at 21:57
  • Personally I'd pass on installing an extra module for this simple a case if I weren't already using `dateutil` - years almost work perfectly with `replace`. But it's clearly a matter of personal preference. If you do use `replace`, also use `calendar.isleap` rather than rolling your own - it's easy to forget the leap year corner cases for centuries. – Peter DeGlopper May 08 '14 at 21:58
  • @PeterDeGlopper yeah, for example, my boss hates external dependencies. And I have a really hard time convincing him to use anything neat and awesome from third-parties :) – alecxe May 08 '14 at 22:00
  • Or come to think of it, you could just test `if b_date.month == 2 and b_date.day == 29:`. – Peter DeGlopper May 08 '14 at 22:05