Django 2.0中按创建时间年、月查询Post数据无结果问题排查
问题分析与解决方案
碰到这种带月份参数就查不到结果的情况,大概率是两个常见原因导致的,咱们一步步来排查解决:
1. URL捕获的参数是字符串类型,与查询所需整数不匹配
你的URL配置里用正则[0-9]{4}和[0-9]{1,2}捕获的year和month都是字符串类型,但Django的DateTimeField__month查询逻辑期望接收整数参数。举个例子:如果URL传过来的月份是字符串'09',但数据库里存储的月份是整数9,字符串和整数类型不匹配,自然查不到对应结果。而年份参数能生效,是因为部分数据库会对字符串格式的年份做隐式转换,但月份就没这么“宽容”了。
解决方法:
在视图函数里把year和month转换成整数后再执行查询:
def archives(request, year, month): # 先把字符串参数转成整数 year = int(year) month = int(month) post_list = Post.objects.filter( created_time__year=year, created_time__month=month ).order_by('-created_time') # 后续打印和渲染代码不变 print('Year:{0}.\nMonth:{1}'.format(year,month)) count = 0 for a in post_list: count += 1 print("I've found {} post here!".format(str(count))) return render(request, 'blog/index.html', context={'post_list': post_list})
2. 时区配置导致的时间偏移问题
如果你的Django项目设置了USE_TZ = True(Django 2.0默认开启),数据库里存储的created_time是UTC标准时间,但你在模板和业务逻辑里用的是本地时间。比如你在东八区,发布一篇本地10月1日0点的文章,UTC时间其实是9月30日16点,这时候按本地的10月查询,用created_time__month=10会查不到——因为数据库里的UTC时间月份是9。
解决方法:
构造本地时间的范围,转换为UTC时间后再查询(记得导入timezone模块):
from django.utils import timezone def archives(request, year, month): year = int(year) month = int(month) # 构造当月第一天和下月第一天的本地时间 start_local = timezone.datetime(year, month, 1) if month == 12: end_local = timezone.datetime(year + 1, 1, 1) else: end_local = timezone.datetime(year, month + 1, 1) # 转换为带时区的时间(适配USE_TZ=True的配置) start_date = timezone.make_aware(start_local) end_date = timezone.make_aware(end_local) # 查询该时间段内的文章 post_list = Post.objects.filter( created_time__gte=start_date, created_time__lt=end_date ).order_by('-created_time') # 后续代码不变 print('Year:{0}.\nMonth:{1}'.format(year,month)) count = 0 for a in post_list: count += 1 print("I've found {} post here!".format(str(count))) return render(request, 'blog/index.html', context={'post_list': post_list})
快速验证步骤
你可以先在视图里打印参数的类型,确认是不是字符串的问题:
print(type(year), type(month)) # 会输出 <class 'str'> <class 'str'>
先试试第一个解决方案,大部分情况下这个就能解决问题。如果还是不行,再检查项目的时区配置,用第二个方法处理。
内容的提问来源于stack exchange,提问作者Marco Mei
相关产品推荐
相关产品推荐

