【Django】モデルの紐づけ(ForeignKey 編)

こんにちは、最近腰痛が気になるゴマ太郎です。
本日は Django モデルの ForeignKey について解説します。
ManyToManyFieldについての記事もあります

1. ForeignKey とは

1-1. モデルを紐づけるリレーションフィールド

ForeignKey は Django のモデル間を紐づけるリレーションフィールドの一つです。
Django のモデルには以下の3種類のリレーションフィールドが用意されており、それらの違いはモデルデータ間の関係性にあります。
各フィールドが使用される場面の例も【大学】をテーマに挙げてみます。

フィールド名関係性使用例
ForeignKey一対多学科 - 学科の在籍学生
ManyToManyField多対多講義 - 講義の履修学生
OneToOneField一対一学生 - 学生のロッカー番号

ちなみに今回扱うのは ForeignKey だけですが、ManyToManyFieldOneToOneField についても後日解説いたします。

1-2. ForeignKey は「一対多」の関係を持たせる

ForeignKey の「一対多」とは何を意味するのか説明します。
そんなの知っとるわという方は読み飛ばしてください。
前節では「学科 - 学科の在籍学生」という例を挙げました。この場合は学科が【一】、学生が【多】となります。

一対多のイメージ

『学生Aさんの学科は?と聞かれたら回答は必ず一つだけであるのに対して、情報学科の学生は?のように聞かれると回答の該当学生が複数いる。』

言ってしまうとこのようなモデルの関係が「一対多」です。
ちなみに、このとき【多】のほうは「複数になってもよいもの」であって、実際は1つだけもしくは NULL でも問題ありません。
ここからは実際に「学科 - 学科の在籍学生」の例で ForeignKey の使用方法を紹介していきます。

2. 前提条件

2-1. 環境

  • Ubuntu 20.04 LTS on WSL2
  • VSCode 1.76.0
  • Docker Engine 23.0.1
  • PostgreSQL 14.4
  • Python 3.10.8
  • Django 4.1.5

3. ForeignKey の使い方

3-1. models.py での書き方

ForeignKey を使うには以下のように書きます。

from django.db import models


class Department(models.Model):
    name = models.CharField(max_length=30)


class Student(models.Model):
    name = models.CharField(max_length=30)
    department = models.ForeignKey(Department, on_delete=models.CASCADE)

ForeignKey は「一対多」のうち【多】のモデルに作成します。

ここで ForeignKey に関係している記述は以下の行になります。
Student モデルの department フィールドに、 Department モデルをセットしています。
department = models.ForeignKey(Department, on_delete=models.CASCADE)
フィールド名 = models.ForeignKey(紐づけたいモデル, on_delete=このあと紹介します)
これだけで ForeignKey の実装は完了です。

3-2. 管理サイトで確認

確認に必要なコードの追記

ここからは ForeignKey が追加できていることを管理サイトで確認していきます。
その準備としていくつか追記します。

from django.contrib import admin
from .models import Department, Student


class StudentAdmin(admin.ModelAdmin):
    list_display = ('name', 'department')


admin.site.register(Department)
admin.site.register(Student, StudentAdmin)

from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

モデルを変更しているためマイグレートも必要です。
python manage.py makemigrations
python manage.py migrate

管理サイト

管理サイト~/admin/にアクセスすると、 Department と Student が追加されています。
管理サイト

学科データをここで登録します。
Departmentを追加

学科の登録が完了すると一覧画面でデータが追加されていることが確認できます。
Department追加後の一覧画面

次に Student に移動し、学生データを登録します。
Studentを追加

学生データ登録画面には、 Name と Department のフィールドがあり、 Department の選択肢に先ほど登録した学科が入っていれば ForeignKey の実装は成功です。
ちなみにプルダウン右側のでも学科を追加することができます。
Studentの登録画面

複数名の学生を同じ学科に紐づけられていることが確認できます。
このようにForeignKey を実装すると、モデル間の「一対多」の紐づけが可能になります。
Student追加後の一覧画面

3-3. on_delete の種類

on_delete 属性は、 ForeignKey などのリレーションフィールドが参照している親(学科)データを削除したい際の、紐づいている子(学生)データへのアクションを指定します。

設定データ削除時の動作
CASCADE削除する学科データに紐づく学生データも削除する。
PROTECT他のデータに紐づいていれば削除できない。
RESTRICT削除できずエラーが表示される。
学科データを削除した際、紐づく学生データは削除されずに残る。
SET_NULL削除される学科データの代わりに NULL がセットされる。
SET_DEFAULT削除される学科データの代わりにデフォルト値がセットされる。
SET()削除される学科データの代わりに指定したデータがセットされる

4. 最後に

今回は Django での ForeignKey の実装方法を解説しました。説明していない内容もまだまだありますので、気になった方は Django 公式ドキュメント をご確認ください。

ここまで読んでいただきありがとうございました。
ManyToManyField 編もありますので、よろしくお願いいたします。お疲れ様でした!

blog.css-net.co.jp

5. 参考


docs.djangoproject.com