"매 in-process pub/sub for Django — observer pattern over the ORM lifecycle". Django signals 는 sender/receiver 의 decouple 하는 dispatch 메커니즘 — 2005 Django core 에 도입, 2026 현재 Django 5.1 LTS 까지 안정. 매 ORM hook (post_save, pre_delete) + custom signal 의 emit 의 standard way.
매 핵심
매 작동 원리
django.dispatch.Signal: receiver list 의 weakref 보관 — 매 GC safe.
send() vs send_robust(): send 의 raise on receiver error, send_robust 의 collect exceptions in result list — 매 production 의 send_robust 권장.
Synchronous: 매 in-process, in-thread — 매 transaction.on_commit() 통해 post-commit 의 schedule.
Async receivers (5.0+): 매 async def receiver 의 native support.
# myapp/signals.pyfromdjango.dispatchimportSignalorder_paid=Signal()# providing_args deprecated in 4.0+# In a view/service after paymentorder_paid.send(sender=Order,order=order,amount=order.total)# Receiver@receiver(order_paid)defsend_receipt(sender,order,amount,**kwargs):EmailService.send_receipt(order,amount)
fromdjango.core.cacheimportcachefromdjango.db.models.signalsimportpost_save,post_delete@receiver([post_save,post_delete],sender=Article)defpurge_article_cache(sender,instance,**kwargs):cache.delete(f"article:{instance.pk}")cache.delete_pattern("articles:list:*")# if django-redis
언제: in-process decoupling 이 필요할 때, ORM lifecycle hook (post_save 등) 이 자연스러울 때, 매 third-party app 의 own model 의 alter 못할 때.
언제 X: cross-service eventing — 매 Kafka/Outbox 의 use; complex workflow orchestration — 매 Celery chain / Temporal 의 use; testability 가 critical 한 critical path — 매 explicit service call 의 prefer.
❌ 안티패턴
Heavy work in receiver: 매 sync send 면 request latency 의 block — Celery enqueue.
Signals for in-app flow: 매 traceability 의 lose — 매 explicit method call 의 use.
No transaction.on_commit: post_save 시점 의 transaction 미commit — race condition 발생.
Forgetting weak=False: lambda receiver 가 GC 의 collected — 매 module-level def 또는 weak=False.
Test pollution: signal 의 test 사이 의 leak — fixture 의 disconnect.