In views.py I have the following view which gets called when a new user account is registered. All it does is get the username, email, and password from the request, then try to create a user with those credentials. In the code below, "A" gets printed, but "B" does not, because it crashes:
views.py
def register(request):
if request.method == 'POST':
query_dict = request.POST
username = query_dict['username']
email = query_dict['user_email']
password = query_dict['password']
role = query_dict['role']
print "A"
user = User.objects.create_user(username, email, password)
# the handler is called here and creates the user profile
print "B"
user = authenticate(username=username, password=password)
user_profile = user.get_profile()
user_profile.role = role
user_profile.save()
if user is not None and user.is_active:
login(request, user)
return HttpResponseRedirect("/")
In myapp/models.py
I have the following code for the handler.
'models.py`
post_save.connect(create_user_profile, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
print "created="+str(created)
if created: # as opposed to being saved after being created earlier, I assume
print "attempting to create a user profile for "+instance.username
up = UserProfile.objects.create(user=instance)
print "created a new UserProfile: <"+str(up)+">"
When I run my app, the print output is:
A
created=True
attempting to create a user profile for john
created a new UserProfile: <john - >
created=True
attempting to create a user profile for john
~~~~CRASHES~~~~
I have noticed throughout my development over the last couple of days that the create_user_profile
method gets called twice when I run User.objects.create_user(username, email, password)
I copied the handler code directly out of the docs, so I'm pretty sure it correct (https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users). I don't know exactly where in the django code the create_user_profile
method gets called from, but I am assuming that it sets the created
flag to true only if the save method that invoked the handler was due to an object being created. Over the last couple of days this code has been working correctly, but all of a sudden today the second time the create_user_profile
method gets called by the handler, the created
flag is set to true, just like it was the first time. This is causing my app to crash with an IntegrityError
, complaining that it can't create two objects with the same primary key.
So there are two things I don't understand. First: why does post_save happen twice when I only called User.objects.create_user(username, email, password)
once; second: why did the created
flag all of a sudden stop working like expected?
How can I debug this?
Thanks
It is possible that your models.py file is being imported, and run, twice. In this case, the same signal handler would be attached twice, and would fire twice when a model instance is saved.
This can easily happen if you import it once as
import myapp.models
and again as
import myproject.myapp.models
Printing something to the console at the top of the file might give you an idea whether that is what is happening or not.
Regardless, you can prevent a signal handler from being registered multiple times by giving it a unique dispatch_uid
. Django will check on Signal.connect
to see if a handler has already been registered for the same sender with the same UID, and will not re-register it if it has.
Change your signal connecting code to something like
post_save.connect(create_user_profile, sender=User, dispatch_uid='create_user_profile')
and see if that helps