ManyToManyフィールドを使った時に、どのようなテーブルが作成されるのかについて。
Django==3.0.2
psql (PostgreSQL) 12.1
Project構成
└── project
├── __init__.py
├── __pycache__
│ ├── __init__.cpython-37.pyc
│ ├── models.cpython-37.pyc ⬅️使ったモデル
│ ├── settings.cpython-37.pyc
│ ├── urls.cpython-37.pyc
│ └── wsgi.cpython-37.pyc
├── asgi.py
├── migrations
│ ├── 0001_initial.py
│ ├── __init__.py
│ └── __pycache__
│ ├── 0001_initial.cpython-37.pyc
│ └── __init__.cpython-37.pyc
├── models.py
├── settings.py
├── urls.py
└── wsgi.py
検証で使ったモデル(models.py)
model.py
from django.db import models
class Person(models.Model):
name = models.CharField("名前", max_length=100)
age = models.IntegerField("年齢")
def __str__(self):
return self.name
class Team(models.Model):
name = models.CharField("チーム名", max_length=100)
members = models.ManyToManyField("Person", through="PersonTeamRelation", through_fields=("team", "person"))
def __str__(self):
return self.name
class PersonTeamRelation(models.Model):
team = models.ForeignKey("Team", models.DO_NOTHING)
person = models.ForeignKey("Person", models.DO_NOTHING)
joined_date = models.DateField(auto_now=False, auto_now_add=False)
このモデルでpython manage.py makemigrationsすると、下のような、0001_initial.pyが作成されます。
initial.py
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Person',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), # 'id'がカラム名
('name', models.CharField(max_length=100, verbose_name='名前')), # 'name'がカラム名
('age', models.IntegerField(verbose_name='年齢')), # 'age'がカラム名
],
),
migrations.CreateModel(
name='PersonTeamRelation',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('joined_date', models.DateField()),
('person', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='project.Person')),
],
),
migrations.CreateModel(
name='Team',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100, verbose_name='チーム名')),
('members', models.ManyToManyField(through='project.PersonTeamRelation', to='project.Person')),
],
),
migrations.AddField(
model_name='personteamrelation',
name='team',
field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='project.Team'),
),
]
python manage.py migrateすると、DBに以下のようなテーブルが作成されます。
.sh
Table "public.project_team"
Column | Type | Collation | Nullable | 説明
--------+------------------------+-----------+----------+------------------------------------------
id | integer | | not null | 勝手に設定される
name | character varying(100) | | not null | modelのフィールド名と同じ
Table "public.project_person"
Column | Type | Collation | Nullable | 説明
--------+------------------------+-----------+----------+--------------------------------------------
id | integer | | not null | 勝手に設定される
name | character varying(100) | | not null | modelのフィールド名と同じ
age | integer | | not null | modelのフィールド名と同じ
Table "public.project_team_members"
Column | Type | Collation | Nullable | 説明
-----------+---------+-----------+----------+--------------------------------------------------
id | integer | | not null | 勝手に設定される
team_id | integer | | not null | <modelのフィールド名>_id
person_id | integer | | not null | <modelのフィールド名>_id
ここでわかりづらいのが、中間テーブルの名前。project_team_membersはどっから出てきたんだと、不思議に思うのですが、これは'Project名' _ '中間テーブルForeignKey' _ 'ManyToMany Field'で設定されるらしい。
カラム名、テーブル名、などはinitial.pyを変えないと、勝手に決められてしまうみたいなので、initial.pyを変更した検証もやっていきたい。
・model.pyの変更をDBに反映させる
model.pyを変更してもう一度migrationをかけるとどうなるかの検証