Djangoのpre_saveとpost_saveシグナルの効果的な使用方法
By khoanc, at: 2025年3月15日20:01
Estimated Reading Time: __READING_TIME__ minutes


Djangoシグナルは、アプリケーション内のロジックをデカップリングするための強力なツールです。特にpre_save
とpost_save
シグナルを使用すると、データベースにモデルインスタンスを保存する前または後に、カスタムアクションを実行できます。これらのシグナルは、タスクの自動化、手動介入の削減、よりクリーンなコードの維持に最適です。
このブログ投稿では、実際のケーススタディ(倉庫在庫の管理と在庫少通知の送信)を紹介することで、これらのシグナルを効果的に使用する方法について説明します。
実際のケーススタディ:スマート倉庫在庫管理
シナリオ
倉庫の在庫管理システムを構築していると想像してください。製品を追加または更新するたびに:
- 倉庫内の製品総数が自動的に更新されます。
- 製品数量がしきい値を下回った場合、在庫切れを防ぐために、倉庫オーナーにメールで通知されます。
このワークフローにより、倉庫の効率的な運用が確保され、手動での追跡が不要になり、在庫不足が防止されます。
実装
ステップ1:モデルの定義
2つのモデルを作成することから始めます。
- Warehouse:すべての製品の総数を格納します。
- Product:倉庫にリンクされた個々の製品を表します。
from django.db import models
class Warehouse(models.Model):
name = models.CharField(max_length=255)
total_products = models.PositiveIntegerField(default=0)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=255)
quantity = models.PositiveIntegerField(default=0)
warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE, related_name="products")
def __str__(self):
return self.name
ステップ2:自動化のためのシグナルの接続
2つのシグナルを使用します。
from django.db.models.signals import pre_save, post_save
from django.dispatch import receiver
from django.core.mail import send_mail
from .models import Product, Warehouse
@receiver(pre_save, sender=Product)
def update_total_products(sender, instance, **kwargs):
if instance.pk:
# データベースから古い数量を取得
old_quantity = Product.objects.get(pk=instance.pk).quantity
difference = instance.quantity - old_quantity
else:
difference = instance.quantity
# 倉庫の製品総数を更新
instance.warehouse.total_products += difference
instance.warehouse.save()
@receiver(post_save, sender=Product)
def send_low_stock_notification(sender, instance, **kwargs):
low_stock_threshold = 10 # 在庫少しきい値
if instance.quantity < low_stock_threshold:
# オーナーにメール通知を送信
send_mail(
subject=f"在庫少アラート:{instance.name}",
message=f"製品 '{instance.name}' の在庫が少なくなっています。残りは {instance.quantity} 個です。早急に補充してください。",
from_email="[email protected]",
recipient_list=["[email protected]"], # 倉庫オーナーのメールアドレスに置き換えてください
)
ステップ3:シグナルの登録
apps.py
ファイルでインポートすることで、アプリの準備が整ったときにシグナルが登録されるようにします。
# apps.py
from django.apps import AppConfig
class InventoryConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "inventory"
def ready(self):
import inventory.signals # シグナルのインポート
システムのテスト
新規製品の追加
新しい製品を作成し、倉庫の製品総数が自動的に更新されることを確認します。
warehouse = Warehouse.objects.create(name="メイン倉庫")
product = Product.objects.create(name="ウィジェット", quantity=20, warehouse=warehouse)
print(warehouse.total_products) # 出力:20
製品数量の更新
製品数量を更新し、倉庫の合計が変更を反映することを確認します。
product.quantity = 35
product.save()
print(warehouse.total_products) # 出力:35
在庫少通知
製品数量をしきい値を下回るように減らし、メール通知を確認します。
product.quantity = 5
product.save()
# メール送信:「製品 'ウィジェット' の在庫が少なくなっています。残りは 5 個です。」
このアプローチのメリット
-
自動化
倉庫の合計と在庫少アラートは自動的に処理されるため、手動での更新は不要です。
-
予防的な通知
重要な問題になる前に、オーナーに在庫少について警告されるため、円滑な運用が確保されます。
-
デカップリングされたロジック
シグナルにより、在庫ロジックがコアアプリケーションから分離されるため、システムのモジュール性と保守性が向上します。
Django シグナルを使用するためのベストプラクティス
-
複雑なロジックを避ける
シグナルハンドラーをシンプルに保ちます。メールの送信などの重いタスクには、Celeryなどのバックグラウンドタスクキューを使用することを検討してください。
-
シグナルのオーバーヘッドを最小限に抑える
シグナルが不要なデータベースクエリを実行したり、リクエスト処理を遅くしたりしないようにします。
-
シグナルの動作をテストする
シグナルが期待通りにトリガーされ、アプリケーションの他の部分に干渉しないことを徹底的にテストします。
結論
Djangoのpre_save
とpost_save
シグナルは、ワークフローを自動化し、アプリケーションロジックをクリーンに保つための優れたツールです。このケーススタディでは、シグナルによって、倉庫の合計を自動的に更新し、オーナーに在庫少を通知することで、在庫管理を効率化できることを示しました。
これらのテクニックを実装することで、時間とコストのかかるエラーを防ぐ、よりスマートで効率的なシステムを構築できます。