Skip to main content

Django Signals and Receivers

Implement Django signals for decoupled event handling — model lifecycle hooks, custom signals, async processing, and testing strategies.

Fill in the placeholders

Edit the values, then copy your finished prompt.

Your Prompt
prompt.txt
Implement a Django signals architecture for e-commerce platform with orders, payments, and notifications. The application needs to react to order placement, payment completion, inventory changes, user registration without tight coupling between apps. Build: 1) Post-save signals for Order, Payment, UserProfile — create receivers that handle both created (new instance) and updated (existing instance) cases differently. For new Order, trigger: send confirmation email, reserve inventory, create shipment record, notify seller. 2) Define custom signals for order_completed (after full payment), inventory_low (below threshold), subscription_renewed using django.dispatch.Signal with providing_args documentation. Connect receivers in core/apps.py ready() method. 3) Pre-save signals for Order, Payment that enforce order total must match line items sum, payment amount cannot exceed order total — raise ValidationError with descriptive messages when rules are violated. 4) M2M changed signals for Product.categories, Order.promotions — react to recalculate discount when promotions change, update search index when categories change when relationships are added/removed. 5) Async processing pattern: signals should dispatch to Celery for heavy operations (email sending, PDF invoice generation, third-party API notifications) instead of running synchronously in the request cycle. Keep the signal handler lightweight. 6) Signal disconnection and reconnection patterns for CSV product import, bulk order status updates to avoid firing signals during bulk imports. 7) Testing strategy: test each receiver in isolation using signal.disconnect/reconnect, mock heavy dependencies, and use signal_defs fixture with mock receivers to verify signals fire with expected arguments.

What this prompt does

This prompt builds a Django signals architecture for a [project_type] so apps can react to [trigger_events] without depending on each other directly. It creates post-save receivers for [post_save_models] that distinguish the created case from the updated case using the created flag, and on a new [primary_model] it fires [creation_actions] like sending confirmations and reserving inventory.

It also defines custom signals for [custom_signal_events] using django.dispatch.Signal with documented arguments, connected in [signal_app]/apps.py ready(), plus pre-save validation on [validation_models] enforcing [business_rules] with descriptive ValidationErrors, and m2m_changed handlers for [m2m_relationships] reacting to [m2m_actions]. The key discipline is that signal handlers stay lightweight: heavy work ([heavy_operations]) is dispatched to [task_queue] rather than running in the request cycle. It also includes the disconnect/reconnect pattern for [bulk_operations] so signals don't fire during imports, plus an isolation-based testing strategy using [test_pattern] that tests each receiver on its own. The result is an event seam where each app announces what happened and other apps subscribe without importing one another.

When to use it

  • You want apps decoupled so placing an order doesn't import email and inventory code
  • You need different behavior on object creation versus update in one receiver
  • You're enforcing business invariants like totals matching line items at save time
  • You need to react when many-to-many relationships change (categories, promotions)
  • You're doing bulk imports and need to suppress signals to avoid side effects
  • You want each receiver unit-tested in isolation with disconnect/reconnect
  • You're untangling tightly coupled apps and want events to flow through a clear seam

Example output

The AI returns receiver functions wired to post_save, pre_save, and m2m_changed, custom Signal definitions with documented arguments, an apps.py ready() connecting them, examples of dispatching [heavy_operations] to [task_queue], a disconnect/reconnect context manager for [bulk_operations], and tests that verify signals fire with the expected arguments. Expect snippets grouped per numbered item, so you can adopt the validation, async, and bulk-suppression pieces independently.

Pro tips

  • Split logic on the created flag in post-save receivers so updates don't re-run creation-only actions from [creation_actions]
  • Keep handlers thin — anything in [heavy_operations] should be a [task_queue] dispatch, not synchronous work in the request
  • Use the disconnect/reconnect pattern for every path in [bulk_operations]; a CSV import firing per-row signals can grind to a halt
  • Connect signals in apps.py ready(), not at module import, to avoid double-registration
  • Raise ValidationError with the specific rule from [business_rules] in the message so failures are debuggable
  • Document the arguments your custom [custom_signal_events] send, since receivers depend on that contract staying stable
  • React to [m2m_actions] in m2m_changed rather than post_save, because the related rows aren't attached yet when the parent saves
  • If receivers are hard to test, lean on [test_pattern] to mock heavy dependencies and assert signal arguments

Frequently Asked Questions

How do I make a post-save receiver behave differently on create versus update?
Django's post_save signal passes a `created` boolean. The generated receivers for `[post_save_models]` branch on it, running creation-only actions like `[creation_actions]` when `created` is True and update logic otherwise, so updates don't accidentally re-trigger new-record side effects.
Won't signals slow down my request cycle?
They can if handlers do heavy work synchronously. This prompt keeps handlers lightweight and dispatches `[heavy_operations]` to `[task_queue]` instead, so the request returns fast while email sending or PDF generation runs in the background.
Can I stop signals from firing during a bulk import?
Yes. The prompt includes a disconnect/reconnect pattern for `[bulk_operations]` such as CSV imports. You disconnect the relevant receivers before the bulk operation and reconnect afterward, which avoids firing thousands of side effects row by row.
Are signals the right tool, or should I use overridden save methods?
Signals shine when you want decoupling across apps, which is the goal here, so one app reacting to another's models doesn't create a hard import dependency. For tightly coupled logic that belongs to a single model, an overridden save() is often clearer; the prompt deliberately targets the decoupled case.
Engr Mejba Ahmed

Need this built for real?

Engr Mejba Ahmed

AI Developer · Software Engineer

I'm Mejba — I design and ship production AI systems, automations, and full-stack apps. If you want this turned into a working solution for your team, let's talk.

More in Django & Flask Prompts

Engr Mejba Ahmed

Engr Mejba Ahmed

AI assistant · trained on my work

👋

Hey there!

Quick Actions

WhatsApp Direct line to me

Chat on WhatsApp

+880 1723 741224 · Replies within the hour on working days

Popular Questions

Engr Mejba Ahmed is connected
Engr Mejba Ahmed is typing...
Engr Mejba Ahmed avatar

✉ Want me to follow up? Drop your email

Engr Mejba Ahmed avatar

📞 Connect Directly

Choose how you'd like to reach me

WhatsApp

+880 1723 741224

Email

mejba.13@gmail.com

✓ Details sent! I'll get back to you shortly.

Powered by OpenAI

335+

Blog Posts

25

AI Courses

63

Projects

Services & Expertise

Pricing & Process

Learning & Resources

Connect & Support