刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」引子 关于Django2版本连接MySQL发生的问题以及修改源码的解决方法参考下面这篇文章: Django与MySQL的交互 但是,上面这种修改源码的方法在生产环境中使用的话会有很多问题。 本文为大家

刨根问底,完美解决Django2版本连接MySQL报错的问题

引子

关于Django2版本连接MySQL发生的问题以及修改源码的解决方法参考下面这篇文章:

Django与MySQL的交互

但是,上面这种修改源码的方法在生产环境中使用的话会有很多问题。

本文为大家详细讲解如何在不修改Django源码的情况下解决这个问题。

Django中的源码解析

我们来看一下我们使用的Python解释器(可以是全局的也可以是虚拟环境的)中django包有关MySQL配置的源码。

源码位置是:

(你的Python解释器安装目录或者虚拟环境目录)django21Libsite-packagesdjangodbackendsmysqlbase.py

代码100分

这个base.py文件中的内容有点多,我们把最关键的部分挑出来解释一下:

代码100分"""
MySQL database backend for Django.

Requires mysqlclient: https://pypi.org/project/mysqlclient/ # 之前没安装的话得从pypi中下载mysqlclient包 """
import re

from django.core.exceptions import ImproperlyConfigured
from django.db import utils
from django.db.backends import utils as backend_utils
from django.db.backends.base.base import BaseDatabaseWrapper
from django.utils.functional import cached_property

try:
    import MySQLdb as Database # 导入MySQLdb模块 except ImportError as err:
    raise ImproperlyConfigured(
        "Error loading MySQLdb module.
"
        "Did you install mysqlclient?"
    ) from err

from MySQLdb.constants import CLIENT, FIELD_TYPE                # isort:skip
from MySQLdb.converters import conversions                      # isort:skip

# Some of these import MySQLdb, so import them after checking if it"s installed.
from .client import DatabaseClient                          # isort:skip
from .creation import DatabaseCreation                      # isort:skip
from .features import DatabaseFeatures                      # isort:skip
from .introspection import DatabaseIntrospection            # isort:skip
from .operations import DatabaseOperations                  # isort:skip
from .schema import DatabaseSchemaEditor                    # isort:skip
from .validation import DatabaseValidation                  # isort:skip
 version = Database.version_info
# 打印一下这个version print("version>>>>>>",version) if version < (1, 3, 7):
    raise ImproperlyConfigured("mysqlclient 1.3.7 or newer is required; you have %s." % Database.__version__)

###################
and so on...

我们可以看到,源码中对MySQLdb模块的版本进行了限制!

django1.11.20版本对MySQLdb的version的限制

在django1.11.20版本中的version限制是1.2.3以上:

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

django2.1及以上对MySQLdb的version的限制

是1.3.7以上:

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

成功运行程序时打印的版本

项目成功运行的话,MySQLdb的版本必须大于1.3.7才可以:

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

所以:解决这个问题的关键在于得解决本机MySQLdb模块的版本!用django2的话必须大于1.3.7!

MySQLdb模块的问题

还是在Django源码里面,我们打印一下这个Database(其实就是MySQLdb):

try:
    import MySQLdb as Database
    # 打印一下这个Database
    print(Database,type(Database)) except ImportError as err:
    raise ImproperlyConfigured(
        "Error loading MySQLdb module.
"
        "Did you install mysqlclient?"
    ) from err

结果出乎意料!!!

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

是的!你没有看错!显示的模块竟然是:pymysql(打印2次是在DEBUG模式下的设置)!!!

这里才是解决问题的关键所在!

pymysql源码解析 ***

然后大家回过头来想一下,我们配置的时候,在与项目同名的那个模块的__init__.py文件中加入了2行与pymysql相关的代码:

代码100分import pymysql  # 导入模块相当于执行了这个包中的__init__.py文件

pymysql.install_as_MySQLdb() # 执行pymysql的install_as_MySQLdb方法

然后我们来看一下当前虚拟环境中安装的pymysql包中的__init_.py文件的源码:

"""
PyMySQL: A pure-Python MySQL client library.

### 说明略去
"""
import sys

