【问题标题】:Pass additional parameters to post_save signal将附加参数传递给 post_save 信号
【发布时间】:2012-06-24 16:56:42
【问题描述】:

我的 Django 应用程序中有一个用户注册表单,它在用户尝试注册时收集其他数据,例如地址、城市、国家/地区、电话号码等。

此数据通过post_save 信号保存在Account 模型类中。用户创建过程是这样的:

# Function to Create user Account/Profile
def create_user_account(sender, instance, created, **kwargs):
    if created:
      models.Account.objects.create(user=instance)

# Create User / User Registration
def UserRegistration(request):
    if request.method == 'POST':
        username = request.POST['fn'].capitalize() + ' ' + request.POST['ln'].capitalize()
        # CREATE USER
        newuser = User.objects.create_user(username=username, email=request.POST['email'], password=request.POST['pw'])
        newuser.first_name = request.POST['fn'].capitalize()
        newuser.last_name = request.POST['ln'].capitalize()
        newuser.save()
    return HttpResponse(username)

#Post Save handler to create user Account/Profile
post_save.connect(create_user_account, sender=User)

这里UserRegistration函数在用户发布表单时被调用,在这个函数下,我可以获得POST数据,我想要的是将数据传递给create_user_account方法,以便它填写Account 模型。

现在,我确实看到在数据库中创建了Account 对象,但是除了用户字段之外的所有字段都是空的。显然,因为 POST 变量没有被传递给create_user_account 方法。

【问题讨论】:

  • ... 但是在您的示例中,您已经将所有信息存储在您的用户模型('fn','ln')中,因此您应该能够通过 instance.first_name 在您的create_user_account 函数。或者我错过了什么?
  • 如果你想使用一些来自 POST 的数据,你应该在视图中创建Account。 Signals 不是为此而设计的。
  • @arie 还有更多数据尚未被该方法使用。
  • @astynax 谢谢,看来我需要这样做..

标签: python django


【解决方案1】:

我所做的是为实例设置一些“_attrs”,然后在信号处理程序中使用它们。

我想你的情况可能是:

# Function to Create user Account/Profile
def create_user_account(sender, instance, created, **kwargs):
    if created:
        attrs_needed = ['_language', '_field', '_otherfield']
        if all(hasattr(instance, attr) for attr in attr_needed):
            models.Account.objects.create(
                user=instance, 
                language=instance._language, 
                field=instance._field,
                otherfield=instance._otherfield)

# Create User / User Registration
def UserRegistration(request):
  if request.method == 'POST':
    username = request.POST['fn'].capitalize() + ' ' + request.POST['ln'].capitalize()
    # CREATE USER
    newuser = User.objects.create_user(
        username=username, email=request.POST['email'],
        password=request.POST['pw'])
    newuser.first_name = request.POST['fn'].capitalize()
    newuser.last_name = request.POST['ln'].capitalize()

    # Set some extra attrs to the instance to be used in the handler.
    newuser._language = request.POST['language']
    newuser._field = request.POST['field']
    newuser._otherfield = request.POST['otherfield']
    newuser.save()


  return HttpResponse(username)

#Post Save handler to create user Account/Profile
post_save.connect(create_user_account, sender=User)

我讨厌这样做,我想它可能会以可怕的方式中断,有时很难调试,也没有严格的方法来强制处理程序所需的数据,可以定义一个 signal_data(data, signal, instance) 到为特定实例定义信号处理程序所需的数据。

我没有尝试过的一个不错的选择是使用实例的方法作为信号的处理程序,也许我们可以使用更结构化的方式来传递数据。

再见。

【讨论】:

  • 感谢您抽出宝贵时间回答这个问题。为了克服这个问题,我基本上决定按照@astynax 的建议在视图本身中调用帐户模型创建方法
  • 所以首先创建用户对象,然后创建帐户模型中的用户帐户,两者都在同一个发布请求下..
  • 我已经编辑了代码,因为它有一个错误,现在我在保存之前设置了 attrs。
  • 感谢您发布此信息。尝试使用它,但 newuser._language 给我一个错误 - 'User' 对象没有属性 '_language'。有什么建议吗?
  • 对我来说User.objects.create_user( 立即触发post_save 处理程序。如何延长 post_save 处理程序以便我可以在 User 对象上设置一些属性?
【解决方案2】:

User.objects.create_userUser.objects.create 都会立即触发 post_save 处理程序,因为在 UserManager create_user 中调用了 save。所以我无法想象豪尔赫的答案是如何起作用的(至少如果你希望保存只被触发一次 - 你为什么要触发它两次???)。您要做的是研究 create_user 做了什么,剖析它,这样您就可以真正控制何时调用 save

# Function to Create user Account/Profile
def create_user_account(sender, instance, created, **kwargs):
    if created:
        attrs_needed = ['_language', '_field', '_otherfield']
        if all(hasattr(instance, attr) for attr in attr_needed):
            models.Account.objects.create(
                user=instance, 
                language=instance._language, 
                field=instance._field,
                otherfield=instance._otherfield)

# Create User / User Registration
def UserRegistration(request):
  if request.method == 'POST':
    username = request.POST['fn'].capitalize() + ' ' + request.POST['ln'].capitalize()
    # CREATE USER
    newuser = User(
        username=username,
        email=request.POST['email'],
        first_name=request.POST['fn'].capitalize()
        last_name = request.POST['ln'].capitalize()
    )
    newuser.set_password(request.POST['pw'])

    # Set some extra attrs to the instance to be used in the handler.
    newuser._language = request.POST['language']
    newuser._field = request.POST['field']
    newuser._otherfield = request.POST['otherfield']
    newuser.save()  # Now this will be really the first save which is called

  return HttpResponse(username)

#Post Save handler to create user Account/Profile
post_save.connect(create_user_account, sender=User, weak=False)

请注意,我在连接处理程序时也会使用weak=False

【讨论】:

  • 这个答案应该有效。批准的答案与此答案中的解释错误,谢谢
【解决方案3】:

我发现receiver(post_save, sender=User)在我们使用create_usercreate方法时会立即被调用, 所以,我们需要先初始化对象,然后填充额外的字段。

【讨论】:

    猜你喜欢
    • 2011-12-21
    • 2013-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多