Django按日期过滤模型:开发正常生产环境无查询结果
核心原因:时区配置不匹配
开发/生产环境的Django时区设置、MySQL时区不一致,导致日期筛选的基准错位,是这类问题最常见的“低级错误”。
1. 先确认关键配置
Django 时区设置:检查
settings.py中的USE_TZ和TIME_ZONE,确保开发、生产环境完全一致:USE_TZ = True TIME_ZONE = 'UTC' # 或你实际使用的时区,比如Asia/Shanghai注意:当
USE_TZ=True时,Django会将timezone.now()生成的带时区时间转成UTC存入数据库(除非字段指定timezone=False),查询时再转回TIME_ZONE对应的时区。MySQL 时区配置:登录生产环境的Azure MySQL,执行以下SQL查看时区:
SELECT @@global.time_zone, @@session.time_zone;如果数据库时区不是UTC(和Django存储的时间时区不一致),会导致
__day/__month这类基于数据库本地时间的筛选条件失效。可以通过Azure控制台修改MySQL时区,或执行SQL临时调整:SET GLOBAL time_zone = '+00:00'; SET SESSION time_zone = '+00:00';
2. 修正查询语句(规避时区坑)
放弃__day/__month、直接用日期字符串这类依赖数据库时区的写法,改用Django时区工具构造精确的时间范围:
from django.utils import timezone # 获取当前时区的当日起始和次日起始时间 today = timezone.now().date() start_of_day = timezone.make_aware(timezone.datetime(today.year, today.month, today.day)) end_of_day = start_of_day + timezone.timedelta(days=1) # 筛选当日创建的日志 logs = EmailLog.objects.filter(created_on__gte=start_of_day, created_on__lt=end_of_day)
这种写法的优势:
- 基于Django配置的时区计算日期范围,不受数据库时区影响
- 用
lt=end_of_day替代lte=当日23:59:59,避免毫秒级精度丢失导致的漏查
3. 验证时间存储的实际时区
你提到数据库中created_on显示为2023-05-10 16:31:34.381,但打印实例时显示2023-05-10 16:31:34.381741+00:00,说明数据库存储的是UTC时间(带+00:00时区)。如果生产环境Django的TIME_ZONE不是UTC,那么timezone.now().date()会生成对应时区的日期,和数据库中的UTC日期可能存在错位(比如UTC的5月10日,对应美国东部时间是5月9日),这就是你查不到数据的直接原因。
内容的提问来源于stack exchange,提问作者Tim D.

