更好地处理Django信号管理

时间:2014-04-11 21:26:45

标签: python django signals

好吧,我有一个django项目工作正常。

在这个项目中,我有以下模型:

class A:
    b = models.ForeignKey(B)
    c = models.ForeignKey(C)
    d = models.ForeignKey(D)
    last_update = models.DateTimeField()

class B:
    # whatever

class C:
    # whatever

class D:
    # whatever

class E:
    a = models.ForeignKey(A)

# And more models...

所以一般的想法是我有模型A,这是我的结构的核心。还有一些其他模型可以参考或引用模型A.

真正的问题是' last_update'模型A的领域。理想情况下,' last_update'当发生以下任何情况时,将更新为当前时间戳:

  1. 用户修改模型A的字段值

  2. 用户添加,更改,删除B类,C,D

  3. 用户添加,更改,删除E类

  4. 对此的一般方法是覆盖每个模型的.save()或将信号挂钩到每个模型的pre_save。

    然而,我想要更清洁的东西。理想情况下,我只需要一种接收不同信号并以相同方式作出反应的方法 - 更新' last_update'模型A的领域。

    提前致谢。

    PS:请不要提及有关数据库级别修改的解决方案(我的意思是触发器)。我们只关注Django。

1 个答案:

答案 0 :(得分:1)

如果这是您应用的核心,您可能需要创建一个通用信号接收器来监听所有模型保存。如果您仍然有很多模型没有直接连接到A模型,那么您可能不想这样做。

import datetime

@receiver(post_save, sender=None, dispatch_uid='update_last_modified')
def update_last_modified(sender, instance, raw, using, update_fields):
    if raw: # database might not be in a consistent state yet
        return
    if sender in (B, C, D): # all models which A has a fk/m2m to
        qs = instance.a_set.using(using)
    elif sender in (E,): # all models which have a fk/o2o to A
        qs = A.objects.filter(pk=instance.a.pk).using(using)
    elif sender is A:
        qs = A.objects.filter(pk=instance.pk).using(using)
    try:
        qs.update(last_update=datetime.datetime.now())
    except NameError:
        pass

通过构造查询集并使用update方法,可以防止在保存单个实例时多次触发信号。

我会挂钩post_save方法而不是pre_save方法,以便在触发信号之前保存新创建的对象的m2m关系,并last_update字段为如果在第一种情况下保存模型时发生错误,则不会更新。