如何在Django中按出生日期剩余天数过滤列表,展示30天内即将过生日的用户
报错根因
该报错是因为两类datetime对象类型不匹配:
- ORM查询返回的
dateOfBirth是带时区信息的offset-aware类型 datetime.today()生成的是不带时区信息的offset-naive类型
两类对象不支持直接做算术运算。
报错修复代码
如果是Django环境,直接使用框架内置的时区工具统一时间类型即可,同时补充生日年份适配逻辑(避免出现当年生日已过,剩余天数为负的情况):
from django.utils import timezone # 获取当前带时区的日期,和数据库字段时区保持一致 today = timezone.localdate() customers = Customer.objects.all()[:10] for i in customers: # 取出生日的月日,适配为当年的生日日期 try: current_year_birthday = i.dateOfBirth.replace(year=today.year).date() except ValueError: # 兼容2月29日生日的平年场景,调整为2月28日 current_year_birthday = i.dateOfBirth.replace(year=today.year, month=2, day=28).date() # 当年生日已过的话,用明年生日计算剩余天数 if current_year_birthday < today: current_year_birthday = current_year_birthday.replace(year=today.year + 1) remaining_days = (current_year_birthday - today).days print(f"用户{i.name}剩余生日天数:{remaining_days}")
完整实现30天内生日用户查询
可以直接在ORM层完成计算和过滤,性能更高,直接返回你需要的字段:
from django.utils import timezone from django.db.models import F, ExpressionWrapper, IntegerField, Case, When, DateTimeField today = timezone.localdate() current_year = today.year upcoming_birthday_users = Customer.objects.annotate( # 计算当年生日日期 current_year_birth = ExpressionWrapper( F('dateOfBirth') + (current_year - F('dateOfBirth__year')) * timezone.timedelta(days=365), output_field=DateTimeField() ), # 当年生日已过的话,顺延到下一年 final_calc_birth = Case( When(current_year_birth__date__lt=today, then=F('current_year_birth') + timezone.timedelta(days=365)), default=F('current_year_birth'), output_field=DateTimeField() ), # 计算剩余天数 remaining_days = ExpressionWrapper( (F('final_calc_birth') - timezone.now()).days, output_field=IntegerField() ) # 过滤30天内生日的用户,按剩余天数升序排列 ).filter(remaining_days__lte=30, remaining_days__gte=0).order_by('remaining_days').values('name', 'dateOfBirth', 'remaining_days')
遍历upcoming_birthday_users即可获取所有符合要求的用户数据,将remaining_days字段格式化为还有X天即可匹配你要的列表展示效果。
如需调整2月29日生日的平年适配规则,修改对应的异常捕获分支即可。
内容的提问来源于stack exchange,提问作者Rowkaha
相关产品推荐
相关产品推荐

