デフォルトのsqlite3をバックエンドDBにしたまま勢い良く作り始めたら、気がついたら結構データがたまって 動きが鈍くなったアプリがありました。
基本PostgreSQLが好きなのでSQLiteからSQL引っこ抜いてPostgreSQLにINSERTしないといけないと思っていたら
Djangoのmanage.py dumpdata
とmanage.py loaddata
で対応できそうだったので試してみました。
環境
移行前のsettings.py
なんとなくDB名だけは変えていてhh.db
という名前で作っていました。
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'hh.db'), } }
データを引っこ抜く
dumpdata
コマンドで現在のモデルのデータを抜けるようです。基本JSONみたいですね。--indent
で人が読みやすい形で出るので見てみます。
(django110) > python manage.py dumpdata --indent 4|head -n 20 [ { "model": "qq.category", "pk": 1, "fields": { "category_name": "xxxxxx", "color": "#FF4444" } }, { "model": "qq.category", "pk": 2, "fields": { "category_name": "xxxxx", "color": null } }, { "model": "qq.category", "pk": 3, :
まぁloadする時にインデントはいらないのでインデントを付けずにファイルに書き出します。
(django110) > python manage.py dumpdata > dump.json
DBの設定変更
loadする前にsettings.pyを変更し新しいDBを見るようにします。
(django110) > diff settings.py settings_before.py 81,86c81,82 < 'ENGINE': 'django.db.backends.postgresql_psycopg2', < 'NAME': 'djangodb', < 'USER': 'p961', < 'PASSWORD': '', < 'HOST': '192.168.99.155', < 'PORT': '9601' --- > 'ENGINE': 'django.db.backends.sqlite3', > 'NAME': os.path.join(BASE_DIR, 'hh.db'), 88a85 >
データを流し込む
準備ができたのでloaddata
でデータを流し込みます。
(django110) > python manage.py loaddata dump.json Traceback (most recent call last): : : File "C:\Program Files\Anaconda2\envs\django110\lib\site-packages\django\db\backends\utils.py", line 64, in execute return self.cursor.execute(sql, params) django.db.utils.ProgrammingError: Problem installing fixture 'C:\ProgramData\gitrepos\XXXXX\XXXXXXX\dump.json': Could not load qq.Category(pk=1): relation "qq_category" does not exist LINE 1: UPDATE "qq_category" SET "category_name" = 'XXXX', "color"... ^
relation "qq_category" does not exist
なので表がないって怒られました。先にmigrateしないとだめですね。
(django110) > python manage.py migrate
気を取り直してもう一度
(django110) > python manage.py loaddata dump.json : : File "C:\Program Files\Anaconda2\envs\django110\lib\site-packages\django\db\utils.py", line 94, in __exit__ six.reraise(dj_exc_type, dj_exc_value, traceback) File "C:\Program Files\Anaconda2\envs\django110\lib\site-packages\django\db\backends\utils.py", line 64, in execute return self.cursor.execute(sql, params) django.db.utils.IntegrityError: Problem installing fixture 'C:\ProgramData\gitrepos\XXXXXX\XXXXXX\dump.json': Could not load contenttypes.ContentType(pk=1): duplicate key value violates unique constraint "django_content_type_app_label_76bd3d3b_uniq" DETAIL: Key (app_label, model)=(admin, logentry) already exists.
また怒られました。。。duplicate key value violates
なのでユニークキー制約(django_content_type_app_label_76bd3d3b_uniq
)で違反ですね。
app_label, modelのセットについている制約みたいです。django_content_type
テーブルはこんな定義でした。
djangodb=# \d django_content_type Table "public.django_content_type" Column | Type | Modifiers -----------+------------------------+------------------------------------------------------------------ id | integer | not null default nextval('django_content_type_id_seq'::regclass) app_label | character varying(100) | not null model | character varying(100) | not nullやま Indexes: "django_content_type_pkey" PRIMARY KEY, btree (id) "django_content_type_app_label_76bd3d3b_uniq" UNIQUE CONSTRAINT, btree (app_label, model) Referenced by: TABLE "auth_permission" CONSTRAINT "auth_permiss_content_type_id_2f476e4b_fk_django_content_type_id" FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED TABLE "django_admin_log" CONSTRAINT "django_admin_content_type_id_c4bce8eb_fk_django_content_type_id" FOREIGN KEY (content_type_id) REFERENCES django_content_type(id) DEFERRABLE INITIALLY DEFERRED
PostgreSQL側でlog_min_duration=0
をいれてSQLを眺めたところ以下のUPDATEが失敗しているようです。
ERROR: duplicate key value violates unique constraint "django_content_type_app_label_76bd3d3b_uniq" DETAIL: Key (app_label, model)=(admin, logentry) already exists. STATEMENT: UPDATE "django_content_type" SET "app_label" = 'admin', "model" = 'logentry' WHERE "django_content_type"."id" = 1
manage.py migrate
した直後にdjango_content_type
を見てみたところ既に(admin, logentry)のエントリがありました。
djangodb=# select * from "django_content_type"; id | app_label | model ----+--------------+-------------------------- 1 | qq | category 2 | qq | message 3 | qq | multianswerset 4 | qq | question 5 | qq | answerchoose 6 | qq | testbase 7 | qq | multianswersettargettest 8 | qq | testcategorylist 9 | qq | answerformultichoose 10 | qq | answer 11 | qq | answerset 12 | qq | answerformulti 13 | qq | questionchoice 14 | admin | logentry 15 | auth | permission 16 | auth | user 17 | auth | group 18 | contenttypes | contenttype 19 | sessions | session
なぜこんなことに・・・と探していると
どうやらdumpdata時点でいくつかexcludeしないと行けない模様
(django110) > python manage.py dumpdata --exclude auth.permission --exclude contenttypes > dump.json
で再度migrateしてからloaddataしました
(django110) > python manage.py loaddata dump.json Installed 563 object(s) from 1 fixture(s)
無事にいきました(問題がある表を抜いたので当たり前な気がしますが) そのまま起動して確認した感じ無事に動いているようです。
(django110) > python manage.py runserver Performing system checks... System check identified no issues (0 silenced). September 06, 2017 - 22:31:36 Django version 1.10, using settings 'HyakuMonHyakutou.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK.
これで無事にPostgreSQLに切り替えることができました。