Django Signals
paystack-django sends Django signals for payment events, allowing you to hook into the payment lifecycle.
Available Signals
paystack_charge_success
Sent when a payment is successful:
from django.dispatch import receiver
from djpaystack.signals import paystack_charge_success
@receiver(paystack_charge_success)
def on_payment_success(sender, transaction=None, **kwargs):
"""Handle successful payment"""
print(f"Payment successful: {transaction.reference}")
paystack_charge_failed
Sent when a payment fails:
from django.dispatch import receiver
from djpaystack.signals import paystack_charge_failed
@receiver(paystack_charge_failed)
def on_payment_failed(sender, transaction=None, **kwargs):
"""Handle failed payment"""
print(f"Payment failed: {transaction.reference}")
paystack_charge_pending
Sent when a payment is pending:
from django.dispatch import receiver
from djpaystack.signals import paystack_charge_pending
@receiver(paystack_charge_pending)
def on_payment_pending(sender, transaction=None, **kwargs):
"""Handle pending payment"""
print(f"Payment pending: {transaction.reference}")
Registering Signals
In your Django app’s apps.py:
from django.apps import AppConfig
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'myapp'
def ready(self):
import myapp.signals
In your signals.py:
from django.dispatch import receiver
from djpaystack.signals import paystack_charge_success
from .models import Order
@receiver(paystack_charge_success)
def update_order_status(sender, transaction=None, **kwargs):
"""Update order status after payment"""
order = Order.objects.get(reference=transaction.reference)
order.status = 'paid'
order.paid_at = timezone.now()
order.save()
Using Signals for Multiple Events
from django.dispatch import receiver
from django.db.models.signals import post_save
from djpaystack.models import Transaction
from djpaystack.signals import paystack_charge_success
# On Paystack transaction model save
@receiver(post_save, sender=Transaction)
def on_transaction_save(sender, instance, created, **kwargs):
if created:
print(f"New transaction: {instance.reference}")
# On custom signal
@receiver(paystack_charge_success)
def on_charge_success(sender, transaction=None, **kwargs):
# Send confirmation email
send_payment_confirmation_email(transaction.email)
Best Practices
Keep signal handlers fast - offload long operations to Celery
Use try-except blocks to avoid crashing signal chain
Log signal events for debugging
Test signals in isolation
Document custom signals
from django.dispatch import receiver
from django.utils import timezone
from djpaystack.signals import paystack_charge_success
from .tasks import send_confirmation_email
@receiver(paystack_charge_success)
def handle_payment_success(sender, transaction=None, **kwargs):
try:
# Log event
logger.info(f"Payment success: {transaction.reference}")
# Offload long operation to Celery
send_confirmation_email.delay(transaction.id)
except Exception as e:
logger.error(f"Error handling payment: {str(e)}")