In my application, I want to create entries in certain tables when a new user signs up. For instance, I want to create a userprofile which will then reference their company and some other records for them. I implemented this with a post_save signal:
def callback_create_profile(sender, **kwargs): # check if we are creating a new User if kwargs.get('created', True): user = kwargs.get('instance') company = Company.objects.create(name="My Company") employee = Employee.objects.create(company=company, name_first=user.first_name, name_last=user.last_name) profile = UserProfile.objects.create(user=user, employee=employee, partner=partner) # Register the callback post_save.connect(callback_create_profile, sender=User, dispatch_uid="core.models")
This works well when run. I can use the admin to create a new user and the other three tables get entries with sensible as well. (Except that is, the employee since the user.first_name and user.last_name aren't filled out in the admin's form when it saves. I still don't understand why it is done like that)
The problem came when I ran my test suite. Before this, I had created a bunch of fixtures to create these entries in the tables. Now I get an error that states:
IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key"
I think this is because I have already created a company,employee and profile records in the fixture with id "1" and now the post_save signal is trying to recreate it.
My questios are: can I disable this post_save signal when running fixtures? Can I detect that I am running as part of the test suite and not create these records? Should I delete these records from the fixtures now (although the signal only sets defaults not the values I want to be testing against)? Why doesn't the fixture loading code just overwrite the created records?
How do people do this?
Django Signals - post_delete()To notify another part of the application after the delete event of an object happens, you can use the post_delete signal.
Like most of Django, they are fully "synchronous".
There are 3 types of signal. pre_save/post_save: This signal works before/after the method save(). pre_delete/post_delete: This signal works before after delete a model's instance (method delete()) this signal is thrown. pre_init/post_init: This signal is thrown before/after instantiating a model (__init__() method).
I think I figured out a way to do this. There is a 'raw' parameter in the kwargs passed in along with signals so I can replace my test above with this one:
if (kwargs.get('created', True) and not kwargs.get('raw', False)):
Raw is used when loaddata is running. This seems to do the trick.
It is mentioned here: http://code.djangoproject.com/ticket/13299
Would be nice if this was documented: http://docs.djangoproject.com/en/1.2/ref/signals/#django.db.models.signals.post_save
This is an old question, but the solution I've found most straightforward is to use the 'raw' argument, passed by load data, and decorate the listener functions, for example:
from functools import wraps def disable_for_loaddata(signal_handler): @wraps(signal_handler) def wrapper(*args, **kwargs): if kwargs['raw']: print "Skipping signal for %s %s" % (args, kwargs) return signal_handler(*args, **kwargs) return wrapper
and then
@disable_for_loaddata def callback_create_profile(sender, **kwargs): # check if we are creating a new User ...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With