刨根問底,完美解決Django2版本連接MySQL報錯的問題

来源:https://www.cnblogs.com/paulwhw/archive/2020/04/21/12743793.html
-Advertisement-
Play Games

引子 關於Django2版本連接MySQL發生的問題以及修改源碼的解決方法參考下麵這篇文章: Django與MySQL的交互 但是,上面這種修改源碼的方法在生產環境中使用的話會有很多問題。 本文為大家詳細講解如何在不修改Django源碼的情況下解決這個問題。 Django中的源碼解析 我們來看一下我 ...


引子

關於Django2版本連接MySQL發生的問題以及修改源碼的解決方法參考下麵這篇文章:

Django與MySQL的交互

但是,上面這種修改源碼的方法在生產環境中使用的話會有很多問題。

本文為大家詳細講解如何在不修改Django源碼的情況下解決這個問題。

Django中的源碼解析

我們來看一下我們使用的Python解釋器(可以是全局的也可以是虛擬環境的)中django包有關MySQL配置的源碼。

源碼位置是:

(你的Python解釋器安裝目錄或者虛擬環境目錄)\django21\Lib\site-packages\django\db\backends\mysql\base.py

這個base.py文件中的內容有點多,我們把最關鍵的部分挑出來解釋一下:

"""
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.\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
# 列印一下這個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.1及以上對MySQLdb的version的限制

是1.3.7以上:

成功運行程式時列印的版本

項目成功運行的話,MySQLdb的版本必須大於1.3.7才可以:

所以:解決這個問題的關鍵在於得解決本機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.\n'
        'Did you install mysqlclient?'
    ) from err

結果出乎意料!!!

是的!你沒有看錯!顯示的模塊竟然是:pymysql(列印2次是在DEBUG模式下的設置)!!!

這裡才是解決問題的關鍵所在!

pymysql源碼解析 ***

然後大家回過頭來想一下,我們配置的時候,在與項目同名的那個模塊的__init__.py文件中加入了2行與pymysql相關的代碼:

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/

然後搜索對應的模塊:

尋找對應的版本

找到對應的版本 

點擊DownloadFiles

選擇不同格式的文件

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

使用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不能支持,還是會報錯的:

所以實際中建議大家選擇合適的Django版本開發。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在sqlserver中,幾年之前就註意到一個現象:sqlserver中對一個大表創建索引或者rebuild索引的過程中,會引起記憶體劇烈的動蕩,究其原因為何,這種現象到底正不正常,是不是sqlserver記憶體管理存在缺陷?另外,最近剛好想到跟MySQL對比一下類似操作引起的記憶體變化,測試MySQL會不 ...
  • 一、Win10 下載、安裝 Navicat 15 1、關閉安全中心的實時保護 因為 註冊機 可能會被系統判定為 有害文件,可能會自動刪除,所以先將實時保護關閉,再去使用註冊機激活,激活後,再打開實時保護。 Step1:打開 Window 安全中心。 Step2:點擊病毒和威脅防護,併進入管理設置頁面 ...
  • 通過寫SQL查詢,我們可以發現很多簡單查詢語句主要就是由一些算術操作、欄位操作、函數還有各種子句構成的,今天我們從這個角度對MySQL單表查詢的基礎知識進行一個彙總。 __計算:__ 計算欄位 算術操作符 算術計算 欄位拼接 格式化顯示 __函數:__ 統計函數 其他常用函數 __子句:__ 排序 ...
  • 筆者大學所學電腦專業,讀書時接觸過Oracle、mysql和SQL SERVER,一度坐井觀天覺得資料庫應該也就這些了,但自筆者畢業進入數據倉庫這個行業,接觸的第一個商業資料庫即是Teradata,亦是接觸到的第一個MPP體系架構,先簡單談談個人對Teradata的認識吧 產品特點: 1.MPP架 ...
  • MySQL安裝 1.先去官網下載安裝包 官網: http://www.mysql.com 要下載社區版(community) 選對系統,選對你要的安裝包版本 點擊後就可以下載mysql了 2.下載完壓縮包之後解壓,並把解壓後的文件放到自己要放的文件夾中(最好不要出現中文目錄), 找到該文件夾下的bi ...
  • Redis介紹: Redis 是完全開源免費的,遵守BSD協議,是一個高性能的key-value資料庫。 Redis 與其他 key - value 緩存產品有以下三個特點: Redis支持數據的持久化RDB和AOF,可以將記憶體中的數據保存在磁碟中,重啟的時候可以再次載入進行使用。 Redis不僅僅 ...
  • MySQL Structured Query Language SQL簡介 SQL (Structured Query Language) 是具有數據操 縱和數據定義等多種功能的資料庫語言,這種語言具有交互性特點,能為用戶提供極大的便利,資料庫管理系統應充分利用SQL語言提高電腦應用系統的工作質量 ...
  • 當Redis客戶端出現請求超時的時候,需要檢查該時間點是否有慢查詢,從而分析出由於慢查詢導致的命令級聯阻塞。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...