【问题标题】:How to use a pre_delete signal to universally prevent delete?如何使用 pre_delete 信号来普遍防止删除?
【发布时间】:2020-04-23 11:13:37
【问题描述】:

我的所有模型都有一个公共字段is_active = models.BooleanField()

我想为删除函数创建一个通用覆盖,以便 is_active = False 而不是从数据库中删除记录。

我知道最好的方法是使用pre_delete 信号,而不是将delete() 本身覆盖为delete() is not called in bulk operations

我尝试了以下实现:

@receiver(pre_delete)
def delete_obj(sender, instance, **kwargs):
    """Override delete() to set object to inactive."""

    return instance.is_active == False

但是,这仍然会导致从数据库中删除对象。我认为这是因为delete()pre_delete 之后仍然被调用。我该如何纠正这个问题?

来自文档:

请注意,当使用 QuerySet 批量删除对象或作为级联删除的结果时,不一定会调用对象的 delete() 方法。为确保执行自定义删除逻辑,您可以使用 pre_delete 和/或 post_delete 信号。

【问题讨论】:

  • 我认为唯一可能的方法是覆盖delete 函数。如果删除是通过关系级联的,您可能还需要考虑这种情况。
  • @adnanmuttaleb 谢谢,但如果我批量删除查询集中的项目,那将无济于事,因为那时不会调用 delete()
  • 可以使用 pre_delete 但不是重新发明轮子,您可以使用 django-model-utils.readthedocs.io/en/latest/…
  • @iklinac 谢谢这很有帮助,如果可能的话,我想了解这个问题背后的原因以及修复它的代码/语法。
  • @alias51 进行批量操作,您可以遍历您的查询集并手动调用您的自定义 delete 方法。这当然性能较差,但会保持数据完整性。

标签: django django-signals


【解决方案1】:

您想替换原始方法的逻辑(在这种情况下,执行更新而不是删除)扩展它。

信号扩展 ma​​in方法逻辑,而不是替换它。

pre_ 信号中 - 在操作之前运行一些额外的逻辑(甚至可能修改对象)。在post_ 信号中 - 在主要操作之后运行一些额外的逻辑。但主要动作仍在运行 - 它应该 - 它在代码中被正确调用 - 信号不应该取代它。

类似于模型上的扩展方法:您将在调用super().method() 之前或之后添加一些逻辑 - 这就是信号的工作方式。

如果用另一个方法逻辑替换方法逻辑 - 当覆盖方法 super() 时很可能不会被调用,因此不会执行原始操作。


因此,要用自定义逻辑替换 delete(),您可以覆盖模型的 delete() 方法,并使用覆盖 delete() 方法的模型的自定义 QuerySet,因此在模型实例或 QuerySet 上调用 delete() 时 - 它会执行而是更新。


Link to surce code where QuerySet delete is performed:

  • pre_delete 信号已发送
  • delete_batch被执行
  • post_delete 信号已发送

【讨论】:

    猜你喜欢
    • 2012-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 2021-12-07
    • 1970-01-01
    相关资源
    最近更新 更多