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

在我的应用程序中,我想在新用户注册时在某些表中创build条目。 例如,我想创build一个用户configuration文件,然后引用他们的公司和其他一些logging。 我用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") 

运行时运行良好。 我可以使用pipe理员创build一个新的用户,其他三个表也可以通过合理的方式获得条目。 (除了user.first_name和user.last_name之外的员工,在保存的时候并没有用pipe理员的forms填写,我还是不明白为什么这样做)

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

 IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key" 

我认为这是因为我已经在id为“1”的夹具中创build了公司,员工和个人档案logging,现在post_save信号正在尝试重新创build它。

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

人们如何做到这一点?

我想我想出了一个办法来做到这一点。 kwargs中有一个'raw'参数和信号一起传入,所以我可以用上面的这个来代替我的testing:

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

Raw在loaddata运行时使用。 这似乎是诀窍。

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

会很好,如果这是logging: http : //docs.djangoproject.com/en/1.2/ref/signals/#django.db.models.signals.post_save

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

 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 ... 

简单的解决scheme,将此添加到您的post_save函数的开始:

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

这将导致此function在加载灯具时退出。

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

我的一个项目遇到了类似的问题。 在我的情况下,信号也放慢了testing。 我最终放弃了信号,赞成重写Model.save()方法。

在你的情况,但我不认为这是通过覆盖任何save()方法来实现这一点。 在这种情况下,你可能想试试这个。 警告,我只试过一次。 它似乎工作,但没有经过彻底的testing。

  1. 创build你自己的testing跑步者 。
  2. 在加载灯具之前,请断开 User类的post_save信号中的callback_create_profile函数。
  3. 让灯具加载。
  4. 将function连接回信号。