【问题标题】:Django ORM executes query with wrong time?Django ORM 以错误的时间执行查询?
【发布时间】:2019-10-16 13:38:45
【问题描述】:

我正在尝试根据 DateTime 字段获取数据!我为此编写了以下脚本:

import datetime as dt

from dasboard.models import Visionsystem 
from django.utils.timezone import make_aware

min_dt = dt.datetime.combine(dt.date.today(), dt.time(7, 15))
max_dt = dt.datetime.combine(dt.date.today(), dt.time(15, 44))

# Changing format for Django
min_dt_aware = make_aware(min_dt)
max_dt_aware = make_aware(max_dt)

# Fetching all the data between 7:15:00 to 15:44:00 for current day
l1 = Visionsystem.objects.filter(start_datetime__range=(min_dt_aware, max_dt_aware))

print(l1) 产生 空列表 并检查 str(l1.query) 给出:

'SELECT `visionsystem`.`id`, `visionsystem`.`Start_Datetime` ... FROM `visionsystem` WHERE 
`visionsystem`.`Start_Datetime` BETWEEN 2019-10-16 01:45:00 AND 2019-10-16 10:14:00'

所需的查询是:

'SELECT `visionsystem`.`id`, `visionsystem`.`Start_Datetime` ... FROM `visionsystem` WHERE 
`visionsystem`.`Start_Datetime` BETWEEN 2019-10-16 07:15:00 AND 2019-10-16 15:44:00'

我不明白为什么 Django-ORM 使用 不同的时间 进行查询,那么指定的时间是什么?

我的时区设置(在 settings.py 中):

TIME_ZONE = 'Asia/Kolkata'
USE_I18N = True
USE_L10N = True
USE_TZ = True

我该如何解决这个问题,从 7:15:0015:44:00 获取当天所需的数据> ?注意:我正在使用 MySQL 数据库!!

models.py 文件

    from django.db import models

    class Visionsystem(models.Model):

        start_datetime = models.DateTimeField(db_column='Start_Datetime', blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'visionsystem'

【问题讨论】:

  • 你能展示你的 Visionsystem models.py 文件吗?
  • 另外,您的数据库使用的是 SQLite 还是 Postgres?
  • @NicoGriffioen 我已经添加了 models.py 文件的代码!!我正在使用 MySQL 数据库!

标签: django django-orm datetime-format


【解决方案1】:

MySql 不支持时区,它以 UTC 存储日期时间,而您的 django 应用程序时区是Asia/Kolkata (UTC +5:30)。

这里 django 在查询 MySQL 数据库之前会自动将您的应用程序时区转换为 UTC。这是有道理的,因为当您使用 django 应用程序保存数据时,它将日期时间转换为 UTC 时间,因此 07:15:00 Kolkata 时间将在 UTC 中存储为 01:45:00

解决方案:

您可以在 UTC 时区存储 MySql 数据,如果现有数据在 Kolkata 时区,则通过减去 -5:30 运行更新查询并将所有新数据保存在 UTC 时区。

如果您的应用程序不需要支持多个时区,您可以将应用程序时区更改为UTC。这是一个快速的解决方案,但不是一个好主意,因为时区信息会被截断。

【讨论】:

  • 由于某些限制(另一个应用程序写入此表),第一个解决方案对我来说不可行!探索第二个解决方案!
  • 实际上在这种情况下,您应该要求另一个应用程序团队将日期时间转换为 UTC 并存储在数据库中,因为这是数据错误。如果您不能请求它们,那么您可以使用切换 django 应用程序时区进行破解,TIME_ZONE = 'UTC'
【解决方案2】:

总之

  1. Django 将商店 UTC 保存在数据库中。
  2. 如果您没有提及时区,则会采用您在 settings.py 中提到的时区(在您的情况下,采用 Asia/Kolkata,因此 make_aware 函数假定您输入的日期时间带有时区 Asia/Kolkata。但是如步骤 1 所述,保存为 UTC。两个时间点指向同一时间 - 即 UTC 和 Asia/Kolkata 描述的时间相同)。
  3. 除了 1 和 2 之外,django 还将您的 timezone_aware 日期时间(即 min_dt_aware 和 max_dt_aware)转换为 UTC,以在查询执行期间确保查询的正确性。

这里有详细的解释。

时区概览

启用时区支持后,Django 以 UTC 格式将日期时间信息存储在数据库中,在内部使用时区感知的日期时间对象,并在模板和表单中将它们转换为最终用户的时区。

值显示为UTC,在SQL查询中打印:

import pytz
utc = pytz.UTC
# Print the utc value of min_dt_aware and max_dt_aware
print(min_dt_aware.astimezone(utc), max_dt_aware.astimezone(utc))
# So, as you can see, these utc values are which you see in SQL queries.

【讨论】:

【解决方案3】:

您可以使用 timezone.now(),它对我有用。首先你需要导入时区,从 django.utils import timezone https://docs.djangoproject.com/en/3.1/topics/i18n/timezones/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 2018-05-21
    • 2018-12-05
    • 1970-01-01
    • 1970-01-01
    • 2011-12-11
    相关资源
    最近更新 更多