概要
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
パッケージをインポートしている。
|
from django.db import models # Create your models here. |
Qustion
モデルとChoice
モデルを作成するため、models.py
を以下のように編集。
|
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引数では、より人が読みやすいフィールド名を付けることができる
Field
によっては必須の引数があり、たとえばCharField
のmax_length
は必須であり、データベースフィールド定義のほか、バリデーションにも使われる
ForeignKey
は外部キーであり、Choice
モデルのquestion
フィールドは1つのQuestion
モデルを参照する
- また参照元の削除に伴って削除される設定もされている
なお、自動作成されるテーブル名を変更したい場合はここを参照。
アプリケーションの追加
polls
アプリケーションを作成してモデルを定義したが、これらはまだDjangoのプロジェクトには認識されていない。プロジェクトとしてモデルとデータベースを結びつけるマイグレーションのためには、アプリケーションをプロジェクトに登録する必要がある。
アプリケーション登録のために、settings.py
のINSTALLED_APPS
に記述を加える。ここではアプリケーション構成クラスを追加する。
|
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
として参照される。
|
from django.apps import AppConfig class PollsConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'polls' |
マイグレーションファイル作成
マイグレーションファイルの作成は以下のコマンドで実行。
|
$ python3 manage.py makemigrations アプリケーション |
以下はpolls
アプリケーションの実行結果で、アプリケーションのmigrations
ディレクトリーにマイグレーションファイル(0001_initial.py
)が作成され、マイグレーションによりQuestion
とChoice
の2つのモデルが作成されることが表示されている。
|
$ 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も確認することができる。
|
$ python3 manage.py sqlmigrate アプリケーション 番号 |
以下はpolls
アプリケーションのマイグレーションファイルをSQLで確認した結果。
|
$ 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を介して参照している
マイグレーション実行
生成されたマイグレーションファイルに基づいて、以下のコマンドでマイグレーションを実行。
|
$ python3 manage.py migrate (アプリケーション) |
以下は今回の例で実行した結果。
|
$ 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) |