2018/03/25
Django モデル クエリセット ForeignKeyDjango2.0から必須になったon_deleteの使い方
モデル同士を紐づけるときに、ForeignKey
やOneToOneField
を使いますが、その際、バージョン2からは引数としてon_delete
を指定することが必須となりました。
指定しないとTypeError: init() missing 1 required positional argument: 'on_delete'というエラーメッセージが出てしまいます。
on_deleteの意味
on_deleteとは、参照するオブジェクトが削除されたときに、それと紐づけられたオブジェクトも一緒に削除するのか、それともそのオブジェクトは残しておくのかを設定するものです。
実際の使用例
例えば、こんなモデル設計があったとします。ForeinKeyを使用して、Storyオブジェクト(小説)はAuthorオブジェクト(作者)を参照しています。
models.py
from django.db import models
class Author(models.Model):
"""作者"""
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Story(models.Model):
"""小説"""
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=50)
text = models.TextField()
def __str__(self):
return self.title
この設計によってこんなStorysテーブルができます。
例えばここでAuthorオブジェクト:"川端康成"を削除したときに、それと紐づいたStoryオブジェクト:"雪国"、"伊豆の踊り子"も削除するのか、それとも残しておくのかを設定するのがon_deleteです。
on_deleteの設定は以下6種類の中から選択します。
- CASCADE
- PROTECT
- SET_NULL
- SET_DEFAULT
- SET()
- DO_NOTHING
それぞれどのような設定になるのか見ていきましょう。
1. CASCADE
models.py
author = models.ForeignKey(Author, on_delete=models.CASCADE)
削除するオブジェクトに紐づいたオブジェクトを全て削除します。
例えば、以下の画像のようにAuthorオブジェクト"川端康成"を削除しようとして削除ボタンを押すと、
このように「関連付けられてるオブジェクトを削除します」とメッセージが出ます。
「はい」ボタンで、Authorオブジェクト"川端康成"が削除されるのと同時に、それに紐づいたStoryオブジェクトも全て削除されます。
2. PROTECT
models.py
author = models.ForeignKey(Author, on_delete=models.PROTECT)
関連付けられてるオブジェクトがあると、削除できません。
この場合、Authorに紐づいたStoryがあるのでAuthorを削除することができません。関連付けられたStoryオブジェクトを全て削除すればAuthorも削除することができるようになります。
3. SET_NULL
models.py
author = models.ForeignKey(
Author,
on_delete=models.SET_NULL,
null=True
)
オブジェクトが削除されると、代わりにNULLをセットします。
今回の例だと、Authorを削除するとStoryオブジェクトのauthorフィールドがNULL(空白)になります。
こんな感じで、Authorに誰も登録されていない状態になります。注意点として、authorフィールドはnull=Trueにしておく必要があります。
4. SET_DEFAULT
models.py
author = models.ForeignKey(
Author,
on_delete=models.SET_DEFAULT,
default=Author.objects.get(name="匿名")
)
削除されたオブジェクトの代わりに、デフォルト値が入るようになります。注意点として、authorフィールドにはデフォルト値を設定しておく必要があります。
このようにauthorフィールドにデフォルト値の"匿名"が入ります。
5. SET()
自分で処理を自由に設定することができます。
今回は、"削除された著者"という文字列をauthorフィールドに入れる処理をします。
models.py
def get_deleted_user():
return Author.objects.get_or_create(name="削除された作者")[0]
class Story(models.Model):
author = models.ForeignKey(Author, on_delete=models.SET(get_deleted_user))
title = models.CharField(max_length=50)
text = models.TextField()
6. DO_NOTHING
何の処理もしません。
まとめ
基本的にはCASCADE
やPROTECT
を使う場面が多いのではないかと思います。いずれにせよ、on_delete
を指定しないとエラーが出てしまうので気をつけましょう。