如何防止灯具与django post_save信号代码冲突?

pos*_*ald 47 python django signals django-signals fixtures

在我的应用程序中,我想在新用户注册时在某些表中创建条目.例如,我想创建一个userprofile,然后引用他们的公司和其他一些记录.我用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")
Run Code Online (Sandbox Code Playgroud)

运行时效果很好.我可以使用admin创建一个新用户,其他三个表也可以获得合理的条目.(除此之外,员工因为user.first_name和user.last_name在保存时未在管理员表单中填写.我仍然不明白为什么这样做)

当我运行我的测试套件时出现问题.在此之前,我创建了一堆灯具来在表格中创建这些条目.现在我收到一条错误,指出:

IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key"
Run Code Online (Sandbox Code Playgroud)

我想这是因为我已经在id为"1"的灯具中创建了公司,员工和个人资料记录,现在post_save信号正在尝试重新创建它.

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

人们如何做到这一点?

pos*_*ald 70

我想我找到了一种方法来做到这一点.传入的kwargs中有一个'raw'参数和信号,所以我可以用上面的代码替换上面的测试:

if (kwargs.get('created', True) and not kwargs.get('raw', False)):
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 好方案!今天早上你让我很头疼.为了简化这一点,可以使用命名参数`created`并删除多余的括号:``如果创建而不是kwargs.get('raw',False):`` (2认同)

bjw*_*bjw 18

这是一个老问题,但我发现最直接的解决方案是使用'raw'参数,通过加载数据传递,并修饰监听器函数,例如:

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
Run Code Online (Sandbox Code Playgroud)

然后

@disable_for_loaddata
def callback_create_profile(sender, **kwargs):
    # check if we are creating a new User
    ...
Run Code Online (Sandbox Code Playgroud)

  • 值得指出的是,m2m 信号不提供“原始”标志。我不知道如何解决这个问题。 (2认同)

小智 12

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

if kwargs.get('raw', False):
    return False
Run Code Online (Sandbox Code Playgroud)

这将导致此功能在加载夹具时退出.

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