迁移概述

将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:使用记事本手动转换(最简单)

  1. 用记事本打开 data.json
  2. 点击"文件" → "另存为"
  3. 在编码下拉框中选择 UTF-8
  4. 保存为 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

问题原因

完整解决方案

参考 步骤4:处理编码问题 中的4种方案,推荐顺序:

  1. 方案B:Python脚本导出(最可靠)
  2. 方案A:设置环境变量后导出
  3. 方案D:记事本手动转换(最简单)
  4. 方案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+ 健康检查
    }
}

安全建议

迁移工具推荐

工具 适用场景 优点 命令
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
  • ☐ 已更新生产环境配置
需要帮助?

如果在迁移过程中遇到问题,请检查:

  1. MySQL版本是否为8.0+
  2. 数据文件是否为UTF-8编码
  3. 数据库字符集是否为utf8mb4
  4. 用户权限是否正确

Django SQLite 到 MySQL 迁移指南

生成时间: 2026-03-10 | 适用于 Django 3.2+ 和 MySQL 8.0+