Я был недоволен всеми ответами здесь.Все они представляют собой вариант «проверять одну дату / год по одному в диапазоне ...», делая длинные, уродливые запросы.Вот простое решение, если кто-то захочет немного денормализовать:
Измените свою модель, чтобы вместо datetime birthdate(yyyy, mm, dd)
с реальной датой вы добавили столбец datetime birthday(DUMMY_YEAR, mm, dd)
.Таким образом, каждый человек в вашей базе данных сохранит свою реальную дату рождения, а затем еще одну дату рождения с фиксированным годом, которая будет сообщена всем остальным.Однако не показывайте это второе поле пользователям и не позволяйте им редактировать его.
После того, как вы отредактировали свою модель, убедитесь, что birthdate
и birthday
всегда связаны, расширяя models.Model
метод сохранения в вашем классе:
def save(self, *args, **kwargs):
self.birthday = datetime.date(BIRTHDAY_YEAR,
self.birthdate.month, self.birthdate.day)
super(YOUR_CLASS, self).save(*args, **kwargs)
И как только вы убедитесь, что при сохранении даты в качестве даты рождения, день рождения также обновляется, вы можете отфильтровать ее с помощью birthday__gte
/ birthday__lte
.См. Отрывок из моего фильтра администратора, в котором я позабочусь о границе года:
def queryset(self, request, queryset):
if self.value() == 'today':
# if we are looking for just today, it is simple
return queryset.filter(birthday = datetime.date(
BIRTHDAY_YEAR, now().month, now().day
))
if self.value() == 'week':
# However, if we are looking for next few days,
# we have to bear in mind what happens on the eve
# of a new year. So if the interval we are looking at
# is going over the new year, break the search into
# two with an OR.
future_date = (now() + datetime.timedelta(days=7)).date()
if (now().year == future_date.year):
return queryset.filter(
Q(birthday__gte = datetime.date(
BIRTHDAY_YEAR, now().month, now().day
)) &
Q(birthday__lte = datetime.date(
BIRTHDAY_YEAR,
future_date.month,
future_date.day)
)
)
else:
return queryset.filter(
# end of the old year
Q(birthday__gte = datetime.date(
BIRTHDAY_YEAR, now().month, now().day
)) &
Q(birthday__lte = datetime.date(BIRTHDAY_YEAR,12, 31)) |
# beginning of the new year
Q(birthday__gte = datetime.date(BIRTHDAY_YEAR, 1, 1)) &
Q(birthday__lte = datetime.date(BIRTHDAY_YEAR,
future_date.month,
future_date.day)
)
)
Если вам интересно, что такое Q()
, посмотрите на Сложные поиски с объектами Q