You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django查询年度数据时DateTimeField naive datetime警告解决方法

问题背景

我需要过滤查询集(queryset)获取当年的全部帖子,最初编写的代码如下:

def thisYearQuerySet(objects):
    start_day = datetime.date(datetime.date.today().year, 1, 1)
    end_day = datetime.date(datetime.date.today().year, 12, 31)
    return objects.filter(date__range=[start_day, end_day])

运行时Django抛出提示,称start_day和end_day的声明可能与django.utils.timezone冲突,该问题不影响核心功能,但抛出的警告非常影响使用体验。

我不想通过关闭Django全局警告的方式消除提示,希望了解如何通过django.utils相关工具生成带时区信息的年度首日与末日来解决该问题。

完整警告内容

RuntimeWarning: DateTimeField Model.date received a naive datetime (2021-01-01 00:00:00) while time zone support is active.
RuntimeWarning: DateTimeField Model.date received a naive datetime (2021-12-31 00:00:00) while time zone support is active.

解决方案

需要设置对应时区才能消除该警告,以下是可直接复用的项目时间处理模块,包含年/月/周/日等多维度的查询集过滤、时间转换工具:

import pytz
import datetime
from django.utils import timezone
from django.conf import settings
from django.db.models import Q
from django.utils.dateparse import parse_datetime


# MM/DD/YY 格式时间转换
def when(create):
    return '%s/%s/%s' % (create.month, create.day, create.year)


# 获取当前格式化时间
def current():
    return when(timezone.now())


# 生成相对时间描述
# create: 对象创建日期
# now: 当前时间
# li: 时间单位字符串列表(可自定义语言)
# lst: 时间后缀(可自定义语言)
# long: 展示的时间单位长度
def howLongAgo(
    create, 
    now, 
    li=[
        '秒',
        '分',
        '时',
        '天',
        '周',
        '月',
        '年',
    ], 
    lst='之前',
    long=2
):
    dif = create - now
    sec = dif.days * 24 * 60 * 60 + dif.seconds
    minute = sec // 60
    sec %= 60
    hour = minute // 60
    minute %= 60
    day = hour // 24
    hour %= 24
    week = day // 7
    day %= 7
    month = (week * 7) // 30
    week %= 30
    year = month // 12
    month %= 12
    s = []
    for ii, tt in enumerate([sec, minute, hour, day, week, month, year]):
        ss = li[ii]
        if tt != 0:
            s.append(str(tt) + ss)

    return ' '.join(list(reversed(s))[:long]) + lst


# 日期转日期时间类型
def dateToDatetime(li):
    res = []
    for ar in li:
        res.append(datetime.datetime.combine(ar, datetime.datetime.min.time()))
    return res


# 生成连续日期范围迭代器
def datespan(startDate, endDate, delta=datetime.timedelta(days=1)):
    currentDate = startDate
    while currentDate < endDate:
        yield currentDate
        currentDate += delta


# ========== 查询集过滤工具 ==========
# 当月数据查询
def thisMonthQuerySet(objects):
    today = timezone.now()
    year = today.year
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(year, today.month, 1)))
    end_day = start_day + datetime.timedelta(30)
    return objects.filter(date__range=[start_day, end_day])


# 上月数据查询
def lastMonthQuerySet(objects):
    today = timezone.now()
    year = today.year
    month = today.month - 1
    if month == 0:
        year -= 1
        month = 12
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(year, month, 1)))
    end_day = start_day + datetime.timedelta(30)
    return objects.filter(date__range=[start_day, end_day])


# 当年数据查询(修复时区警告版本)
def thisYearQuerySet(objects):
    today = timezone.now()
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
    end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year + 1, 1, 1)))
    return objects.filter(date__range=[start_day, end_day])


# 去年数据查询
def lastYearQuerySet(objects):
    today = timezone.now()
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year - 1, 1, 1)))
    end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
    return objects.filter(date__range=[start_day, end_day])


# 近四个季度数据查询
def lastQuaterQuerySet(objects):
    today = timezone.now()
    four_month_before = today - timezone.timedelta(30 * 4)
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(four_month_before.year, four_month_before.month, 1)))
    return objects.filter(date__gte=start_day)


# ========== 时间范围获取工具 ==========
# 获取上周日期范围
def getLastWeek():
    date = datetime.date.today()
    end_day = date - datetime.timedelta(date.weekday())
    start_day = end_day - datetime.timedelta(7)
    return dateToDatetime([day for day in datespan(start_day, end_day)])


# 获取本周日期范围
def getThisWeek():
    date = datetime.date.today()
    start_day = date - datetime.timedelta(date.weekday())
    end_day = start_day + datetime.timedelta(7)
    return dateToDatetime([day for day in datespan(start_day, end_day)])


# 获取上月日期范围
def getLastMonth():
    today = datetime.date.today()
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month - 1 if today.month - 1 != 0 else 1, 1)))
    end_day = start_day + datetime.timedelta(30)
    return [day for day in datespan(start_day, end_day)]


# 获取当月日期范围
def getThisMonth():
    today = datetime.date.today()
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month, 1)))
    end_day = start_day + datetime.timedelta(30)
    return [day for day in datespan(start_day, end_day)]


# 获取去年日期范围
def getLastYear():
    today = datetime.date.today()
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year - 1, 1, 1)))
    end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
    return [day for day in datespan(start_day, end_day)]


# 获取当年日期范围
def getThisYear():
    today = datetime.date.today()
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, 1, 1)))
    end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year + 1, 1, 1)))
    return [day for day in datespan(start_day, end_day)]


# ========== 排除查询工具 ==========
# 排除当日数据
def dayNotIn(objects):
    return objects.filter(~Q(date=timezone.now()))


# 排除近7天数据
def weekNotIn(objects):
    return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=7))


# 排除近30天数据
def monthNotIn(objects):
    return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=30))


# 排除近365天数据
def yearNotIn(objects):
    return objects.filter(date__lt=timezone.now() - datetime.timedelta(days=365))


# ========== 按指定年月查询 ==========
def getQSbyYM(objects, y, m):
    # m 取值范围 [0, 12]
    em = m + 1 
    ey = y
    if em == 13:
        em = 1
        ey = y + 1
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(y, m, 1)))
    end_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(ey, em, 1)))
    return objects.filter(date__lt=end_day, date__gte=start_day)


# 查询当日创建的数据
def createInToday(objects):
    today = timezone.now()
    start_day = pytz.timezone('Asia/Shanghai').localize((datetime.datetime(today.year, today.month, today.day)))
    end_day = start_day + datetime.timedelta(1)
    return objects.filter(date__lt=end_day, date__gte=start_day)


# 日期时间转标准字符串格式
def dtstr(dt) -> str:
    return dt.strftime('%Y-%m-%dT%H:%M:%S')


# 字符串转带时区的日期时间对象
def strdt(st):
    return pytz.timezone('Asia/Shanghai').localize((parse_datetime(st)))

使用说明

  • 使用时请根据模型的DateTime字段名称修改date__前缀
  • 请根据站点部署的区域调整对应时区即可

内容的提问来源于stack exchange,提问作者Weilory

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 05:24:06