I need to trigger a profile creation every time a User is registered. I can either override the save() method on my User model or use a post_save signal. I've read conflicting opinions—some say signals make the code harder to debug because they are "magical," while others say overriding save() is bad for decoupling. In a large-scale Django project, which one is considered the cleaner architectural choice?
3 answers
Signals are better for keeping apps separate. Use the post_save signal for creating profiles; it keeps your User model clean and focused only on authentication data.
Overriding the save() method is generally preferred for logic that is internal to the model itself. However, for cross-app communication, signals are the way to go. If your 'User' model is in one app and the 'Profile' model is in another, overriding save() creates a tight coupling where the User app must know about the Profile app. Signals allow the Profile app to "listen" for changes without the User app ever knowing it exists. The "magic" of signals can be mitigated by keeping them in a dedicated signals.py file and documenting them well in your app's ready() method.
Have you considered that signals don't fire during bulk updates? If you use User.objects.bulk_create(), your profiles won't be created automatically. Does that affect your use case?
Matthew brings up a critical point. This is the #1 "gotcha" with signals. If your application relies on bulk operations for performance, signals will leave your data in an inconsistent state. In those cases, a service layer (a separate function that handles both User and Profile creation) is actually superior to both signals and the save() method. It makes the transaction explicit and avoids the hidden side effects that make signals so difficult for new developers to trace.
I agree with Nancy. Keeping the models decoupled makes it much easier to reuse the apps in different projects later on without dragging in extra dependencies.