使用'出生日期'DateField获得即将到来的生日

时间:2015-04-24 20:51:54

标签: django

鉴于以下Person型号,我正试图在即将到来的20天内过生日:

class Person(models.Model):
    dob = models.DateField()  # date of birth

关于SO已经存在类似的问题(herehere),但这些问题不包括我的用例,因为我存储的是出生日期而不是下一个生日或时间段

我试过做以下事情:

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天中每一天都过去,但这似乎相当无效。

关于如何以正确的方式做到这一点的任何想法?

3 个答案:

答案 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字符串,以及今天的字符串,然后将它们用作值进行比较。

我有三个边缘情况,你一定要确保工作:

  1. 正常月份翻转。 (例如,6月至7月)
  2. 闰日 - 不要忘记检查2月29日的存在情况。
  3. 年份边界 - 您需要执行两个查询并将结果合并,或使用OR个对象执行Q查询。
  4. 编辑:另见:

    等等。我刚刚进行了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