概要
Djangoのモデル作成について、チュートリアルに沿って進めた内容の整理。mysiteプロジェクトのpollアプリケーションのモデルを作成する手順。
前提
mysiteプロジェクト作成・初期設定済みpollsアプリケーション作成済み
手順
models.pyを編集し、モデルクラスを記述models.pyはアプリケーションディレクトリー下- モデルクラスの内容=テーブルのフィールド構成
settings.pyのINSTALLED_APPSにアプリケーション登録- アプリケーション構成クラスを追加
manage.py makemigrationsコマンドでマイグレーションファイルの準備- 必要なら
manage.py sqlmigrateでSQLを確認
- 必要なら
- マイグレーション実行
models.pyの編集
モデルはデータベースの操作をラップし、DBMSによる差異を吸収する。
- Djangoでは、モデルはアプリケーションごとに作成する
- モデルの構造はPythonのクラスとして記述する
- モデルの記述場所はアプリケーションディレクトリー下の
models.py
以下のツリーでmodels.pyの場所を確認しておく。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
mysite ├── config │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── manage.py └── polls ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ ├── 0001_initial.py │ └── __init__.py ├── models.py ├── tests.py ├── urls.py └── views.py |
アプリケーション作成直後のmodels.pyファイルの内容は以下のとおり。モデルが継承するmodelsパッケージをインポートしている。
|
1 2 3 |
from django.db import models # Create your models here. |
QustionモデルとChoiceモデルを作成するため、models.pyを以下のように編集。
|
1 2 3 4 5 6 7 8 9 10 |
from django.db import models class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) |
要点は以下のとおり。
- モデル名は単数形で
QustionとChoiceの2つ - 各モデルは
django.db.models.Modelクラスを継承 - 各モデルクラスのフィールドは
modelsパッケージのField関係クラスのインスタンス- たとえば
CharFieldは文字列フィールド、DateTimeFieldはdatetime型のフィールドなど
- たとえば
- こちらで定義した
question_text、pub_dateなどのフィールド名はPythonのコードで扱われるとともに、データベースのフィールド名としても使われる - 各
Fieldコンストラクターの第1引数では、より人が読みやすいフィールド名を付けることができる- 上の例では
'date published'
- 上の例では
Fieldによっては必須の引数があり、たとえばCharFieldのmax_lengthは必須であり、データベースフィールド定義のほか、バリデーションにも使われるForeignKeyは外部キーであり、Choiceモデルのquestionフィールドは1つのQuestionモデルを参照する- また参照元の削除に伴って削除される設定もされている
なお、自動作成されるテーブル名を変更したい場合はここを参照。
アプリケーションの追加
pollsアプリケーションを作成してモデルを定義したが、これらはまだDjangoのプロジェクトには認識されていない。プロジェクトとしてモデルとデータベースを結びつけるマイグレーションのためには、アプリケーションをプロジェクトに登録する必要がある。
アプリケーション登録のために、settings.pyのINSTALLED_APPSに記述を加える。ここではアプリケーション構成クラスを追加する。
|
1 2 3 4 5 6 7 8 9 |
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'polls.apps.PollsConfig', ] |
ここではpollsアプリケーションのPollsConfigクラスを登録している。このクラスはアプリケーション作成時にDjangoにより生成、アプリケーションのapps.pyファイルで定義されていて、AppConfigクラスを継承している。
pollsアプリケーションの場合はpolls.apps.PollsConfigとして参照される。
|
1 2 3 4 5 6 |
from django.apps import AppConfig class PollsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'polls' |
マイグレーションファイル作成
マイグレーションファイルの作成は以下のコマンドで実行。
|
1 |
$ python3 manage.py makemigrations アプリケーション |
以下はpollsアプリケーションの実行結果で、アプリケーションのmigrationsディレクトリーにマイグレーションファイル(0001_initial.py)が作成され、マイグレーションによりQuestionとChoiceの2つのモデルが作成されることが表示されている。
|
1 2 3 4 5 |
$ python3 manage.py makemigrations polls Migrations for 'polls': polls/migrations/0001_initial.py - Create model Question - Create model Choice |
0001_initial.pyファイルの内容を見てみる。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# Generated by Django 3.2.12 on 2022-03-17 05:08 from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Question', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('question_text', models.CharField(max_length=200)), ('pub_date', models.DateTimeField(verbose_name='date published')), ], ), migrations.CreateModel( name='Choice', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('choice_text', models.CharField(max_length=200)), ('votes', models.IntegerField(default=0)), ('question', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='polls.question')), ], ), ] |
2つのモデルとも、クラス定義にはなかったidフィールドが追加されている。これらのフィールドはAUTO_INCREMENTタイプで自動的に作成され、主キー(primary_key)として設定されている。
SQLの確認
マイグレーションファイルの内容でデータベースのテーブルを作成する際のSQLも確認することができる。
|
1 |
$ python3 manage.py sqlmigrate アプリケーション 番号 |
以下はpollsアプリケーションのマイグレーションファイルをSQLで確認した結果。
|
1 2 3 4 5 6 7 8 9 10 |
$ python3 manage.py sqlmigrate polls 0001 -- -- Create model Question -- CREATE TABLE `polls_question` (`id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, `question_text` varchar(200) NOT NULL, `pub_date` datetime(6) NOT NULL); -- -- Create model Choice -- CREATE TABLE `polls_choice` (`id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, `choice_text` varchar(200) NOT NULL, `votes` integer NOT NULL, `question_id` bigint NOT NULL); ALTER TABLE `polls_choice` ADD CONSTRAINT `polls_choice_question_id_c5b4b260_fk_polls_question_id` FOREIGN KEY (`question_id`) REFERENCES `polls_question` (`id`); |
読み易いように整形した結果。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
-- -- Create model Question -- CREATE TABLE `polls_question` ( `id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, `question_text` varchar(200) NOT NULL, `pub_date` datetime(6) NOT NULL ); -- -- Create model Choice -- CREATE TABLE `polls_choice` ( `id` bigint AUTO_INCREMENT NOT NULL PRIMARY KEY, `choice_text` varchar(200) NOT NULL, `votes` integer NOT NULL, `question_id` bigint NOT NULL ); ALTER TABLE `polls_choice` ADD CONSTRAINT `polls_choice_question_id_c5b4b260_fk_polls_question_id` FOREIGN KEY (`question_id`) REFERENCES `polls_question` (`id`); |
MySQLの場合、
- 自動的に作成された
idのAUTO_INCREMENT、PRIMARY KEYが設定されている CharField(max_length=200)がvarchar(200)となっているdatetime(6)の引数6は秒未満の小数部の桁数- モデルクラスでは
Choice.questionがQuestionを参照するよう定義したが、SQLではpolls_choiceテーブルのquestion_idがpolls_questionテーブルのidを参照するという風に、IDを介して参照している
マイグレーション実行
生成されたマイグレーションファイルに基づいて、以下のコマンドでマイグレーションを実行。
|
1 |
$ python3 manage.py migrate (アプリケーション) |
以下は今回の例で実行した結果。
|
1 2 3 4 5 |
$ python3 manage.py migrate Operations to perform: Apply all migrations: admin, auth, contenttypes, polls, sessions Running migrations: Applying polls.0001_initial... OK |
manage.py showmigrationsで、pollsアプリケーションのマイグレーションファイルが実行されているのが確認できる。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
$ python3 manage.py showmigrations admin [X] 0001_initial [X] 0002_logentry_remove_auto_add [X] 0003_logentry_add_action_flag_choices auth [X] 0001_initial [X] 0002_alter_permission_name_max_length [X] 0003_alter_user_email_max_length [X] 0004_alter_user_username_opts [X] 0005_alter_user_last_login_null [X] 0006_require_contenttypes_0002 [X] 0007_alter_validators_add_error_messages [X] 0008_alter_user_username_max_length [X] 0009_alter_user_last_name_max_length [X] 0010_alter_group_name_max_length [X] 0011_update_proxy_permissions [X] 0012_alter_user_first_name_max_length contenttypes [X] 0001_initial [X] 0002_remove_content_type_name polls [X] 0001_initial sessions [X] 0001_initial |
MySQL側でテーブルを確認。2つのテーブルpolls_question、polls_choiceが作成されている。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
mysql> show tables; +----------------------------+ | Tables_in_django_tutorial | +----------------------------+ | auth_group | | auth_group_permissions | | auth_permission | | auth_user | | auth_user_groups | | auth_user_user_permissions | | django_admin_log | | django_content_type | | django_migrations | | django_session | | polls_choice | | polls_question | +----------------------------+ 12 rows in set (0.00 sec) |
2つのテーブルの定義を確認。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
mysql> describe polls_question; +---------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------+--------------+------+-----+---------+----------------+ | id | bigint | NO | PRI | NULL | auto_increment | | question_text | varchar(200) | NO | | NULL | | | pub_date | datetime(6) | NO | | NULL | | +---------------+--------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec) mysql> describe polls_choice; +-------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+----------------+ | id | bigint | NO | PRI | NULL | auto_increment | | choice_text | varchar(200) | NO | | NULL | | | votes | int | NO | | NULL | | | question_id | bigint | NO | MUL | NULL | | +-------------+--------------+------+-----+---------+----------------+ 4 rows in set (0.00 sec) |