django アプリケーションで使用しているテーブルの全削除、再作成を実施したところ、初期データとして必要なデータも消えてしまい、面倒なことになりました。
初期データをSQLで、migration の一貫として実行できると便利に思いましたので、SQLを直接実行する migration ファイルを作成してみました。
結果を以下に記載します。
前提
環境情報は以下の通りです。
-
OS
sw_vers ----------------------- ProductName: Mac OS X ProductVersion: 10.12.5 BuildVersion: 16F73 -----------------------
-
python version
python3 -V ----------------------- Python 3.5.1 -----------------------
-
Django Version
pip3 list | grep Django ----------------------- Django (1.10.7) -----------------------
migrations.RunSQL にINSERT文を直書きする
以下の手順で実施しました。
-
空のマイグレーションファイルを作成する
-
マイグレーションファイルに、
migrations.RunSQL
で、INSERT 文を記載する。 -
migrate 実行
空のマイグレーションファイルを作成する
./manage.py makemigrations festivals4partypeople --empty
-----------------------------------------
Migrations for 'festivals4partypeople':
festivals4partypeople/migrations/0002_auto_20170604_1454.py:
-----------------------------------------
マイグレーションファイルに、migrations.RunSQL
で、INSERT 文を記載する。
以下のようにSQL文を直に記載します。
第2引数のDELETE 文は、リカバリ用のSQLになります。
# -*- coding: utf-8 -*-
# Generated by Django 1.10.2 on 2017-06-04 05:54
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('festivals4partypeople', '0001_squashed_0003_auto_20170411_0110'),
]
operations = [
# echonest_artist UNKNOWN DATA
migrations.RunSQL(
"""INSERT INTO echonest_artist (id, echonest_id, name, relate_status, create_date, update_date) VALUES (-1,
'XXXXXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXXXXX', '2',
'1970-01-01 00:00:00.000+09', '1970-01-01 00:00:00.000+09');""",
"""DELETE FROM echonest_artist where id = -1;"""),
# lastfm_artist UNKNOWN DATA
migrations.RunSQL(
"""INSERT INTO lastfm_artist (id, mbid, name, relate_status, create_date, update_date) VALUES (-1,
'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', 'XXXXXXXXXXXXXXXXXX', '2', '1970-01-01 00:00:00.000+09',
'1970-01-01 00:00:00.000+09');""",
"""DELETE FROM lastfm_artist where id = -1;"""),
]
migrate 実行
- コマンド実行
./manage.py migrate --------------------------------------------- Operations to perform: Apply all migrations: admin, auth, contenttypes, festivals4partypeople, sessions Running migrations: Applying festivals4partypeople.0002_auto_20170604_1454... OK ---------------------------------------------
migrations.RunSQL でSQLファイルを実行する
sqlparse
をインストールする前提ですが、RunSQL で、外だしのsql ファイルが実行できるようです。
もともと投入データをSQL文で記載していましたので、結局こちらの方法で、初期データ投入用のスクリプトは作成しました。
以下、参考になりました。
sqlparse のインストール
python3 -m pip install sqlparse
マイグレーションファイルを作成する
- migrationファイル
load_sql
というメソッドを作成しました。
複数のINSERT文を記載したSQLファイルを文字列で読み込み、
RunSQLの引数とします。
# -*- coding: utf-8 -*-
# Generated by Django 1.10.2 on 2017-06-04 06:50
from __future__ import unicode_literals
from django.db import migrations
def load_sql(filename):
f = open(filename)
sql_statements = f.read()
f.close()
return sql_statements
class Migration(migrations.Migration):
dependencies = [
('festivals4partypeople', '0002_auto_20170604_1454'),
]
operations = [
migrations.RunSQL(load_sql('festivals4partypeople/sqls/V1.0.0.1__Add_heldYears.sql')),
migrations.RunSQL(load_sql('festivals4partypeople/sqls/V1.0.0.2__Add_festivals.sql')),
migrations.RunSQL(load_sql('festivals4partypeople/sqls/V1.0.0.3__Add_artists.sql')),
]
- sqlファイル
SQL ファイルの中身は以下のようなフォーマットです。
文末を;
区切りにします。
INSERT INTO held_year (id, held_year, create_date, update_date) VALUES (nextval('held_year_id_seq'), '2010', current_date, current_date);
INSERT INTO held_year (id, held_year, create_date, update_date) VALUES (nextval('held_year_id_seq'), '2011', current_date, current_date);
INSERT INTO held_year (id, held_year, create_date, update_date) VALUES (nextval('held_year_id_seq'), '2012', current_date, current_date);
INSERT INTO held_year (id, held_year, create_date, update_date) VALUES (nextval('held_year_id_seq'), '2013', current_date, current_date);
INSERT INTO held_year (id, held_year, create_date, update_date) VALUES (nextval('held_year_id_seq'), '2014', current_date, current_date);
INSERT INTO held_year (id, held_year, create_date, update_date) VALUES (nextval('held_year_id_seq'), '2015', current_date, current_date);
migrate 実行
./manage.py migrate
---------------------------------------------
Operations to perform:
Apply all migrations: admin, auth, contenttypes, festivals4partypeople, sessions
Running migrations:
Applying festivals4partypeople.0003_auto_20170604_1550... OK
---------------------------------------------
migrations.RunSQL にCREATE INDEX 文を直書きする
後日、CREATE INDEX文を実行する機会があったので追記します。
Django の Version は、2.1.8
を使用しました。
Executing Custom SQL in Django Migrations | End Point が参考になりました。
INSERT文と同様に、INDEX作成などのDDL文も migrations.RunSQL
で実行できます。
-
migrationファイル
# Generated by Django 2.1.8 on 2019-08-16 19:14 from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('home', '0007_entrygooglesearchconsole'), ] operations = [ migrations.RunSQL( """ CREATE INDEX date_idx ON puput_entrypage (date); """, """ DROP INDEX date_idx; """, ) ]
-
Postgres 以外のデータベースの場合
INSERT文では試していないのでわからないですが、CREATE INDEX を SQLite で実行した際は、SQL直書きの場合でもsqlparse
のインストールが必要でした。
Executing Custom SQL in Django Migrations | End Point にも記載があるので引用します。Unless you’re using Postgres for your database, you’ll need to install the sqlparse library, which allows Django to break the SQL strings into individual statements.
以上です。
コメント