ORM

Django ORMの関連データ作成入門|ForeignKeyを使ったデータ追加

Django ORMでForeignKey(外部キー)を持つモデルにデータを追加する方法を解説します。紐づいたモデルがある場合のデータ作成には、いくつかのパターンがあります。

モデルの準備

まず、1対多のリレーションを持つモデルを定義します。

models.py
from django.db import models

class Company(models.Model):
    name = models.CharField(max_length=100)

    class Meta:
        verbose_name = "会社"

class Employee(models.Model):
    name = models.CharField(max_length=100)
    company = models.ForeignKey(Company, on_delete=models.CASCADE)

    class Meta:
        verbose_name = "社員"

EmployeeモデルがCompanyモデルへのForeignKeyを持っています。これは「社員は1つの会社に所属する」というリレーションです。

基本的なデータ作成(外部キーIDを指定)

最もシンプルな方法は、ForeignKeyのフィールド名に_idを付けてIDを直接指定する方法です。

views.py
from .models import Company, Employee

def create_employee(request):
    # company_idを直接指定してEmployeeを作成
    Employee.objects.create(name="山田太郎", company_id=1)
実行結果
# Employeeテーブルに以下のレコードが追加される
# id=1, name="山田太郎", company_id=1

company_id=1と指定することで、idが1のCompanyに紐づくEmployeeが作成されます。

オブジェクトを指定する方法

外部キーのIDではなく、関連オブジェクト自体を渡すこともできます。

views.py
# Companyオブジェクトを取得してから指定
company = Company.objects.get(id=1)
Employee.objects.create(name="山田太郎", company=company)

Djangoが自動的にオブジェクトからIDを取得して外部キーに設定します。前の例と結果は同じです。

逆参照を使った作成

親モデル(Company)側から子モデル(Employee)を作成することもできます。

views.py
company = Company.objects.get(id=1)

# 逆参照マネージャを使って作成
company.employee_set.create(name="佐藤花子")

# related_nameを設定している場合はそのまま使える
# 例: company = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='employees')
# company.employees.create(name="佐藤花子")

この方法では、company_idを明示的に指定する必要がなく、自動的に紐づけが行われます。

save()を使った作成

create()を使わず、インスタンスを作成してからsave()する方法もあります。

views.py
company = Company.objects.get(id=1)

# インスタンスを作成してからsave
employee = Employee(name="鈴木一郎", company=company)
employee.save()

# または company_idで指定
employee = Employee(name="鈴木一郎", company_id=1)
employee.save()

バリデーションを行ってから保存したい場合や、保存前に追加の処理を行いたい場合に便利です。

実践的な使用例(フォームからの登録)

ビューでフォームからのデータを受け取って関連モデルを作成する実践例です。

views.py
from django.shortcuts import redirect, render
from .models import Company, Employee

def create_employee(request):
    if request.method == 'POST':
        name = request.POST.get('name')
        company_id = request.POST.get('company_id')

        # 会社が存在するか確認してから作成
        if Company.objects.filter(id=company_id).exists():
            Employee.objects.create(
                name=name,
                company_id=company_id
            )
            return redirect('employee_list')

    companies = Company.objects.all()
    return render(request, 'employees/create.html', {
        'companies': companies
    })
ポイント

create()は内部でsave()を呼び出すため、1行でインスタンスの作成と保存が同時に行われます。一方、Employee()でインスタンスを作成しただけではデータベースには保存されないため、必ずsave()を呼ぶ必要があります。

注意

ForeignKeyのon_deleteパラメータは必須です。親レコードが削除された場合の動作を指定します。CASCADE(一緒に削除)、PROTECT(削除を防ぐ)、SET_NULL(NULLに設定、null=True必須)などがあります。

まとめ

  • company_id=1のようにForeignKeyのIDを直接指定して作成できる
  • 関連オブジェクトを取得してcompany=company_objのように渡すこともできる
  • 親モデルのemployee_set.create()で逆参照から作成できる
  • create()は作成と保存を同時に行い、save()は分離して実行できる
  • フォームからの登録時は、存在確認を行ってからデータを作成するのが安全