Django实现忽略年份的日期范围过滤方法
Django 忽略年份按日月维度过滤日期数据实现方案
你需要提取日期字段的月份、日两个维度单独做匹配,不需要用到年份信息,下面是两种常用实现方式:
方案1:Django 3.2+ 官方推荐实现(适配所有数据库后端)
使用Django内置的Extract函数提取月、日字段后做过滤:
- 先导入依赖模块:
from django.db.models import Q from django.db.models.functions import Extract
- 普通不跨年末的范围查询示例(比如查询3月15日到9月10日之间的所有生日记录):
start_month = 3 start_day = 15 end_month = 9 end_day = 10 Sample.objects.annotate( # 单独提取生日的月份和日 birth_month=Extract('birthday', 'month'), birth_day=Extract('birthday', 'day') ).filter( # 匹配大于等于起始日月 Q(birth_month__gt=start_month) | Q(birth_month=start_month, birth_day__gte=start_day) ).filter( # 匹配小于等于结束日月 Q(birth_month__lt=end_month) | Q(birth_month=end_month, birth_day__lte=end_day) )
- 跨年末的范围查询示例(比如查询12月20日到次年1月10日之间的所有生日记录):
Sample.objects.annotate( birth_month=Extract('birthday', 'month'), birth_day=Extract('birthday', 'day') ).filter( Q(birth_month=12, birth_day__gte=20) | Q(birth_month=1, birth_day__lte=10) )
方案2:旧版本Django兼容实现
如果你使用的Django版本低于3.2,可以调用对应数据库的原生日期函数实现,以MySQL为例:
from django.db.models import Q Sample.objects.extra( where=[ 'MONTH(birthday) > %s OR (MONTH(birthday) = %s AND DAYOFMONTH(birthday) >= %s)', 'MONTH(birthday) < %s OR (MONTH(birthday) = %s AND DAYOFMONTH(birthday) <= %s)' ], params=[start_month, start_month, start_day, end_month, end_month, end_day] )
注意:
extra方法已被Django官方标记为废弃,仅在无法升级Django版本时临时使用,优先选择方案1。
闰年特殊处理
如果业务场景涉及2月29日的生日记录,可以根据需求额外补充判断逻辑:
- 非闰年时可将2月29日的匹配规则对齐到2月28日
- 仅当查询范围包含2月29日时才返回对应生日的记录
内容的提问来源于stack exchange,提问作者John R Perry
相关产品推荐
相关产品推荐

