Context
I have working code copied from a tutorial a while back. Through a post_save
signal, it fulfills its purpose which is to automatically create a Profile
object when a CustomUser
object is created. The tutorial helped get it up and running, but I would like to understand what’s happening more fully and know if there’s a better way to go about it because I’ve come across several more knowledgable people saying or writing about in passing how signals are really good for specific use cases but can sometimes be overused. It’s unclear to me what those specific use cases are, so I don’t know if this is a good use of signals or there’s a better way. Additionally, the tutorial also did not include tests, so I added a test for the create_profile()
myself and welcome feedback.
Questions:
- Is this example a good use case for when to use a
post_save
signal?
1a. If no, what would you recommend I use instead of the signal to achieve the same goal? - The tutorial showed what to write for
create_profile()
andpost_save.connect()
but didn’t explain what was being written. I found the Django docs sections post_save signal and signal.connect() which helped me understand what’s going on (at least at a high level), however one part I still don’t understand is why**kwargs
is there as a parameter. What is that part doing to help in this case? For context, I still have a rudimentary understanding of key word arguments as I’m quite new to programming.
Bonus Questions:
3. Do you have any broad rules of thumb for knowing when is a good time to use a signal and when is not a good time to use a signal?
4. Is this test the way you would’ve written it? (I’m not well-versed in writing tests on my own and, while this seems to do what I expect it to, I’m curious if this is how others would approach testing this sort of thing.)
Code excerpts:
Models
# accounts/models.py
from django.contrib.auth.models import AbstractUser, PermissionsMixin
class CustomUser(AbstractUser, PermissionsMixin):
pass
# profiles/models.py
import uuid
from django.contrib.auth import get_user_model
from django.db import models
from django.db.models.signals import post_save
from django.urls import reverse
CustomUser = get_user_model()
class Profile(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
def __str__(self):
return self.user.username
# Create Profile When New User Signs Up
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
post_save.connect(create_profile, sender=CustomUser)
Test
from django.contrib.auth import get_user_model
from django.test import TestCase
from .models import Profile
class ProfileTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.user = get_user_model().objects.create_user(
username="testuser",
email="test@email.com",
password="secret",
)
def test_profile_created(self):
self.assertEqual(self.user.profile, Profile.objects.get(user=self.user))
Thank you in advance.