Django 部署準備之一SQLite遷移到MySQL

前言

Django開發的時候爲了方面,內置了sqlite數據庫,可以直接用,不用過多關心,直接ORM操作即可。

Mysql Sqlite
特點 爲服務端設計 輕量級,可嵌入手機應用
高併發 不能
佔用內存 比SQLite
適用性 服務器 手機,桌面應用

等我們Django業務基本開發完了,部署之前,我們最好把SQLite遷移到Mysql,現在本地Mac電腦爲例,操作一下遷移以及遇到的坑

安裝

方式一(手動安裝,不推薦)

- 下載地址:https://www.mysql.com/downloads/
- 滾動網頁至最下方,選擇`DOWNLOADS => MySQL  Community  Server`

跟着提示安裝後需要配置環境變量
不配置環境變量的話,執行mysql命令,必須在mysql的安裝目錄下,所以選擇配置環境變量。在終端中,進入到用戶目錄下,執行 vim .bash_profile 或者直接執行vim ~/.bash_profile ,按i進入編輯模式,添加如下內容,按esc,輸入:wq退出並保存。

# mysql
export PATH=${PATH}:/usr/local/mysql/bin
#快速啓動、結束MySQL服務, 可以使用alias命令
alias mysqlstart='sudo /usr/local/mysql/support-files/mysql.server start'
alias mysqlstop='sudo /usr/local/mysql/support-files/mysql.server stop'

我們就可以在任何地方執行mysql命令了。

  • 終端輸入myqsl -u root -p啓動MySQL,安裝地址是/usr/local/mysql

方式二(Homebrew)

brew install mysql
# brew uninstall mysql
# brew list
mysql -V
mysql  Ver 8.0.18 for osx10.14 on x86_64 (Homebrew)

以上安裝成功默認是沒有密碼的,MySQL 8以上新增了安全配置引導,下面有介紹,如果不想設置密碼,可以直接進入

mysql -u root -p
直接回車即可

MySQL 密碼安全設置

MySQL 8新增了安全設置嚮導,對於在服務器部署MySQL來說,簡化了安全設置的操作。

  1. 密碼強度驗證插件
  2. 修改root賬號密碼
  3. 移除匿名用戶
  4. 禁用root賬戶遠程登錄
  5. 移除測試數據庫(test)
  6. 重新加載授權表
  • 示例
/usr/local/opt/mysql/bin/mysql_secure_installation # mysql 提供的配置嚮導

Securing the MySQL server deployment.

Enter password for user root:

VALIDATE PASSWORD COMPONENT can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD component?

Press y|Y for Yes, any other key for No: no
#這裏我選了不安全密碼強度驗證插件

