53

在我的应用程序中,我想在新用户注册时在某些表中创建条目。例如,我想创建一个用户资料,然后为他们引用他们的公司和其他一些记录。我用 post_save 信号实现了这个:

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")

这在运行时效果很好。我可以使用管理员创建一个新用户,而其他三个表也可以使用 sensible 获取条目。(除了user.first_name和user.last_name以来的员工在保存时没有填写在admin的表单中。我还是不明白为什么会这样)

当我运行我的测试套件时,问题就来了。在此之前,我已经创建了一堆固定装置来在表格中创建这些条目。现在我收到一条错误消息:

IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key"

我认为这是因为我已经在 id 为“1”的夹具中创建了公司、员工和个人资料记录,现在 post_save 信号正在尝试重新创建它。

我的问题是:我可以在运行灯具时禁用这个 post_save 信号吗?我可以检测到我作为测试套件的一部分运行而不创建这些记录吗?我现在应该从夹具中删除这些记录吗(尽管信号只设置默认值而不是我想要测试的值)?为什么夹具加载代码不会覆盖创建的记录?

人们如何做到这一点?

4

4 回答 4

80

我想我想出了一个办法来做到这一点。与信号一起传入的 kwargs 中有一个“原始”参数,所以我可以用这个替换上面的测试:

if (kwargs.get('created', True) and not kwargs.get('raw', False)):

运行 loaddata 时使用 Raw。这似乎可以解决问题。

这里提到:http: //code.djangoproject.com/ticket/13299

如果记录在案会很好:http: //docs.djangoproject.com/en/1.2/ref/signals/#django.db.models.signals.post_save

于 2010-08-17T06:57:18.737 回答
23

这是一个老问题,但我发现最直接的解决方案是使用加载数据传递的“原始”参数,并装饰侦听器函数,例如:

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

接着

@disable_for_loaddata
def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    ...
于 2012-07-10T08:53:18.240 回答
13

简单的解决方案,将其添加到 post_save 函数的开头:

if kwargs.get('raw', False):
    return False

这将导致此函数在加载夹具时退出。

请参阅:https ://docs.djangoproject.com/en/dev/ref/signals/#post-save

于 2014-02-10T17:15:33.560 回答
3

我在我的一个项目中遇到了类似的问题。就我而言,信号也在减慢测试速度。我最终放弃了信号,转而重写了一个Model.save()方法。

但是,在您的情况下,我认为通过覆盖任何save()方法来实现这一点是没有意义的。在这种情况下,您可能想尝试一下。警告,我只试过一次。它似乎有效,但没有经过彻底测试。

  1. 创建您自己的测试运行器
  2. 在加载固定装置之前,请断开callback_create_profile函数与 Userpost_save信号的连接。
  3. 让固定装置加载。
  4. 将函数连接回信号。
于 2010-08-17T06:40:09.067 回答