日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無先后,達(dá)者為師

網(wǎng)站首頁 編程語言 正文

Django切換數(shù)據(jù)庫和遷移數(shù)據(jù)詳解_python

作者:程序設(shè)計(jì)實(shí)驗(yàn)室 ? 更新時(shí)間: 2022-12-11 編程語言

前言

今天來分享一下 Django 項(xiàng)目切換數(shù)據(jù)庫和遷移數(shù)據(jù)的方案,網(wǎng)絡(luò)上找到的文章方法不一,且使用中容易遇到各類報(bào)錯(cuò),本文根據(jù) Django 官方文檔和工作中的經(jīng)驗(yàn),穩(wěn)定可靠,在博客中長期更新~

如果你遇到同樣的問題,閱讀本文應(yīng)該能得到比較好的解決方案。

基本步驟

Django 默認(rèn)使用 SQLite 數(shù)據(jù)庫方便開發(fā),同時(shí)其 ORM 支持多種數(shù)據(jù)庫,只要安裝對(duì)應(yīng)的驅(qū)動(dòng)就行。

切換數(shù)據(jù)庫一般是將開發(fā)環(huán)境的 SQLite 切換到 MySQL (MariaDB) 或 PostgreSql ,本文只測試了從 SQLite 到 MySQL / PostgreSQL,同理,其他切換路徑也是可以的。

數(shù)據(jù)庫的表結(jié)構(gòu)沒啥問題,使用 Django 的 migrate 功能就行了

關(guān)鍵在于數(shù)據(jù)遷移,可以使用 Navicat 之類的數(shù)據(jù)庫工具進(jìn)行數(shù)據(jù)同步,但往往會(huì)因?yàn)楸碇g的約束關(guān)系導(dǎo)致同步失敗(要求按特定順序?qū)霐?shù)據(jù))。

所以最好的方法是使用 Django 的?dumpdata?功能,將數(shù)據(jù)庫導(dǎo)出為 json 或 xml 文件,然后切換數(shù)據(jù)庫再導(dǎo)入。

步驟如下:

  • 導(dǎo)出原有數(shù)據(jù):?python manage.py dumpdata -o db.json
  • 在目標(biāo)數(shù)據(jù)庫(MySQL / PostgreSql)里創(chuàng)建一個(gè)空的庫
  • 在?settings.py?里切換到新的數(shù)據(jù)庫
  • 建立新的數(shù)據(jù)庫表結(jié)構(gòu)?python manage.py migrate
  • 導(dǎo)入原有數(shù)據(jù):?python manage.py loaddata db.json

搞定~

附上幾種數(shù)據(jù)庫配置,方便使用

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': '數(shù)據(jù)庫名稱',
        'USER': '用戶名',
        'PASSWORD': '密碼',
        'HOST': '數(shù)據(jù)庫服務(wù)器地址',
        'PORT': 5432,
    },
    'mysql': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': '數(shù)據(jù)庫名稱',
        'USER': '用戶名',
        'PASSWORD': '密碼',
        'HOST': '數(shù)據(jù)庫服務(wù)器地址',
        'PORT': 3306,
    }
}
# 這里可以方便切換不同數(shù)據(jù)庫
DATABASES = {'default': db_config['pgsql']}

其中:

  • MySQL 需要安裝?mysqlclient?包
  • PostgreSql 需要安裝?psycopg2?

然后,事情往往沒有這么簡單和順利,導(dǎo)出導(dǎo)入的過程中可能會(huì)遇到一些問題,請(qǐng)繼續(xù)看~

導(dǎo)出報(bào)錯(cuò)

報(bào)錯(cuò)信息

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

原因跟編碼有關(guān)

解決方法

使用 Python 的 UTF-8 模式導(dǎo)出數(shù)據(jù)就沒問題

用這個(gè)命令導(dǎo)出文件

(不導(dǎo)出?auth.permission?和?contenttypes?,這倆在?migrate?時(shí)會(huì)自動(dòng)生成,這樣避免了導(dǎo)入原有數(shù)據(jù)時(shí)沖突)

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

或者

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

導(dǎo)入過程出錯(cuò)解決

報(bào)錯(cuò)1: Duplicate entry

報(bào)錯(cuò)信息

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'")

解決方法一: 重新導(dǎo)出數(shù)據(jù)

加上這倆參數(shù)

  • --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.

作用是導(dǎo)出的時(shí)候去除一些約束,導(dǎo)入時(shí)會(huì)自動(dòng)處理,減少導(dǎo)入時(shí)因?yàn)楸碇g約束關(guān)系的問題

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

解決方法二: 刪除?content_type?數(shù)據(jù)

另一種思路,把?migrate?過程產(chǎn)生的初始化數(shù)據(jù)刪了,避免導(dǎo)入時(shí)和原有數(shù)據(jù)沖突

先進(jìn)入 python shell

python3 manage.py shell

輸入以下Python代碼執(zhí)行

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

報(bào)錯(cuò)2: 編碼錯(cuò)誤

報(bào)錯(cuò)信息

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

解決方法一: 使用 Python 的 UTF8 模式(推薦)

在導(dǎo)入命令前面加上?-Xutf8?參數(shù)

python -Xutf8 manage.py loaddata db.json

解決方案二: 魔改 Django 代碼

能用,但不推薦,實(shí)在沒辦法再來試這個(gè)方法

修改文件

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')

再進(jìn)行導(dǎo)入操作

參考資料

  • https://docs.djangoproject.com/en/4.1/ref/django-admin/
  • https://www.shubhamdipt.com/blog/django-transfer-data-from-sqlite-to-another-database/
  • https://javaatpoint.com/solved-unicodedecodeerror-utf-8-codec-cant-decode-byte-0xff-in-position-0-invalid-start-byte/
  • https://counter2015.com/2020/01/15/django-migration-sqlite-to-postgre/
  • https://stackoverflow.com/questions/64457733/django-dumpdata-fails-on-special-characters

原文鏈接:https://www.cnblogs.com/deali/p/16884908.html

欄目分類
最近更新