加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

python – Django日期比较服务器上的不同

发布时间:2020-12-20 13:52:02 所属栏目:Python 来源:网络整理
导读:我刚刚意识到我们的生产设置中有一些非常奇怪的日期比较行为,我不明白. 上市模型 title (CharField)from_date (DateTimeField)to_date (DateTimeField) 查询集 now = arrow.now()Listing.objects.filter(to_date__gte=now.datetime) 建立 Python 2.7 Django
我刚刚意识到我们的生产设置中有一些非常奇怪的日期比较行为,我不明白.

上市模型

title (CharField)
from_date (DateTimeField)
to_date (DateTimeField)

查询集

now = arrow.now()
Listing.objects.filter(to_date__gte=now.datetime)

建立

> Python 2.7
> Django 1.7
> SQLite / PostgreSQL
> Ubuntu

问题

当列表对象的to_date设置为比现在早一个小时,在开发服务器和生产服务器上的shell上时,查询集将返回正确的结果(不包括所讨论的列表).但是,在生产服务器上,查询继续包括列表(未启用缓存).我已经确定,如果我将列表的日期设置为前一天,则会将其正确排除,使其看起来只有几天进行比较(我甚至将时间设置为00:00以排除时区问题,但这仍然包括列表 – 如上所述,只改变工作日).请问为什么会这样,我该如何解决?

附加信息

>我使用“date”命令确认服务器时区与settings.py中指定的时区一致
>我已在settings.py中确认USE_TZ = True且已正确设置TIME_ZONE.
>我已经登录到服务器上的PostgreSQL终端并运行了now命令 – 这返回了与系统相同的时区和settings.py中指定的时区.
>我已经确认postgresql中的to_date字段是“带时区字段的时间戳”
>传递给db的实际sql的提取:WHERE(“directory_listing”.“to_date”> = 2015-08-22 14:01:56.663072)

解决方法

我相信您看到的差异的关键在于您使用两个不同的数据库引擎,一个在您的开发环境中,另一个在您的生产环境中,并且它们对日期和时间的处理方式截然不同.

日期和时间可以以文本格式,浮点数量或整数存储,并且各种函数用于将输入数据转换为这些形式之一以用于存储或比较目的.此外,它没有任何特定的“带时区的日期时间”数据类型,甚至没有完全支持任意时区之间的时区转换.

Postgresql has comprehensive support用于有和没有时区的日期,时间,间隔和时间戳.它还具有专门定义的运算符,用于相互比较这些运算符.

我怀疑当使用SQLite作为数据库后端时,Django正在使用文本形式.如果是这种情况,那么给出一个像这样的WHERE子句:

WHERE (to_date >= '2015-08-22 14:01:56.663072')

它将使用纯文本比较 – 这似乎工作正常,因为您可以通过这种方式比较两个ISO8601字符串(只要您不关心时区).

在生产环境中,您使用的是postgresql,其中包含“带时区的时间戳”类型.这意味着存储在数据库中的数据与附加的时区信息一起存储.

在这种情况下,有几个时区在起作用:

> Django / python环境的时区
>运行客户端(Django)软件的计算机上的系统时区
>数据库的时区(通过timezone配置参数配置,您可以使用命令SHOW timezone检查;在psql提示符下).
>无论在数据库中发送的字符串中嵌入了什么时区信息.

根据您的评论,您至少检查了其中一些设置.

一种可能性是,当记录被插入数据库时??,to_date字段包含一个时区,它与postgresql数据库设置使用的时区不同.例如,考虑一下:

ispdb_t2=> select '2015-08-22 00:00:00-10:00'::timestamp with time zone >= '2015-08-22 14:01:56.663072';
 ?column?
----------
 t
(1 row)

看起来好像认为2015-08-22 00:00:00是> = 2015-08-22 14:01:56.663072.这里实际发生的是左边的时间戳有时区-10,而右边的时间戳没有附加任何时区,所以它在数据库会话的时区中被解释(在我的情况下是’澳大利亚/维多利亚’,目前UTC时长10小时).

要验证这是否是您的情况,我建议您执行以下步骤:

>验证’timezone’postgresql配置参数的值.请注意,它可以按会话设置 – 因此您还应确认Django框架是否在连接后发送SET时区命令
>检查用于在数据库中插入值的SQL.确认时间值是否包含嵌入的时区.
>确认在查询中发送的文字的值,例如在WHERE子句中.根据您提供的信息确认它们是否包含嵌入的时区(看起来不像它们).
>获取服务器正在执行的SQL的确切文本,包括任何占位符值.尝试使用psql命令行工具直接在数据库中运行相同的查询.执行此操作时,请确保将时区设置为与Django正在执行的值相同的值(如果有).然后,您可以尝试更改各种值,直到获得有效的查询,然后从那里向后工作以使Django代码正常工作.

提示:您可以通过将配置参数log_statement设置为all来获取postgresql以记录所有语句.

您可能不希望在实际生产系统上进行此类测试.我建议您更改开发系统的配置,以便它使用Postgresql作为后端,然后重现您遇到的问题.

这让我得出了最后的建议:尽可能在开发系统中使用与生产中使用相同的数据库系统.即使允许应用程序开发人员隐藏数据库细节的框架,不同SQL数据库的运行方式通常也存在很大差异.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读