Django ORM中__date查询SQLite正常、MySQL5.7返回None问题
问题根源
你遇到的是Django跨数据库后端的__date字段查找兼容问题:
- SQLite本身对日期格式处理比较宽松,无时区强制校验逻辑,因此
DateTimeField__date查找可以正常提取日期部分 - MySQL 5.7的日期提取函数严格依赖时区配置,当Django项目开启
USE_TZ = True(默认开启)时,存入MySQL的是带UTC时区的时间值,若MySQL实例的系统时区、连接时区和Django项目配置的TIME_ZONE不匹配,就会导致__date查找时提取失败,返回None
最优解决方案
推荐使用Django官方提供的跨数据库兼容日期截断函数TruncDate实现需求,无需调整数据库配置,适配所有主流数据库后端:
首先导入依赖:
from django.db.models import Sum from django.db.models.functions import TruncDate
修改查询代码为:
daily_changes = Inbound.objects.annotate( # 直接在数据库层截断时间,仅保留日期部分 effective_date_date = TruncDate('effective_date') ).values('effective_date_date').annotate( total_change = Sum('number') ).order_by('effective_date_date')
返回结果中effective_date_date字段就是日期类型的统计维度,和你原来用__date的预期返回完全一致。
低版本Django兼容方案
如果你的Django版本低于1.10(不支持TruncDate),可以用extra方法临时兼容MySQL:
daily_changes = Inbound.objects.extra( {'effective_date_date': 'DATE(effective_date)'} ).values('effective_date_date').annotate( total_change=Sum('number') )
注意extra方法已经被官方标记为弃用,仅作为极端场景下的临时方案使用。
备选配置方案(不推荐)
如果坚持使用__date查找,可调整Django数据库配置,强制MySQL连接时区和项目时区一致,以MySQL时区为东八区为例:
# settings.py DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', # 其他数据库配置 'OPTIONS': { 'init_command': "SET time_zone = '+08:00'", }, } }
该方案依赖环境时区配置,迁移到其他时区的服务器时需要同步修改,兼容性较差。
内容的提问来源于stack exchange,提问作者Mas Zero
相关产品推荐
相关产品推荐

