在views.py中,我有以下视图,在注册新用户帐户时会调用该视图。它所做的就是从请求中获取用户名,电子邮件和密码,然后尝试使用这些凭据创建用户。在下面的代码中,“A”被打印,但“B”没有,因为它崩溃了:
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("/")
在myapp/models.py
中,我为处理程序提供了以下代码。
'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)+">"
当我运行我的应用程序时,打印输出为:
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~~~~
我在整个开发过程中注意到,create_user_profile
方法在运行User.objects.create_user(username, email, password)
时被调用了两次我直接从文档中复制了处理程序代码,所以我很漂亮确定它是正确的(https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users)。我不确切地知道调用create_user_profile
方法的django代码中的确切位置,但我假设只有在调用处理程序的save方法是由于时才将created
标志设置为true正在创建的对象。在过去的几天里,这段代码一直在正常工作,但是今天突然间第二次create_user_profile
方法被处理程序调用,created
标志被设置为true,就像它一样这是第一次。这导致我的应用程序崩溃IntegrityError
,抱怨它无法使用相同的主键创建两个对象。
所以有两件事我不明白。第一:当我只调用User.objects.create_user(username, email, password)
一次时,为什么post_save会发生两次;第二:为什么created
标志一下子就像预期的那样停止工作?
我该如何调试?
由于
答案 0 :(得分:7)
您的models.py文件可能正在导入并运行两次。在这种情况下,相同的信号处理程序将连接两次,并在保存模型实例时触发两次。
如果您将其导入一次
,则很容易发生这种情况import myapp.models
再次作为
import myproject.myapp.models
将某些内容打印到文件顶部的控制台可能会让您了解这是否正在发生。
无论如何,通过为信号处理程序提供唯一的dispatch_uid
,可以防止多次注册信号处理程序。 Django将检查Signal.connect
以查看处理程序是否已为具有相同UID的同一发件人注册,如果有,则不会重新注册。
将连接代码的信号更改为
post_save.connect(create_user_profile, sender=User, dispatch_uid='create_user_profile')
并查看是否有帮助