Connecting Django REST Framework (DRF) with Django Signals
Last updated 4 months ago | 345 views 75 5

Introduction: Why Combine Django Signals with DRF?
In modern web applications, many things need to happen automatically when data changes — like sending an email after user registration, logging changes, or triggering third-party APIs.
If you're using Django REST Framework (DRF), your API views typically handle creation and updates. But how do you run automatic post-save logic globally?
That’s where Django signals come in.
Signals like post_save
, pre_save
, post_delete
, and more allow you to attach automated actions to your models — and they work seamlessly with DRF serializers and views.
This article shows you how to connect Django signals with DRF-based workflows, step by step.
⚙️ Step-by-Step: Connecting DRF with Django Signals
Step 1: Create a Django Model
# models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(blank=True)
joined_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"Profile of {self.user.username}"
Step 2: Create a DRF Serializer
# serializers.py
from rest_framework import serializers
from .models import Profile
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ['id', 'user', 'bio', 'joined_at']
Step 3: Write a Signal Handler
# signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Profile
from django.core.mail import send_mail
@receiver(post_save, sender=Profile)
def send_welcome_email(sender, instance, created, **kwargs):
if created:
# Example action: send email
send_mail(
subject='Welcome!',
message=f"Hello {instance.user.username}, thanks for joining.",
from_email='[email protected]',
recipient_list=[instance.user.email],
)
Step 4: Connect the Signal
You must make sure the signals.py
is imported when the app starts:
# apps.py
from django.apps import AppConfig
class YourAppConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'your_app'
def ready(self):
import your_app.signals # Connect signals here
Step 5: Create an API View
# views.py
from rest_framework import viewsets
from .models import Profile
from .serializers import ProfileSerializer
class ProfileViewSet(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
Step 6: Hook the ViewSet into URLs
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProfileViewSet
router = DefaultRouter()
router.register(r'profiles', ProfileViewSet)
urlpatterns = [
path('api/', include(router.urls)),
]
Complete Functional Example
You now have:
✅ A Profile
model
✅ A ProfileSerializer
using DRF
✅ A ProfileViewSet
to manage API endpoints
✅ A post_save
signal sending a welcome email after each new profile is created via the API
Whether you create the object via the Django admin, Django shell, or a DRF endpoint — the signal will always fire!
Comparison Table: Signals vs Serializer Hooks
Feature | Django Signals | DRF Serializer Methods |
---|---|---|
Scope | Global | Local to API |
Works outside API | ✅ Yes | ❌ No |
Best for | Decoupled tasks | API-specific logic |
Debugging | Can be tricky | Easier to trace |
Risk of silent failure | Medium | Low |
⚠️ Tips & Common Pitfalls
✅ Best Practices
-
Always register signals inside
apps.py
→ready()
method. -
Use
created
inpost_save
to avoid triggering the signal on every update. -
Keep signal logic short and focused — for heavy lifting, call a separate service.
❌ Common Pitfalls
-
Forgetting to import your
signals.py
results in no signals firing. -
Triggering infinite loops if the signal modifies and saves the same model.
-
Using signals where you need request context (use serializer hooks in such cases).
Conclusion: Best Practices for Using Signals with DRF
Combining Django signals with DRF gives you powerful control over automated backend logic — across your API and admin interfaces.
Key Takeaways
-
Use signals for reusable, global logic (emailing, logging, etc.).
-
Use serializer hooks for request-specific behavior.
-
Keep your signal logic clean, minimal, and easy to debug.
By mastering this integration, your Django applications become more modular, automated, and maintainable.