5

我为我的模型编写了一些智能通用计数器和管理器(以避免select count查询等)。因此,我对 post_save 进行了一些繁重的逻辑。

我想防止在不需要时处理信号。我想完美的界面应该是:

instance.save(dispatch_signal=False)

我怎样才能做到这一点?


更新

如果有人感兴趣,请提供有关我在做什么的更多信息:

  1. 通用计数器存储在单独的表中
  2. 每次 Django 对对象列表进行分页时,它都会调用我的自定义管理器的重写 count() 方法,该方法基本上检索适当对象类的静态计数器值。
  3. 信号触发计数器更新的逻辑,这有点复杂,因为它检查相关模型的许多方面(即它必须基于嵌套类别树生成可见性属性)。我不能把这个逻辑放在 Model.save() 中,因为一个计数器依赖于许多不同的模型。我希望将这种逻辑整合在一起,而不是碎片散布。
  4. 我正在对我的一些模型进行非规范化,因此我跨表重写(复制)某些值。
  5. 出于测试目的,我运行我的小命令扩展 - Dilla来填充随机数据。
  6. 我注意到触发了不需要的信号,因此我希望它们有条件地运行。

希望它足够清楚。请原谅我的语言错误。

4

4 回答 4

15

您可以断开并重新连接信号。尝试使用with:此实用程序类的语句:

class SignalBlocker(object):
    def __init__(self, signal, receiver, **kwargs):
        self.signal = signal
        self.receiver = receiver
        self.kwargs = kwargs

    def __enter__(self, *args, **kwargs):
        self.signal.disconnect(self.receiver)

    def __exit__(self, *args, **kwargs):
        self.signal.connect(self.receiver, **self.kwargs)

您现在可以使用:

with SignalBlocker(post_save, my_post_save_handler):
    instance.save()
于 2012-06-04T12:49:48.970 回答
15

我找到了简单易行的解决方案:

MyModel.objects.filter(pk=instance.id).update(**data)

这是由于(https://docs.djangoproject.com/en/1.5/ref/models/querysets/#update):

最后,请意识到 update() 在 SQL 级别进行更新,因此不会在模型上调用任何 save() 方法,也不会发出 pre_save 或 post_save 信号(这是调用 Model.save( ))。

于 2013-05-15T03:25:55.847 回答
14

一个快速而肮脏的解决方案是:

from django.db.models.signals import post_save
from somewhere_in_my_app import my_post_save_handler

post_save.disconnect(my_post_save_handler)
instance.save()
post_save.connect(my_post_save_handler)

但除此之外,我强烈建议将您的逻辑转移到save()模型的方法中。

于 2009-02-23T12:05:29.197 回答
2

您还可以在您的或信号处理程序中调用instance.save_base(raw=True)并检查raw参数:pre_savepost_save

def my_post_save_handler(instance, raw, **kwargs):
    if not raw:
        heavy_logic()

您可以添加一些糖并获得完美的界面:

class MyModel:
    def save(self, dispatch_signal=True, **kwargs):
        self.save_base(raw=not dispatch_signal, **kwargs)

请注意,这save_base()不是 Django 的公共 API 的一部分,因此它可能会在未来的版本中更改。

于 2009-09-14T10:39:02.690 回答