• Django更换数据库和迁移数据方案


    前言#

    双十一光顾着买东西都没怎么写文章,现在笔记里还有十几篇半成品文章没写完…

    今天来分享一下 Django 项目切换数据库和迁移数据的方案,网络上找到的文章方法不一,且使用中容易遇到各类报错,本文根据 Django 官方文档和工作中的经验,稳定可靠,在博客中长期更新~

    如果你遇到同样的问题,阅读本文应该能得到比较好的解决方案。

    基本步骤#

    Django 默认使用 SQLite 数据库方便开发,同时其 ORM 支持多种数据库,只要安装对应的驱动就行。

    切换数据库一般是将开发环境的 SQLite 切换到 MySQL (MariaDB) 或 PostgreSql ,本文只测试了从 SQLite 到 MySQL / PostgreSQL,同理,其他切换路径也是可以的。

    数据库的表结构没啥问题,使用 Django 的 migrate 功能就行了

    关键在于数据迁移,可以使用 Navicat 之类的数据库工具进行数据同步,但往往会因为表之间的约束关系导致同步失败(要求按特定顺序导入数据)。

    所以最好的方法是使用 Django 的 dumpdata 功能,将数据库导出为 json 或 xml 文件,然后切换数据库再导入。

    步骤如下:

    • 导出原有数据: python manage.py dumpdata -o db.json
    • 在目标数据库(MySQL / PostgreSql)里创建一个空的库
    • settings.py 里切换到新的数据库
    • 建立新的数据库表结构 python manage.py migrate
    • 导入原有数据: python manage.py loaddata db.json

    搞定~

    附上几种数据库配置,方便使用

    db_config = {
        'sqlite': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
            'OPTIONS': {
                'timeout': 20,
            }
        },
        'pgsql': {
            'ENGINE': 'django.db.backends.postgresql',
            'NAME': '数据库名称',
            'USER': '用户名',
            'PASSWORD': '密码',
            'HOST': '数据库服务器地址',
            'PORT': 5432,
        },
        'mysql': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': '数据库名称',
            'USER': '用户名',
            'PASSWORD': '密码',
            'HOST': '数据库服务器地址',
            'PORT': 3306,
        }
    }
    # 这里可以方便切换不同数据库
    DATABASES = {'default': db_config['pgsql']}
    

    其中:

    • MySQL 需要安装 mysqlclient
    • PostgreSql 需要安装 psycopg2

    然后,事情往往没有这么简单和顺利,导出导入的过程中可能会遇到一些问题,请继续看~

    导出报错#

    报错信息

    CommandError: Unable to serialize database: 'gbk' codec can't encode character '\u30fb' in position 4: illegal multibyte sequence
    

    原因跟编码有关

    解决方法#

    使用 Python 的 UTF-8 模式导出数据就没问题

    用这个命令导出文件

    (不导出 auth.permissioncontenttypes ,这俩在 migrate 时会自动生成,这样避免了导入原有数据时冲突)

    python -Xutf8 manage.py dumpdata --exclude auth.permission --exclude contenttypes > db.json
    

    或者

    python -Xutf8 manage.py dumpdata -o db.json
    

    导入过程出错解决#

    报错1: Duplicate entry#

    报错信息#

    django.db.utils.IntegrityError: Problem installing fixture 'db.json'  Could not load contenttypes.ContentType(pk=15): (1062, "Duplicate entry 'xxx' for key 'django_content_type.django_content_type_app_label_model_76bd3d3b_uniq'")
    

    解决方法一: 重新导出数据#

    加上这俩参数

    • --natural-primary: Omits the primary key in the serialized data of this object since it can be calculated during deserialization.
    • --natural-foreign: Uses the natural_key() model method to serialize any foreign key and many-to-many relationship to objects of the type that defines the method.

    作用是导出的时候去除一些约束,导入时会自动处理,减少导入时因为表之间约束关系的问题

    python3 manage.py dumpdata --natural-primary --natural-foreign -o db.json
    

    解决方法二: 删除 content_type 数据#

    另一种思路,把 migrate 过程产生的初始化数据删了,避免导入时和原有数据冲突

    先进入 python shell

    python3 manage.py shell
    

    输入以下Python代码执行

    from django.contrib.contenttypes.models import ContentType
    ContentType.objects.all().delete()
    

    报错2: 编码错误#

    报错信息#

    UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xff in position 0: invalid start byte in Django
    

    解决方法一: 使用 Python 的 UTF8 模式(推荐)#

    在导入命令前面加上 -Xutf8 参数

    python -Xutf8 manage.py loaddata db.json
    

    解决方案二: 魔改 Django 代码#

    能用,但不推荐,实在没办法再来试这个方法

    修改文件

    lib\site-packages\django\core\serializers\json.py
    

    Deserializer 方法中找到这行代码

    stream_or_string = stream_or_string.decode()
    

    改成这样

    stream_or_string = stream_or_string.decode('UTF-16')
    

    再进行导入操作

    参考资料#

  • 相关阅读:
    excel内容通过apache poi读取后读出来为数字,转为日期类型
    【C语言刷题】快慢指针巧解带环单链表问题
    trick3-关于目标检测算法好坏的一些衡量指标
    如何通过EasyCVR接口监测日志观察平台拉流情况?
    红蓝对抗-攻防演练中红队如何识别蜜罐保护自己
    华为云云耀云服务器L实例评测|云耀云服务器L实例部署Gogs服务器
    vscode 插件配置推荐
    【openscreen 】FrameId
    C/C++内存管理(栈、堆区;malloc,new;内存泄漏等)
    net-java-php-python-阿克苏水果销售管理计算机毕业设计程序
  • 原文地址:https://www.cnblogs.com/deali/p/16884908.html