django DateTimeField类型及日期比较

79 阅读6分钟

django日期的比较 DateTimeField

DateTimeField 是一个日期和时间字段,用于存储日期,在 Python 中由实例表示。顾名思义,该字段用于存储 python 中创建的 datetime 对象。此字段的默认表单窗口小部件是 .管理员使用两个带有 JavaScript 快捷方式的单独小部件。datetime.datetime``TextInput``TextInput

语法

field_name = models.DateTimeField(**options)

DateTimeField 具有以下额外的可选参数 –

  • DateTimeField.auto_now

    每次保存对象时,自动将字段设置为现在。对 “last-modified” 时间戳很有用。请注意,始终使用当前日期;它不会被你传递的默认值覆盖。
    该字段仅在调用 Model.save() 时自动更新。当以其他方式(例如 QuerySet.update())更新其他字段时,该字段不会更新,但你可以在这样的更新中为该字段指定一个自定义值。

  • DateTimeField.auto_now_add

    首次创建对象时,自动将字段设置为现在。用于创建时间戳。请注意,始终使用当前日期;它不仅仅是您可以覆盖的默认值。因此,即使在创建对象时为此字段设置了值,它也将被忽略。如果希望能够修改此字段,请设置以下内容,而不是 auto_now_add=True:

    • 对于 DateTimeField: default=datetime.now – 从datetime.now()
    • 对于 DateTimeField: default=timezone.now – 从django.utils.timezone.now()

: 选项 auto_now_add、auto_now 和 default 是互斥的。这些选项的任意组合都会导致错误。

Python日期的比较

使用datetime模块创建日期

在Django中存储日期和时间的字段通常是DateTimeField或DateField。这些字段分别用于存储日期和时间、或两者的组合。一旦我们从数据库中获取了这些字段的值,我们可以使用datetime模块来处理和比较它们。

首先,我们需要导入datetime模块:

from datetime import datetime

接下来,我们可以使用datetime模块中的各种方法来创建日期。

下面是一些示例:

now = datetime.now()  # 当前日期和时间
today = datetime.today()  # 当天的日期和时间
date = datetime(2022, 1, 1)  # 指定的日期

我们可以在创建日期时指定年、月和日,也可以省略其他字段。datetime模块还提供了许多其他方法来处理日期,比如获取年、月、日等等。

使用datetime比较日期

一旦我们有了两个日期,我们可以使用datetime模块中的比较运算符(如<、>、等)来比较它们。

下面是一些示例:

date1 = datetime(2022, 1, 1)
date2 = datetime(2023, 1, 1)

if date1 < date2:
    print("date1在date2之前")
elif date1 > date2:
    print("date1在date2之后")
else:
    print("date1和date2相同")

if date1 != date2:
    print("date1和date2不相同")

我们可以使用比较运算符来判断两个日期的相对位置,并根据需要执行相应的逻辑。

在Django查询中使用datetime比较日期

使用datetime模块比较日期的一个常见情况是在Django查询中筛选日期。Django提供了一种灵活且易于使用的方式来执行这样的查询。

假设我们有一个Model,其中有一个日期字段pub_date,我们想要找到所有pub_date在当前日期之后的记录。我们可以使用以下查询:

from django.db import models
from datetime import datetime

class Article(models.Model):
    # other fields
    pub_date = models.DateField()

articles = Article.objects.filter(pub_date__gt=datetime.now().date())

在上面的例子中,我们使用了__gt表达式来检索pub_date大于当前日期的记录。你还可以使用其他运算符,如__lt(小于)、__gte(大于等于)等等。

字段比较大小

__gt 大于 __lt 小于 __gte 大于或等于 __lte 小于或等于

使用datetime进行日期计算

除了比较日期,datetime模块还提供了各种方法来执行日期计算。比如,我们可以计算两个日期之间的时间差,或者在给定日期上添加或减去一段时间。

下面是一些示例:

from datetime import timedelta

date1 = datetime(2022, 1, 1)
date2 = datetime(2023, 1, 1)

diff = date2 - date1  # 计算时间差
print(diff.days)  # 打印相差的天数

new_date = date1 + timedelta(days=7)  # 在给定日期上添加一周的时间
print(new_date)

以上示例展示了如何计算两个日期之间的天数差,并在给定日期上添加一段时间。

报错解决——DateTimeField *** received a naive datetime (***) while time zone support is active

这是一个跟时区有关的问题,报错中说到datetime字段得到一个naive datetime,而不是支持time zone的active datetime
由于Django的设置中米哦人USE_TZ设置为True,Django会自动根据所设的时区对时间进行转换,所以程序中和数据保存的时间都转UTC时间,只有模版渲染时会把时间转为TIME_ZONE所设置的时区的时间。

  使用datetime.datetime.utcnow() 输出的是不带时区的utc时间,称为naive time

rom datetime import datetime 
datetime.now() 
datetime.datetime(2016, 06, 19, 07, 14, 55, 865000)

 

  使用django.utils.timezone.now() 输出的是带时区的utc时间,称为active time

from django.utils import timezone
timezone.now()
datetime.datetime(2025, 1, 8, 13, 0, 37, 256763, tzinfo=datetime.timezone.utc)

 

  如果项目需要根据时区显示时间,那就使用Django的timezone.now()。不需要的话将USE_TZ设置为False即可。

  使用带时区的时间,将所有用到datetime.now()的地方改为timezone.now(),并在对应的文件顶部加上from django.utils import timezone,就OK了。

  如果项目中已经有了很多datetime.now(),又不想大面积改动的话,可以将import的语句修改一下

# from datetime import datetime # 原来用的注释掉
from django.utils import timezone as datetime # 不想大面积修改就这么做

但是用timezone.now()去获取date、time、today都是没有时区信息的

timezone.now().today()
Out[54]: datetime.datetime(2025, 1, 8, 21, 9, 57, 799967)
timezone.now().date()
Out[55]: datetime.date(2025, 1, 8)

如果还要用django.utils.timezone,按需要可以使用timezone.now()加上或减去时间段timedelta

from datetime import timedelta
timezone.now()-timedelta(minutes=5)
Out[58]: datetime.datetime(2025, 1, 8, 13, 10, 9, 142733, tzinfo=datetime.timezone.utc)

例如:我要查找创建时间为十五分钟之前的订单,并对其进行更新

def update_timeout_order():
    passed_time = timedelta(minutes=15)
    now = timezone.now()
    # 查找十五分钟之前的订单
    timeout_orders = Order.objects.filter(create_time__lte=now - passed_time).filter(status='01')
    print(timeout_orders)
    # 更新
    timeout_orders.update(status='09')

参考文章

DateTimeField - Django Models - GeeksforGeeks

Django 使用datetime来与Django中的日期进行比较|极客教程 (geek-docs.com)

报错解决——DateTimeField *** received a naive datetime (***) while time zone support is active - ''竹先森゜ - 博客园 (cnblogs.com)