from ._compat import PY2
from .constants import FIELD_TYPE
from .converters import escape_dict, escape_sequence, escape_string
from .err import (
    Warning, Error, InterfaceError, DataError,
    DatabaseError, OperationalError, IntegrityError, InternalError,
    NotSupportedError, ProgrammingError, MySQLError)
from .times import (
    Date, Time, Timestamp,
    DateFromTicks, TimeFromTicks, TimestampFromTicks)

# pymysql的版本
VERSION = (0, 9, 3, None) if VERSION[3] is not None:
    VERSION_STRING = "%d.%d.%d_%s" % VERSION
else:
    VERSION_STRING = "%d.%d.%d" % VERSION[:3]
threadsafety = 1
apilevel = "2.0"
paramstyle = "pyformat"


class DBAPISet(frozenset):

    # 省略

# 省略 def Binary(x): """Return x as a binary type.""" # 省略

def Connect(*args, **kwargs): """ Connect to the database; see connections.Connection.__init__() for more information. """ # 省略

from . import connections as _orig_conn if _orig_conn.Connection.__init__.__doc__ is not None: Connect.__doc__ = _orig_conn.Connection.__init__.__doc__ del _orig_conn def get_client_info(): # for MySQLdb compatibility version = VERSION if VERSION[3] is None: version = VERSION[:3] return ".".join(map(str, version)) connect = Connection = Connect # we include a doctored version_info here for MySQLdb compatibility version_info = (1, 3, 12, "final", 0) NULL = "NULL" __version__ = get_client_info() def thread_safe(): return True # match MySQLdb.thread_safe()

### 这里是最关键的 def install_as_MySQLdb(): """ After this function is called, any application that imports MySQLdb or _mysql will unwittingly actually use pymysql. """
### 导入MySQLdb、_mysql其实相当于导入了pymysql模块!!! sys.modules["MySQLdb"] = sys.modules["_mysql"] = sys.modules["pymysql"]
__all__ = [ # 略去 ]

其中有个地方十分关键,根据 install_as_MySQLdb 函数中的内容可以看到:

在这个环境中导入MySQLdb模块相当于导入了pymysql模块。

也就是说,在Django的那个base.py文件中的  version = Database.version_info,其实用的是pymysql.version_info,从pymysql的源码中我们可以看到,里面的version_info的值为(1, 3, 12, “final”, 0),跟我们上图中打印的结果是一样的!

这也就解释了了为什么我们打印Database的时候显示的竟然是pymysql模块。

使用合适的pymysql的版本解决

通过上面的源码分析,相信聪明的你已经想出了解决方案了:针对不同版本的Django使用对应版本的pymysql模块就可以了!

从上面pymysql的源码可以看到:pymysql的版本是 VERSION为0.9.3,对应的MySQLdb的版本设置成了1.3.12,比规定的1.3.7高,可以解决报错问题!

使用pypi安装指定版本的pymysql

当然,在联网的情况下,我们可以直接使用pip安装指定版本的pymysql:

pip install pymysql==0.9.3 -i https://pypi.douban.com/simple

实际中大家的服务器可能会禁止连接外网,下面为大家介绍一下使用pypi安装的方法。

进入pypi官网搜索对应的模块

pypi的官网为:https://pypi.org/

然后搜索对应的模块:

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

寻找对应的版本

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

找到对应的版本 

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

点击DownloadFiles

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

选择不同格式的文件

文件的格式基本都是 *.whl 或者 *.tar.gz

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

使用scp命令传递文件

Linux scp命令

whl文件与tar包的安装方法

whl文件的安装方法

[root@mycentos ~]# /opt/py3.6/ve1/bin/pip  install  xxx.whl

tar包的安装方法

先解压并进入目录

tar -xzvf  xxx.tar.gz
cd xxx

执行安装命令 (虚拟环境中安装的话需要使用虚拟环境的目录)

/opt/py3.6/ve1/bin/python setup.py install

大功告成!

后记:关于Django2.2版本的问题

我试了一下,使用Django2.2版本的话,需要的MySQldb版本是 1.3.13,而0.9.3版本的pymysql不能支持,还是会报错的:

刨根问底,完美解决Django2版本连接MySQL报错的问题「建议收藏」

所以实际中建议大家选择合适的Django版本开发。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/8903.html

(0)
上一篇 2023-02-19
下一篇 2023-02-19

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注