Using existing password for root.
Change the password for root ? ((Press y|Y for Yes, any other key for No) : no
#這裏我選了不修改root密碼
 ... skipping.
 
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : yes
Success.
#這裏我選擇了移除匿名用戶


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : yes
Success.
#這裏我選擇了禁用root賬號遠程登錄訪問

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.

Remove test database and access to it? (Press y|Y for Yes, any other key for No) : no
 ... skipping.
 #這裏我選擇了不移除測試數據庫
 
Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : yes
Success.
#這裏我選擇了重新加載權限表,因爲我前面選擇了禁用root賬號遠程登錄訪問

All done!

MySQL忘記了Root密碼操作(em…這個真的很重要)

MySQL官網鏈接忘記密碼操作
這裏看下除了Window的其他系統如何操作。
1.如果有不要,請先停止MySQL相關服務。

ps -ef | grep mysql

1118089483  2247     1   0  3:12下午 ttys000    0:00.02 /bin/sh /usr/local/Cellar/mysql/8.0.18/bin/mysqld_safe --datadir=/usr/local/var/mysql --pid-file=/usr/local/var/mysql/FVFXGM44HV29.pid
1118089483  2358  2247   0  3:12下午 ttys000    0:04.24 /usr/local/Cellar/mysql/8.0.18/bin/mysqld --basedir=/usr/local/Cellar/mysql/8.0.18 --datadir=/usr/local/var/mysql --plugin-dir=/usr/local/Cellar/mysql/8.0.18/lib/plugin --log-error=FVFXGM44HV29.err --pid-file=/usr/local/var/mysql/FVFXGM44HV29.pid
1118089483  2522  2154   0  3:24下午 ttys000    0:00.01 grep mysql

如果有相關進程,需要關閉
mysql.service stop

# kill pid 

2.--skip-grant-tables啓動
該方法重啓,任何人都無需密碼就可以使所有的權限,因此,我們會跟上--skip-networking阻止遠程鏈接

/usr/local/bin/mysqld --skip-grant-tables --skip-networking &

3.修改密碼
這裏直接alter是會報錯的,需要先刷新權限

mysql> FLUSH PRIVILEGES;
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';
mysql> show columns from user; # 查看列  desc 表名;
mysql> select host, user, authentication_string from user;  # 查看信息

4.這裏的密碼默認都是高強度的,別入你之前通過安全設置設置過,你可以修改對應的全局密碼管理設置

mysql> show variables like 'validate_password%';
+--------------------------------------+--------+
| Variable_name                        | Value  |
+--------------------------------------+--------+
| validate_password.check_user_name    | ON     |
| validate_password.dictionary_file    |        |
| validate_password.length             | 8      |
| validate_password.mixed_case_count   | 1      |
| validate_password.number_count       | 1      |
| validate_password.policy             | MEDIUM |
| validate_password.special_char_count | 1      |
+--------------------------------------+--------+
7 rows in set (0.00 sec)

mysql> 

這裏看到倒數第二條是MEDIUM,我們需要改成LOW,修改密碼強度

SET GLOBAL validate_password.policy=LOW;

然後修改密碼位數

SET GLOBAL validate_password.length=6;

現在可以爲MySQL設置簡單密碼了,只要滿足六位的長度即可,

ALTER USER 'root'@'localhost' IDENTIFIED BY 'MyNewPass';

重啓

mysql.server restart
#也可以使用命令:brew services restart mysql
#不過建議使用命令:mysql.server restart在出錯時可以看到更準確完整的信息

建表

我們開發時用的SQLite數據庫,在生產部署之前都要把本地的數據表遷移到MySQL去。由於MySQL的密碼強度問題,經常忘記密碼的同學直接去上面的知識點操作一下。下面開始建數據庫,準備配置到Django的setting.py中去。

ps -ef | grep mysql
# 沒啓動就啓動
mysql.service start
# 進入
mysql -u root -p
# 查看
show databases;
# 開始創建
create database mikejingsitedb charset=utf8mb4 default collate utf8mb4_unicode_ci;

看到這裏有些小夥伴會覺得有點不對啊,一般的操作是create database xxx charset=utf8,這裏花裏胡哨的操作的參數,下面介紹下

collate和charset用法

default collate utf8mb4_unicode_ci; 介紹collate之前先說個題外話,大家應該都很熟悉,mysql中utf8和utf8mb4兩種編碼,可以這麼說吧,大家可以忘記這個utf8這個東西,永遠使用utf8mb4,這是MySQL的遺留問題,utf8最多支持3bytes字節長度的字符編碼,對於一些需要佔據4個字節的文字,比如emoji表情,mylsqutf8就不支持了,要使用utf8mb4才行。

所謂collate utf8mb4_unicode_ci,通俗的翻譯爲校驗通過utf8超集,utf8mb4(utf8 mobile 4bytes)的unicode編碼,而且是case insensitive(忽略大小寫,還有個縮寫是cs=case sensitive,顧名思義開始需要比較大小寫)。對於MySQL中那些類型字段,如VARCHAR,CHAR,TEXT類型的列,都需要一個COLLATE類型來告訴他們排序的規則。簡而言之,COLLATE會影響到ORDER BY語句的順序,會影響到WHERE條件中大於小於號篩選出來的結果,會影響DISTINCTGROUP BYHAVING語句的查詢結果。凡是涉及到排序,比較的地方,都會和COLLATE有關。

詳細的介紹可以查看這個文章

MySQL字符編碼

有了上面的介紹,我們就需要在my.cnf(Mac) my.ini(Windows)進行字符集配置。
默認字符集使用utf8mb4版本

#修改配置文件
vim /usr/local/etc/my.cnf

[mysqld]
...
[mysql]
# 設置mysql客戶端默認字符集
default-character-set=utf8mb4
[client]
default-character-set=utf8mb4

character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
  • 重啓查看
mysql.server restart
#也可以使用命令:brew services restart mysql
#不過建議使用命令:mysql.server restart在出錯時可以看到更準確完整的信息

MySQL不同版本加密方式兼容

1.配置文件修改
MySQL 8.0默認是cacheing_sha2_password 5.7和5.6是mysql_native_password,爲了兼容設置如下把默認加密方式改成default_authentication_plugin = mysql_native_password

新版本如果你用Navicat去鏈接,就會報錯

2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_sha2_password.so, 2): image not found

編輯vim /usr/local/etc/my.cnf插入一條數據
default_authentication_plugin=mysql_native_password
上面的這種方案對已有的賬戶是無法修改的,只是後續新增的賬戶就會默認的Plugin變成mysql_native_password
在這裏插入圖片描述
2.sql修改

ALTER USER 'root'@'localhost' IDENTIFIED BY 'password' PASSWORD EXPIRE NEVER; #修改加密規則 
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'password'; #更新一下用戶的密碼 
FLUSH PRIVILEGES; #刷新權限

因此,後面授權新用戶的方式可以在後面跟一個加密方式,默認是跟着配置文件走

create user 'root'@'localhost' identified WITH mysql_native_password BY 'password';
grant all privileges on *.* to root@'localhost' with grant option;
flush privileges;

時區問題(後面啓動博客就能遇到)

這裏先把數據庫的時區問題解決了
macOS。這些文件的一個可能位置是/usr/share/zoneinfo 目錄 導入mysql數據時區

mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql -p

