巳年じゃないけど Python やろうぜ(その 15)
初期データの一括投入
今回から、当ブログではすっかりお馴染みの「政令指定都市一覧」を使って、Django の様々な機能を見ていきます。
$ ./manage.py startapp major_city
例によってアプリを作成するところからスタート。
Model を作ります。
from django.db import models # Create your models here. class District(models.Model): name = models.CharField(max_length=30) class Prefecture(models.Model): name = models.CharField(max_length=30) district = models.ForeignKey(District, on_delete=models.CASCADE) class City(models.Model): name = models.CharField(max_length=30) prefecture = models.ForeignKey(Prefecture, on_delete=models.CASCADE) designated = models.DateField() area = models.DecimalField(max_digits=7, decimal_places=2) population = models.IntegerField()
ForeignKey
が初登場しました。これは参照する親モデルのクラス名と、親クラスを削除した時の挙動(ON DELETE ~)を指定します。ちなみに on_delete
は Django 2.0 以降で必須になるそうです*1ので、デフォルトに甘えずに指定しておくと移行が楽になるでしょう。
マイグレーションを作成します。
$ ./manage.py makemigrations major_city (0.001) SELECT name, type FROM sqlite_master WHERE type in ('table', 'view') AND NOT name='sqlite_sequence' ORDER BY name; args=None (0.000) SELECT "django_migrations"."app", "django_migrations"."name" FROM "django_migrations"; args=() Migrations for 'major_city': major_city/migrations/0001_initial.py: - Create model City - Create model District - Create model Prefecture - Add field prefecture to city
SQL を確認してみましょう。
$ ./manage.py sqlmigrate major_city 0001 (中略) BEGIN; -- -- Create model City -- CREATE TABLE "major_city_city" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(30) NOT NULL, "designated" date NOT NULL, "area" decimal NOT NULL, "population" integer NOT NULL ); -- -- Create model District -- CREATE TABLE "major_city_district" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(30) NOT NULL ); -- -- Create model Prefecture -- CREATE TABLE "major_city_prefecture" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(30) NOT NULL, "district_id" integer NOT NULL REFERENCES "major_city_district" ("id") ); -- -- Add field prefecture to city -- ALTER TABLE "major_city_city" RENAME TO "major_city_city__old"; CREATE TABLE "major_city_city" ( "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "name" varchar(30) NOT NULL, "designated" date NOT NULL, "area" decimal NOT NULL, "population" integer NOT NULL, "prefecture_id" integer NOT NULL REFERENCES "major_city_prefecture" ("id") ); INSERT INTO "major_city_city" ( "id", "name", "designated", "area", "population", "prefecture_id" ) SELECT "id", "name", "designated", "area", "population", NULL FROM "major_city_city__old"; DROP TABLE "major_city_city__old"; CREATE INDEX "major_city_prefecture_a34a99d3" ON "major_city_prefecture" ("district_id"); CREATE INDEX "major_city_city_71a71d54" ON "major_city_city" ("prefecture_id"); COMMIT;
若干回りくどい処理をしていますが、これはモデル名のアルファベット順に処理をしようとしているからでしょうか。
最後はマイグレーションファイルを適用するのを忘れずに。
$ ./manage.py migrate
いよいよ初期データ投入です。初期データは major_city/fixtures
フォルダの中に JSON 形式か XML 形式で入れておきます(PyYAML をインストールすることで YAML 形式も使用可能)。
今回は JSON を利用しようと思います。長いです、ハイ。
initial_data.json
という名前にしているのは、古いバージョンで使えた syncdb
コマンドに自動的に認識してもらうためのものでしたが、現在は migrate
+ loaddata
が基本です。
$ ./manage.py loaddata initial_data
で初期データが投入できます。
次回は汎用ビューのお話。