鉴于以下Person
型号,我正试图在即将到来的20天内过生日:
class Person(models.Model):
dob = models.DateField() # date of birth
关于SO已经存在类似的问题(here和here),但这些问题不包括我的用例,因为我存储的是出生日期而不是下一个生日或时间段
我试过做以下事情:
from datetime import timedelta, date
today = date.today()
next_20_days = today+timedelta(days=20)
Person.objects.filter(dob__month=today.month, dob__day__range=[today.day, next_20_days.day])
...但我得到FieldError: Unsupported lookup 'day' for DateField or join on the field not permitted.
当我这样做的时候Person.objects.filter(dob__month=today.month, dob__day=next_20_days.day)
,我确实从现在起20天内得到了结果。所以我可能会在一个循环中的20天中每一天都过去,但这似乎相当无效。
关于如何以正确的方式做到这一点的任何想法?
答案 0 :(得分:1)
仅供参考,我最终做了以下哪些对我有用,并且不需要原始SQL。 欢迎任何改进: - )
# Get the upcoming birthdays in a list (which is ordered) for the amount of days specified
def get_upcoming_birthdays(person_list, days):
person_list= person_list.distinct() # ensure persons are only in the list once
today = date.today()
doblist = []
doblist.extend(list(person_list.filter(dob__month=today.month, dob__day=today.day)))
next_day = today + timedelta(days=1)
for day in range(0, days):
doblist.extend(list(person_list.filter(dob__month=next_day.month, dob__day=next_day.day, dod__isnull=True)))
next_day = next_day + timedelta(days=1)
return doblist
答案 1 :(得分:0)
不幸的是,我认为您应该放弃日期对象,因为年份数据的额外复杂性会导致轻松选择。相反,我建议将生日存储为MMDD
字符串(comparison of strings works,只要您一致地格式化它们)。然后,您可以计算next_20_days
并将其转换为类似的MMDD
字符串,以及今天的字符串,然后将它们用作值进行比较。
我有三个边缘情况,你一定要确保工作:
OR
个对象执行Q
查询。编辑:另见:
等等。我刚刚进行了Google搜索"堆栈溢出生日选择"。
答案 2 :(得分:0)
过去几天我一直在努力解决同样的问题。我想我已经汇集了一个非常可靠的解决方案,可以让你轻松地获得接下来X天的所有生日。此查询针对数据库表geburtstage(birthdays)运行,包含以下4个字段:ID(设置为主键)vorname(firstname),nachname(lastname)和geburtstag(birthday)。只需创建表格,填写一些记录并运行以下查询:
select * FROM (
select curdate() AS today, DAY(CURDATE()) AS d_T, MONTH(CURDATE()) AS m_T, DAY(geburtstag) AS d_G, MONTH(geburtstag) AS m_G, subdate(CURDATE(),-20) AS date_20, DAY(subdate(CURDATE(),-20)) AS d_20, MONTH(subdate(CURDATE(),-20)) AS m_20, vorname, nachname, geburtstag, (YEAR(CURRENT_TIMESTAMP) - YEAR(geburtstag) +1 - CASE WHEN MONTH(CURRENT_TIMESTAMP) < MONTH(geburtstag) THEN 1 WHEN MONTH(CURRENT_TIMESTAMP) > MONTH(geburtstag) THEN 0 WHEN DAY(CURRENT_TIMESTAMP) <= DAY(geburtstag) THEN 1 ELSE 0 END) AS age, datediff(DATE_FORMAT(geburtstag,concat('%',YEAR(CURDATE()),'-%m-%d')),NOW()) AS no_of_days FROM geburtstage
union
select curdate() AS today, DAY(CURDATE()) AS d_T, MONTH(CURDATE()) AS m_T, DAY(geburtstag) AS d_G, MONTH(geburtstag) AS m_G, subdate(CURDATE(),-20) AS date_20, DAY(subdate(CURDATE(),-20)) AS d_20, MONTH(subdate(CURDATE(),-20)) AS m_20, vorname, nachname, geburtstag, (YEAR(CURRENT_TIMESTAMP) - YEAR(geburtstag) +1 - CASE WHEN MONTH(CURRENT_TIMESTAMP) < MONTH(geburtstag) THEN 1 WHEN MONTH(CURRENT_TIMESTAMP) > MONTH(geburtstag) THEN 0 WHEN DAY(CURRENT_TIMESTAMP) <= DAY(geburtstag) THEN 1 ELSE 0 END) AS age, datediff(DATE_FORMAT(geburtstag,concat('%',(YEAR(CURDATE())+1),'-%m-%d')),NOW()) AS no_of_days FROM geburtstage) AS upcomingbirthday
WHERE no_of_days >=0 AND no_of_days <= 20 GROUP BY ID
ORDER BY (m_G, d_G) < (m_T, d_T), m_G, d_G, geburtstag desc, age