DjangoのSignalとは、フレームワーク内でアクションが発生した際に処理が発生する仕組みを言い、以下のようなSignalがある。
pre_save post_save> | モデルのsave()メソッドが実行される前後に実行される (本記事で詳細を説明) |
pre_save post_save |
モデルのdelete()メソッド、QuerySetのdelete()メソッドが実行される前後で実行される |
m2m_changed | モデルのManyToManyが変更されたときに呼び出される |
request_started request_finished |
DjangoがRequestを処理する前後で呼び出される |
pre_save, post_saveの詳細・定義の方法
per_saveは、modelのsave()メソッド処理の前に呼び出される
以下の引数を持つ
- sender: モデルクラス
- instance: 保存されたインスタンス
- pre_save用の関数を、以下のように定義
そして、以下のようにdjango.db.models.signals.presave.connect()でモデルにpre_saveに登録設定する
# sender, instance, *args, **kwargsを引数として持つ
from django.db.models.signals import pre_save
pre_save.connect(blog_post_model_pre_save_receiver, sender=PostModel)
実際にコードは以下のように記載する。
- models.pyの定義
id = models.BigAutoField(primary_key=True)
active = models.BooleanField(blank=True)
title = models.CharField(max_length=240)
slug = models.SlugField(null=True, blank=True)
content = models.TextField(null=True, blank=True)
def blog_post_model_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug and instance.title:
instance.slug = slugify(instance.title)
pre_save.connect(blog_post_model_pre_save_receiver, sender=PostModel)
# pre_saveをPostModelモデルに設定しする。
# 保存前にオブジェクトのtitleが出力され、slugが設定される
また、pre_saveの設定を外すには、disconnectメソッドを利用する。
pre_save.disconnect(blog_post_model_pre_save_receiver, sender=PostModel)
同様にmodelのsave()後に実行するようにシグナルを設定するのは、post_saveを利用する。
以下の引数を持つ
- sender: モデルクラス
- instance: 保存されたインスタンス
- created: レコードが新たに作成されたときにTrueを返すブール値
- pre_save用の関数を、以下のように定義
そして、django.db.models.signals.post_save.connect()でモデルにpost_saveに登録する
# sender, instance, created, *args, **kwargsを引数として持つ
from django.db.models.signals import post_save
post_save.connect(blog_post_model_post_save_receiver, sender=PostModel)
実際にコードは以下のように記載する
- post_saveの定義
if created:
if not instance.slug and instance.title:
instance.slug = slugify(instance.title)
instance.save()
post_save.connect(blog_post_model_post_save_receiver, sender=PostModel)
# receiver, senderを設定、modelのsave後に、blog_post_model_post_save_receirverが呼び出される
同様にpost_saveの設定を外すにはdisconnectを利用する
pre_save, post_saveの定義の方法2
pre_save, post_saveを登録する方法は、デコレータを使う方法もあり、簡潔に記載することができる
以下のように関数の上に@receiver(pre_save(or post_save),modelクラス)のように記載する。
- pre_save, post_saveの設定方法2
from django.db.models.signals import post_save, pre_save
# PostModelのsave前に実行される
@receiver(pre_save, sender=PostModel)
def blog_post_model_pre_save_receiver(sender, instance, *args, **kwargs):
if not instance.slug and instance.title:
instance.slug = slugify(instance.title)
# PostModelのsave後に実行される
@receiver(post_save, sender=PostModel)
def blog_post_model_post_save_receiver(sender, instance, created, *args, **kwargs):
if created:
if not instance.slug and instance.title:
instance.slug = slugify(instance.title)
instance.save()