Pythonメモ torinaブログ

このブログはDjangoとBootstrap4で作成されました
ソースコード

Django、on_deleteを使う

プログラミング関連 Django
約174日前 2016年10月3日18:53
このような、シンプルなモデルがあります。
from django.db import models


class Category(models.Model):
    """カテゴリ"""

    name = models.CharField(max_length=255)

    def __str__(self):
        return self.name


class Post(models.Model):
    """記事"""

    title = models.CharField(max_length=255)
    text = models.TextField()
    category = models.ForeignKey(Category)

    def __str__(self):
        return self.title


試しに記事をいくつか作成し、全て「食べ物」というカテゴリにしたとします。




この状態で、「食べ物」というカテゴリを削除すると...


「食べ物」を指定した記事も、一緒に削除されます。


以前、このブログでカテゴリを整理しようと思った際に同様のことをやってしまい
グーグル検索のキャッシュを見ながら人力で記事を作成しなおす、という不毛な作業を行ったことは記憶に新しいです。
今回は、このような際の挙動を変更してみましょう。

結論から書くと、on_deleteに指定することでふるまいを変更できます。
category = models.ForeignKey(Category, on_delete=models.CASCADE)



models.CASCADE - デフォルトの動作。一緒に削除される



category = models.ForeignKey(Category, on_delete=models.CASCADE)




models.PROTECT - 保護する。参照されてたら、削除ができなくなるよ



category = models.ForeignKey(Category, on_delete=models.PROTECT)




ただし、そのカテゴリがどの記事からも指定されてなければ削除はできます。


これをつけておけば多い日も安心ですね。



models.SET_NULL - NULLをセットします。null=Trueにしてないといけません。



category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)

nullを許可していいのなら、これも有用そうです。




空欄になりますね。




models.SET_DEFAULT - デフォルト値をセットします。default=...と指定してないといけません。



    category = models.ForeignKey(
        Category,
        on_delete=models.SET_DEFAULT,
        default=Category.objects.get(name="飲み物"),
    )





ちゃんとデフォルトで指定した飲み物に変わりますね。



models.SET() - セットします。割と柔軟なことができます。



def make_and_set():
    category = Category.objects.get_or_create(name="New")[0]
    return category


class Post(models.Model):
    """記事"""

    title = models.CharField(max_length=255)
    text = models.TextField()
    category = models.ForeignKey(
        Category,
        on_delete=models.SET(make_and_set),
    )

    def __str__(self):
        return self.title



飲み物カテゴリしかない状態です。






このように、Newカテゴリが作成されセットされました。


これが、なければ作り、あればそのまま返す、という処理です。
Category.objects.get_or_create(name="New")[0]




models.DO_NOTHING - 何もしないそうです。




このon_deleteですが、Django 2.0では必須になるっぽいですね。


Changed in Django 1.9:
on_delete can now be used as the second positional argument (previously it was typically only passed as a keyword argument). It will be a required argument in Django 2.0.