導入後可以通過下面兩個方式查看時區是否正確

select timediff(now(),convert_tz(now(),@@session.time_zone,'+00:00')); 
SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP); 

# 如果是中國標準時間, 會輸出08:00

配置Django的數據庫爲MySQL

create database mikejingsitedb charset=utf8mb4 default collate utf8mb4_unicode_ci;
1.上面已經創建好了數據庫,開始配置settings.py

# DATABASES = {
#     'default': {
#         'ENGINE': 'django.db.backends.sqlite3',
#         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
#     }
# }
# mikejingsitedb    mkjkejingsitedb2
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql', # 後端數據庫引擎
        'NAME': 'mkjkejingsitedb2', # Django對應mysql數據庫的名字
        'USER': 'mkj', # 用戶
        'PASSWORD': 'M@ikejing123', # 密碼
        'HOST': 'localhost', # ip
        'PORT': '3306', # 端口
    }
}

注意分配用戶:
我們上面的操作都是MySQL的root用戶,有最高權限,不能直接寫在這裏,因此需要分配對應數據庫權限的用戶。

# 查看用戶
select host, user from user;

# 創建新用戶
create user 'xxx'@'localhost' identified by 'xxxx';
grant all privileges on mikejingsitedb.* to 'mkj'@'localhost'; # 分配mikejingsitedb的所有表權限
flush privileges; # 刷新

# 修改已有權限用戶
# grant all privileges on mikejingsitedb.* to '已有用戶'@'localhost'; # 分配mikejingsitedb的所有表權限
# flush privileges; # 刷新

# 登錄查看
mysql -u mkj -p 
show databases; # 只能查看對應的數據庫

2.啓動測試
如果這個時候直接運行python manager.py runserver會提示沒有遷移,先執行python manager.py migrate執行遷移。這裏正常情況下就會報錯了,因爲Django不同版本的數據庫操作類不同,提示是沒有clientmysql類似的這種中,Mac中你直接安裝pip install xxx也會安裝不上,Windows會有whl版本直接安裝編譯好的插件。Mac網上那些文章都是直接安裝pip install pymysql但是後續的問題就來了。

解決方法:
Django連接MySQL時默認使用MySQLdb驅動,但MySQLdb不支持Python3,因此這裏將MySQL驅動設置爲pymysql,使用 pip install pymysql 進行安裝,然後在工程文件__init__.py添加以下代碼即可。

#安裝pymysql
pip install pymysql

#__init__.py
import pymysql
pymysql.install_as_MySQLdb()

又會報錯

django2.2/mysql ImproperlyConfigured: mysqlclient 1.3.13 or newer is
required; you have 0.9.3

第一種:
django降到2.1.4版本就OK了
第二種:修改源碼
在這裏插入圖片描述

# 找到base.py文件,註釋掉 base.py 中如下部分(35/36行)
if version < (1, 3, 3):
     raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)

此時還不夠,依然會報錯AttributeError: ‘str’ object has no attribute ‘decode’

#找到operations.py文件(46行,版本不同行數不同哈~自個兒find一下),將decode改爲encode
#linux vim 查找快捷鍵:?decode
if query is not None:
    query = query.decode(errors='replace')
return query
#改爲
if query is not None:
    query = query.encode(errors='replace')
return query

OK,問題解決,可以進行遷移了。

3.執行遷移
python manager.py migrate,可以看到log都是成功的,就說明表遷移成功。

4.SQLite數據導出,導入MySQL

# 打開settings.py 的 sqlite註解 註釋掉mysql 導出
python manager.py dumpdata > data.json

# 打開settings.py 的 mysql註解 註釋掉sqlite 導入
python manage.py loaddata data.json

確保Mysql用戶表裏爲空的,如果之前有遷移過數據到Mysql,有可能會出錯。注意出錯的時候所報的錯誤信息。如果提示有重複主鍵,那需要先刪掉數據。這些數據是在給MySQL數據庫應用遷移文件的時候產生的,一般是content_type相關的表。

use 你的數據庫名;
delete from auth_permission;
delete from django_content_type;

繼續導入

python manage.py loaddata data.json
Installed 1057 object(s) from 1 fixture(s)

這裏導入數據,如果你編碼問題,就會遇到各種報錯,比如這種編碼問題報錯
我們建庫的時候已經制定了utf8mb4,可以看下實際的表數據
在這裏插入圖片描述

成功入庫,這個時候如果你用到的緩存表來緩存數據,記得在執行下

python manager.py createcachetable
python manager.py runserver

遷移成功,能看到我之前的博客網站數據都正常,而且也能登錄,搞定。那麼到時候部署到服務器,也是一樣的操作

參考文章:
SQL查詢語句相關模糊搜索
修改root密碼
優雅的忘記密碼
MySQL安裝
官網忘記密碼介紹
django2.2/mysql ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.3
mysql時區查詢
mysql時區導入
數據庫遷移中文資料
COLLATE和utf8mb4
Python3出現"No module named ‘MySQLdb’"問題-以及使用PyMySQL連接數據庫

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章