Connecting Django REST Framework (DRF) with Django Signals

Last updated 4 months ago | 345 views 75     5

Tags:- Python Django DRF

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.pyready() method.

  • Use created in post_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.