Vic*_*r T 5 python django django-database django-settings django-1.11
2019 年 4 月 8 日更新
\n\n这是 django<=2.2 的一个已知错误,自此PR起已修复
\n\n===================================
\n\n(我们假设mysql后端)
\n\n我可以在 中设置TIME_ZONE多次settings.py,一次用于全局 django 应用程序,一次用于每个数据库(请参阅https://docs.djangoproject.com/en/1.11/ref/settings/#time-zone (ref1))
典型用法是用于日期时间不以 UTC 存储的旧数据库。
\n\n查询我的数据库会考虑此设置,例如:
\n\n在settings.py
USE_TZ = True\nTIME_ZONE = \'Europe/Paris\' # tz1\nDATABASES = {\n \'legacy\': {\n \'ENGINE\': \'django.db.backends.mysql\',\n \'OPTIONS\': {\n \'read_default_file\': \'....cnf\',\n },\n \'TIME_ZONE\': \'Europe/Paris\', # tz2\n },\n \'default\' : {\n \'ENGINE\': \'django.db.backends.mysql\',\n \'OPTIONS\': {\n \'read_default_file\': \'....cnf\',\n },\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n在里面manage.py shell
>>> dt = timezone.make_aware(datetime.datetime(2017, 7, 6, 20, 50))\n>>> dt\ndatetime.datetime(2017, 7, 6, 20, 50, tzinfo=<DstTzInfo \'Europe/Paris\' CEST+2:00:00 DST>)\n>>> MyModel.objects.filter(my_datetime_field=dt).exists()\nTrue\nRun Code Online (Sandbox Code Playgroud)\n\n这有效,因为我的数据库读取\'2017-07-06 20:50:00\'
相关文档https://docs.djangoproject.com/en/1.11/ref/models/querysets/#date (ref2)
\n\n但这是行不通的,虽然从逻辑上来说应该如此
\n\n>>> MyModel.objects.filter(my_datetime_field__date=dt.date()).exists()\nFalse*\nRun Code Online (Sandbox Code Playgroud)\n\nDEBUG 的相关 SQL 查询是:
\n\nSELECT (1) AS `a` FROM `my_model` WHERE DATE(CONVERT_TZ(`my_model`.`my_datetime_field`, \'UTC\', \'Europe/Paris\')) = \'2017-07-06\' LIMIT 1;\nRun Code Online (Sandbox Code Playgroud)\n\n(*) 请注意,我还没有在 MySQL 中填写时区表,因此结果应该是True这种情况,但可能False接近午夜。\n相关文档是https://dev.mysql.com/doc/refman /5.7/en/mysql-tzinfo-to-sql.html
有两件事是错误的。首先,转换应该是从巴黎到巴黎,而不是UTC到巴黎。转换应该从数据库时区 tz2 到 django 应用程序一 tz1。
\n\n确实来自 ref1 :
\n\n\n\n\n当 USE_TZ 为 True 并且数据库不支持时区(例如 SQLite、MySQL、Oracle)时,如果设置了此选项,Django 将根据本地时间读取和写入日期时间;如果设置了,则以 UTC 读取和写入日期时间\x80\x99t。
\n
和参考2:
\n\n\n\n\n当 USE_TZ 为 True 时,字段在过滤之前会转换为当前时区
\n
其次,当tz1 == tz2时,应该不需要使用CONVERT_TZ,查询将在MySQL中没有时区表的情况下工作。
显式查询是:
\n\nmysql> SELECT (1) AS `a` FROM `my_model` WHERE `my_model`.`my_datetime_field` = \'2017-07-06 20:50:00\' LIMIT 1;\n+---+\n| a |\n+---+\n| 1 |\n+---+\n1 row in set (0.00 sec)\n\nmysql> SELECT (1) AS `a` FROM `my_model` WHERE DATE(`my_model`.`my_datetime_field`) = \'2017-07-06\' LIMIT 1;\n+---+\n| a |\n+---+\n| 1 |\n+---+\n1 row in set (0.00 sec)\nRun Code Online (Sandbox Code Playgroud)\n\n为什么\'UTC\'出现在查询中?不应该吗\'Europe/Paris\'?
我是否误解了文档中的某些内容,或者这是一个错误?
\n\n谢谢。
\n\n编辑:我的系统 tz 不是 UTC,如果这有帮助的话
\n\nmysql> SELECT @@global.time_zone, @@session.time_zone, @@system_time_zone;\n+--------------------+---------------------+--------------------+\n| @@global.time_zone | @@session.time_zone | @@system_time_zone |\n+--------------------+---------------------+--------------------+\n| SYSTEM | SYSTEM | CEST |\n+--------------------+---------------------+--------------------+\nRun Code Online (Sandbox Code Playgroud)\n
这种行为是可以预料的,因为Django 的代码如下
django/db/backends/mysql/operations.py
def _convert_field_to_tz(self, field_name, tzname):
if settings.USE_TZ:
field_name = "CONVERT_TZ(%s, 'UTC', %%s)" % field_name
params = [tzname]
else:
params = []
return field_name, params
Run Code Online (Sandbox Code Playgroud)
为了 的利益,数据库特定时区被忽略'UTC'。
对于它的价值,我已经在 djangoproject 上开了一张票,它是相关的拉取请求
将其替换为:
def _convert_field_to_tz(self, field_name, tzname):
if settings.USE_TZ and self.connection.timezone_name != tzname:
field_name = "CONVERT_TZ(%s, '%s', %%s)" % (field_name, self.connection.timezone_name)
params = [tzname]
else:
params = []
return field_name, params
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10181 次 |
| 最近记录: |