3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Djangoで多対多のモデルを使う

3
Last updated at Posted at 2020-02-03

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をかけるとどうなるかの検証

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?