Django 故障排除

创建时间 2019-04-11
更新时间 2019-07-30

Django 时区操作

一般情况下,习惯了Linux的用户在 Django 开发中设置的时区是 Asia/Shanghai 也就是上海。

Django 开发过程中,使用时区的的情况下,设置 settings 中 USE_TZ = True,这样就会有两种时间,一种没有时区信息的,用 datetime 生成,一种带时区信息的,用 timezone.now 生成。

有时候需要在已经生成的时间进行转换,一种情况是已经有了时区,需要去掉,一种是没有时区,需要加上时区。更多的是没有时区,然后加上时区。

一种实现方式是,直接替换时区信息,如下所示

import datetime
from django.utils import timezone

time = datetime.datetime.now() # 没有时区
time = time.replace(tzinfo=timezone.get_default_timezone())

这样做有一些问题,就是北京时间比上海时间差6分钟,常常会有时间不准确的情况。打印出来的时间后面,显示的是 +08:06。为了去掉这个 06 可以使用本地化的方式,如下所示。

import datetime
from django.utils import timezone

time = datetime.datetime.now() # 没有时区
time =  timezone.get_default_timezone().localize(datetime)

如果时间已经有时区信息了,要想去掉那个 06 可以使用下面的方法,先去掉时区信息,然后再进行本地化,如下所示。

import datetime
from django.utils import timezone

def localize(datetime):
    if timezone.is_aware(datetime):
        datetime = datetime.replace(tzinfo=None)
    return timezone.get_default_timezone().localize(datetime)

django.db.utils.OperationalError: (2006, ‘MySQL server has gone away’)

首先,出现 MySQL server has gone away 错误的根本原因,是由于MySQL服务器超时,并关闭了与客户端的连接导致的。

默认情况下,如果8小时内对mysql没有请求的话,服务器就会自动断开。可以通过修改全局变量 wait_time 和 interactive_timeout 两个变量的值来进行修改。

不过,这里解释的是django的错误,所以这里只说明从django端来解决这个错误。

django默认情况下对于连接是持续的。但是MySQL端默认只有8个小时,所以要想解决这个问题很简单,在配置文件中修改mysql的最长连接时间就可以了。

所以修改 settings.py 文件如下,加入 CONN_MAX_AGE 选项:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'CONN_MAX_AGE': 3600,
        # 其他配置信息
    }
}

其中 3600 是django对于MySQL连接的最长时间,之后就重新连接。默认情况下 MySQL 数据库的超时时间是 28800,小于这个值应该就可以。

由于,django 连接超时的判断只会在请求发起是执行。所以如果程序的运行状态并不是web应用程序,而只是用到了django的ORM来处理数据,那么就需要手动判断连接是否有效,进而关闭不可用的连接,新建新的连接。具体的处理方法也很方便,示例如下:

from functions import wraps
from django.db import close_old_connections

def check_connection(func):

    @wraps(func)
    def check(*args, **kwargs):
        close_old_connections()
        return func(*args, **kwargs)
    return check

只需要调用 close_old_connections 函数就可以了,如果想要方便一点,可以定义如上装饰器,在用到数据库操作的地方检测一下就可以了。