迁移概述
将Django项目从SQLite迁移到MySQL是项目成长过程中的常见需求。SQLite适合开发和测试,但生产环境通常需要MySQL提供更强的性能、并发处理能力和数据完整性保障。
迁移原理:Django的ORM层屏蔽了底层数据库差异,因此迁移过程主要是数据导出导入,而非修改业务代码。
迁移流程图
SQLite数据库
↓
导出数据 (dumpdata)
↓
处理编码问题(关键步骤)
↓
创建MySQL数据库
↓
修改Django配置
↓
导入数据 (loaddata)
↓
验证迁移结果
环境要求
| 组件 | 最低版本 | 推荐版本 | 说明 |
|---|---|---|---|
| Django | 3.2 | 4.2+ | Django 4.2+ 需要MySQL 8.0+ |
| MySQL | 5.7 | 8.0+ | Django 4.2+ 必须MySQL 8.0+ |
| Python | 3.8 | 3.10+ | Python MySQL驱动兼容性 |
| mysqlclient | 2.0 | 2.2+ | Python的MySQL连接库 |
重要警告:Django 4.2及以上版本必须使用MySQL 8.0或更高版本。使用MySQL 5.7会报错:
MySQL 8 or later is required (found 5.7.xx)
备份数据
迁移前务必备份!虽然Django的迁移过程相对安全,但备份能防止意外数据丢失。
备份SQLite数据库
bash
# 直接复制数据库文件
cp db.sqlite3 db.sqlite3.backup.$(date +%Y%m%d%H%M%S)
# Windows
copy db.sqlite3 db.sqlite3.backup.%date:~0,4%%date:~5,2%%date:~8,2%
备份到JSON(双重保险)
bash
# 导出所有数据
python manage.py dumpdata --natural-primary --natural-foreign > full_backup.json
# 排除contenttypes和auth权限(这些会自动生成)
python manage.py dumpdata --exclude contenttypes --exclude auth.permission > data_backup.json
步骤1:安装MySQL依赖
1
安装mysqlclient
bash
# 推荐安装方式
pip install mysqlclient
# 如果安装失败,尝试以下替代方案:
# 方案A:使用pymysql(纯Python实现)
pip install pymysql
# 然后在项目__init__.py中添加:
# import pymysql
# pymysql.install_as_MySQLdb()
# 方案B:使用mysql-connector-python(官方驱动)
pip install mysql-connector-python
# 然后在settings.py中修改ENGINE:
# 'ENGINE': 'mysql.connector.django',
Windows安装mysqlclient提示:如果安装失败,先下载安装 MySQL Connector/C,或直接使用pymysql替代方案。
步骤2:创建MySQL数据库
2
创建数据库和用户
SQL
-- 登录MySQL(使用root或管理员账号)
mysql -u root -p
-- 创建数据库(使用utf8mb4字符集支持emoji)
CREATE DATABASE django_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
-- 创建专用用户(推荐,不要使用root)
CREATE USER 'django_user'@'localhost'
IDENTIFIED BY 'your_secure_password';
-- 授权
GRANT ALL PRIVILEGES ON django_db.*
TO 'django_user'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
-- 验证
SHOW DATABASES;
SELECT user, host FROM mysql.user;
字符集说明:
utf8mb4 是完整的UTF-8实现,支持存储emoji表情和特殊字符。旧的 utf8 是阉割版,不建议使用。
步骤3:修改Django配置
3
修改settings.py
settings.py
# 原SQLite配置(注释掉或删除)
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
# }
# }
# 新MySQL配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db', # 数据库名
'USER': 'django_user', # 用户名
'PASSWORD': 'your_secure_password', # 密码
'HOST': 'localhost', # 主机地址
'PORT': '3306', # 端口(默认3306)
# 连接选项
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
# 连接池配置(可选)
'CONN_MAX_AGE': 600, # 连接持久化10分钟
}
}
# 如果使用pymysql替代方案,在文件顶部添加:
# import pymysql
# pymysql.install_as_MySQLdb()
测试连接
bash
# 验证配置是否正确
python manage.py check
# 如果出现错误,检查:
# 1. MySQL服务是否启动
# 2. 用户名密码是否正确
# 3. 数据库是否存在
步骤4:处理编码问题(关键步骤)
这是最容易出错的步骤!Windows系统默认使用GBK编码,而Django需要UTF-8,直接导出的文件可能包含乱码,导致导入失败。
4
确保导出文件为UTF-8编码
方案A:设置环境变量后导出(推荐)
PowerShell (Windows)
# 设置UTF-8编码环境
$env:PYTHONIOENCODING="utf-8"
# 然后导出数据
python manage.py dumpdata --natural-primary --natural-foreign --indent 2 > data.json
# 验证文件编码(使用VS Code或Notepad++打开,右下角应显示UTF-8)
CMD (Windows)
# 设置环境变量
set PYTHONIOENCODING=utf-8
# 导出数据
python manage.py dumpdata --natural-primary --natural-foreign --indent 2 > data.json
方案B:使用Python脚本导出(最可靠)
export_data.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import django
# 设置环境
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'your_project.settings')
sys.stdout = open('data.json', 'w', encoding='utf-8')
django.setup()
from django.core.management import call_command
# 导出数据
call_command('dumpdata',
'--natural-primary',
'--natural-foreign',
'--indent', '2',
'--exclude', 'contenttypes',
'--exclude', 'auth.permission'
)
print("数据已导出到 data.json (UTF-8编码)")
bash
python export_data.py
方案C:如果已有文件编码错误,使用修复脚本
如果导出后出现
UnicodeDecodeError: 'utf-8' codec can't decode byte... 错误,使用以下脚本修复:
fix_encoding.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
编码修复脚本 - 处理Windows导出的GBK编码文件
"""
import os
def fix_encoding():
# 读取原始文件(二进制模式)
with open('data.json', 'rb') as f:
raw_data = f.read()
# 尝试多种编码解码
encodings = ['utf-8', 'gbk', 'gb2312', 'gb18030', 'latin-1']
decoded_text = None
used_encoding = None
for encoding in encodings:
try:
decoded_text = raw_data.decode(encoding)
used_encoding = encoding
print(f"✓ 成功使用 {encoding} 解码")
break
except UnicodeDecodeError:
print(f"✗ {encoding} 解码失败")
continue
if decoded_text is None:
# 如果都失败,使用UTF-8忽略错误
decoded_text = raw_data.decode('utf-8', errors='ignore')
used_encoding = 'utf-8 (忽略错误)'
print("⚠ 使用UTF-8忽略错误解码,部分数据可能丢失")
# 保存为UTF-8
with open('data_fixed.json', 'w', encoding='utf-8') as f:
f.write(decoded_text)
print(f"\n✓ 已保存为 data_fixed.json")
print(f"✓ 原始编码: {used_encoding}")
print(f"✓ 文件大小: {os.path.getsize('data_fixed.json')} 字节")
# 验证JSON格式
import json
try:
with open('data_fixed.json', 'r', encoding='utf-8') as f:
json.load(f)
print("✓ JSON格式验证通过")
except json.JSONDecodeError as e:
print(f"✗ JSON格式错误: {e}")
if __name__ == '__main__':
fix_encoding()
bash
python fix_encoding.py
# 使用修复后的文件
python manage.py loaddata data_fixed.json
方案D:使用记事本手动转换(最简单)
- 用记事本打开
data.json - 点击"文件" → "另存为"
- 在编码下拉框中选择 UTF-8
- 保存为
data_fixed.json
验证编码:使用VS Code打开文件,右下角会显示当前编码。如果不是UTF-8,点击编码 → "通过编码保存" → 选择UTF-8。
步骤5:导出数据
5
从SQLite导出数据
确保此时Django配置仍然是SQLite!在导出前不要修改settings.py为MySQL配置。
bash
# 完整导出(包含所有数据)
python manage.py dumpdata --natural-primary --natural-foreign --indent 2 > data.json
# 排除系统自动生成的表(推荐)
python manage.py dumpdata \
--natural-primary \
--natural-foreign \
--exclude contenttypes \
--exclude auth.permission \
--exclude admin.logentry \
--exclude sessions.session \
--indent 2 > data.json
# 仅导出特定app数据
python manage.py dumpdata myapp1 myapp2 --indent 2 > data.json
参数说明:
--natural-primary:使用自然主键,避免ID冲突--natural-foreign:使用自然外键,保持关联关系--indent 2:格式化JSON,便于阅读和调试--exclude:排除不需要迁移的表
步骤6:导入数据
6
导入到MySQL
此时应该已经修改settings.py为MySQL配置,并且已经创建了数据库表结构(执行过migrate)。
创建表结构
bash
# 确保配置已改为MySQL
# 然后创建表结构
python manage.py migrate
# 如果出现MySQL版本错误,请升级MySQL到8.0+
导入数据
bash
# 使用修复后的UTF-8文件导入
python manage.py loaddata data_fixed.json
# 或者如果原始文件就是UTF-8
python manage.py loaddata data.json
# 导入特定文件
python manage.py loaddata mydata.json
导入顺序:如果有多个数据文件,按依赖顺序导入(先导入无依赖的,再导入有外键依赖的)。
步骤7:验证迁移
7
验证数据完整性
bash
# 1. 检查数据库连接
python manage.py dbshell
# 在MySQL shell中执行:
# SHOW TABLES;
# SELECT COUNT(*) FROM auth_user;
# 2. 检查数据量
python manage.py shell
>>> from myapp.models import MyModel
>>> MyModel.objects.count() # 应该与SQLite中相同
# 3. 运行测试
python manage.py test
# 4. 启动开发服务器测试
python manage.py runserver
# 访问 http://127.0.0.1:8000/admin 检查数据
创建超级用户(如果丢失)
bash
# 如果admin数据没有迁移,重新创建超级用户
python manage.py createsuperuser
常见问题:MySQL版本
错误信息:
django.db.utils.NotSupportedError: MySQL 8 or later is required (found 5.7.26).
解决方案
必须升级MySQL到8.0+,Django 4.2+不再支持MySQL 5.7。
升级步骤
# 1. 备份现有MySQL数据
mysqldump -u root -p --all-databases > mysql_backup.sql
# 2. 下载并安装MySQL 8.0
# https://dev.mysql.com/downloads/installer/
# 3. 恢复数据
mysql -u root -p < mysql_backup.sql
# 4. 验证版本
mysql --version
# 应该显示 8.0.x
如果不想升级MySQL,可以降级Django到3.2版本(最后一个支持MySQL 5.7的版本):
bash
pip install "Django>=3.2,<4.0"
常见问题:编码问题详解
错误信息:
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 1283: invalid start byte
问题原因
- Windows系统默认使用GBK编码
- Python输出重定向到文件时使用了系统默认编码
- Django的loaddata期望UTF-8编码
完整解决方案
参考 步骤4:处理编码问题 中的4种方案,推荐顺序:
- 方案B:Python脚本导出(最可靠)
- 方案A:设置环境变量后导出
- 方案D:记事本手动转换(最简单)
- 方案C:修复脚本(应急使用)
预防措施
永久设置UTF-8(Windows)
# 在系统环境变量中添加 PYTHONIOENCODING=utf-8
# 控制面板 → 系统 → 高级系统设置 → 环境变量 → 新建系统变量
# 或者在PowerShell配置文件中添加
$PROFILE # 查看配置文件路径
# 在文件中添加:$env:PYTHONIOENCODING="utf-8"
常见问题:外键约束错误
错误信息:
IntegrityError: (1452, 'Cannot add or update a child row: a foreign key constraint fails')
解决方案
导出时排除contenttypes
# 这些表会自动生成,不应导出导入
python manage.py dumpdata \
--exclude contenttypes \
--exclude auth.permission \
--exclude admin.logentry \
--exclude sessions.session \
> data.json
临时禁用外键检查(MySQL)
# 在导入前登录MySQL禁用外键检查
mysql -u django_user -p django_db
SET FOREIGN_KEY_CHECKS = 0;
-- 然后执行 loaddata
SET FOREIGN_KEY_CHECKS = 1;
其他常见问题
1. mysqlclient安装失败
解决方案
# Windows: 安装Visual C++ Build Tools
# https://visualstudio.microsoft.com/visual-cpp-build-tools/
# 或使用预编译版本
pip install mysqlclient-1.4.6-cp38-cp38-win_amd64.whl # 下载对应版本
# 或使用pymysql替代
pip install pymysql
# 在项目__init__.py中添加:
import pymysql
pymysql.install_as_MySQLdb()
2. 数据丢失或损坏
检查清单
# 1. 对比数据量
python manage.py shell
>>> from django.contrib.auth.models import User
>>> User.objects.count() # SQLite和MySQL应该相同
# 2. 检查特定记录
>>> User.objects.first().__dict__
# 3. 如果有丢失,检查JSON文件
python -c "
import json
with open('data.json', 'r', encoding='utf-8') as f:
data = json.load(f)
print(f'总记录数: {len(data)}')
users = [x for x in data if x['model'] == 'auth.user']
print(f'用户记录数: {len(users)}')
"
3. 字符集错误
解决方案
# 修改数据库字符集
ALTER DATABASE django_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
# 修改表字符集
ALTER TABLE myapp_mymodel CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
生产环境配置
连接池配置
settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_db',
'USER': 'django_user',
'PASSWORD': os.environ.get('DB_PASSWORD'), # 从环境变量读取
'HOST': os.environ.get('DB_HOST', 'localhost'),
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
'CONN_MAX_AGE': 600, # 连接持久化10分钟
'CONN_HEALTH_CHECKS': True, # Django 4.1+ 健康检查
}
}
安全建议
- 数据库密码使用环境变量,不要硬编码
- 使用专用数据库用户,不要使用root
- 限制数据库用户权限(仅需要的数据库)
- 启用SSL连接(生产环境)
- 定期备份数据库
迁移工具推荐
| 工具 | 适用场景 | 优点 | 命令 |
|---|---|---|---|
| dumpdata/loaddata | 标准迁移 | Django内置,跨数据库兼容 | python manage.py dumpdata/loaddata |
| sqlite3-to-mysql | 大数据量 | 直接转换,速度快 | sqlite3mysql -f db.sqlite3 -d mysql_db |
| MySQL Workbench | 可视化迁移 | 图形界面,易于操作 | GUI工具 |
| Navicat | 商业工具 | 功能强大,支持多种数据库 | GUI工具 |
sqlite3-to-mysql使用
# 安装
pip install sqlite3-to-mysql
# 基本用法
sqlite3mysql -f db.sqlite3 -d django_db -u django_user -p
# 指定主机和端口
sqlite3mysql -f db.sqlite3 -h localhost -P 3306 -d django_db -u django_user --mysql-password your_password
# 仅特定表
sqlite3mysql -f db.sqlite3 -d django_db -u django_user -t table1 table2 table3
迁移检查清单
完成迁移后,请确认以下事项:
- ☐ 所有数据表已创建
- ☐ 数据记录数与SQLite一致
- ☐ 外键关系正确
- ☐ 中文和特殊字符显示正常
- ☐ 应用程序功能正常
- ☐ 已删除或备份db.sqlite3
- ☐ 已更新生产环境配置
需要帮助?
如果在迁移过程中遇到问题,请检查:
- MySQL版本是否为8.0+
- 数据文件是否为UTF-8编码
- 数据库字符集是否为utf8mb4
- 用户权限是否正确
Django SQLite 到 MySQL 迁移指南
生成时间: 2026-03-10 | 适用于 Django 3.2+ 和 MySQL 8.0+