在 Django 中,当我调用 User.objects.create_user(用户名、电子邮件、密码) 时 - 为什么 post_save 被调用两次?

发布于 2024-12-27 12:21:42 字数 2322 浏览 1 评论 0原文

在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~~~~

在过去几天的整个开发过程中,我注意到当我运行 User.objects.create_user(username) 时,create_user_profile 方法被调用两次,电子邮件,密码) 我直接从文档中复制了处理程序代码,所以我很确定它是正确的(https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users)。我不知道 django 代码中的 create_user_profile 方法是从哪里调用的,但我假设只有在 save 方法满足以下条件时,它才会将 create_user_profile 标志设置为 true调用处理程序是由于创建了一个对象。在过去的几天里,这段代码一直工作正常,但是今天突然之间,处理程序第二次调用 create_user_profile 方法时,设置了 created 标志真实,就像第一次一样。这导致我的应用程序崩溃并出现 IntegrityError,抱怨它无法创建具有相同主键的两个对象。

所以有两件事我不明白。第一:为什么 post_save 发生了两次,而我只调用了一次 User.objects.create_user(用户名,电子邮件,密码) 一次;第二:为什么 created 标志突然停止按预期工作?

我该如何调试这个?

谢谢

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

婴鹅 2025-01-03 12:21:42

您的 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')

,看看是否有帮助

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文