Introduction
Refer to the following article for the problem of Django2 connecting to MySQL and the solution of modifying the source code:
The interaction between Django and MySQL
However, there are many problems when the above source code modification method is used in the production environment.
This article explains in detail how to solve this problem without modifying Django source code.
Source code analysis in Django
Let's take a look at the source code of the django package for MySQL configuration in the Python interpreter we use (which can be global or virtual environment).
The source location is:
(your Python interpreter installation directory or virtual environment directory) django21 \ lib \ site packages \ Django \ DB \ backends \ MySQL \ base.py
There are a lot of contents in this base.py file. Let's pick out the most important parts to explain:
""" MySQL database backend for Django. Requires mysqlclient: https://pypi.org/project/mysqlclient/ # If not installed before, you need to download mysqlclient package from pypi """ 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 # Import MySQL DB module except ImportError as err: raise ImproperlyConfigured( 'Error loading MySQLdb module.\n' '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 # Print this 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...
We can see that the source code limits the version of MySQL DB module!
Restrictions of Django version 1.11.20 on the version of MySQL DB
The version limit in Django version 1.11.20 is above 1.2.3:
Django 2.1 and above restrictions on the version of MySQL DB
Above 1.3.7:
Version printed when program runs successfully
If the project runs successfully, the MySQL DB version must be greater than 1.3.7
So: the key to solve this problem is to solve the version of the native MySQL DB module! django2 must be greater than 1.3.7!
Problems of MySQL DB module
In Django source code, let's print the Database (in fact, MySQL dB):
try: import MySQLdb as Database # Print this Database print(Database,type(Database)) except ImportError as err: raise ImproperlyConfigured( 'Error loading MySQLdb module.\n' 'Did you install mysqlclient?' ) from err
The result is unexpected!!!
yes! You are not wrong! The module displayed is: pymysql (print 2 times in DEBUG mode)!!!
Here is the key to solving the problem!
pymysql source code analysis***
Then, when you look back, we added two lines of pymysql related code in the init.py file of the module with the same name as the project:
import pymysql # The import module is equivalent to executing the__init__.py file pymysql.install_as_MySQLdb() # implement pymysql Of install_as_MySQLdb Method
Then let's take a look at the source code of the file "init". Py "in the pymysql package installed in the current virtual environment:
""" PyMySQL: A pure-Python MySQL client library. ### Description omitted """ 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) # Version of 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): # ellipsis
# ellipsis def Binary(x): """Return x as a binary type.""" # ellipsis
def Connect(*args, **kwargs): """ Connect to the database; see connections.Connection.__init__() for more information. """ # ellipsis
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()
### Here's the key def install_as_MySQLdb(): """ After this function is called, any application that imports MySQLdb or _mysql will unwittingly actually use pymysql. """
### Importing mysql dB and mysql is equivalent to importing pymysql module!!! sys.modules["MySQLdb"] = sys.modules["_mysql"] = sys.modules["pymysql"] __all__ = [ # Omitted ]
One of them is very critical. According to the contents of the install as MySQL DB function, you can see:
Importing MySQL DB module in this environment is equivalent to importing pymysql module.
That is to say, in Django's base.py file, version = database.version info, actually pymysql.version info is used. From the source code of pymysql, we can see that the value of version info is (1, 3, 12, 'final', 0), which is the same as the result printed in our figure above!
This also explains why the pymysql module is displayed when we print the Database.
Solve with the appropriate version of pymysql
Through the above source code analysis, I believe you have come up with a solution: use the corresponding version of pymysql module for different versions of Django!
From the source code of pymysql above, we can see that the VERSION of pymysql is VERSION 0.9.3, and the corresponding VERSION of MySQL DB is set to 1.3.12, which is higher than the specified VERSION of 1.3.7, which can solve the problem of error reporting!
Using pypi to install the specified version of pymysql
Of course, in the case of networking, we can directly use pip to install the specified version of pymysql:
pip install pymysql==0.9.3 -i https://pypi.douban.com/simple
In fact, your server may not be allowed to connect to the Internet. Here is how to install pypi.
Enter pypi official website to search corresponding modules
pypi's official website is: https://pypi.org/
Then search the corresponding module:
Find the corresponding version
Find the corresponding version
Click download files
Select files of different formats
The file format is basically *. whl or *. tar.gz
Installation method of what file and tar package
The installation method of what file
[root@mycentos ~]# /opt/py3.6/ve1/bin/pip install xxx.whl
Installation method of tar package
Extract and enter the directory first
tar -xzvf xxx.tar.gz
cd xxx
Execute the installation command (the directory of the virtual environment needs to be used when installing in the virtual environment)
/opt/py3.6/ve1/bin/python setup.py install
be accomplished!