Django信号与重写保存方法

问题描述 投票:75回答:6

我在缠绕这个问题时遇到了麻烦。现在我有一些看起来像这样的模型:

 def Review(models.Model)
    ...fields...
    overall_score = models.FloatField(blank=True)

def Score(models.Model)
    review = models.ForeignKey(Review)
    question = models.TextField()
    grade = models.IntegerField()

评论有几个“分数”,整体分数是分数的平均值。保存评论或分数时,我需要重新计算total_score平均值。现在我正在使用重写的保存方法。使用Django的信号调度程序会有什么好处吗?

python django django-models django-signals
6个回答
77
投票

保存/删除信号通常适用于需要进行不完全特定于相关模型的更改的情况,或者可以应用于具有某些共同点的模型,或者可以配置为跨模型使用的模型。

覆盖save方法的一个常见任务是从模型中的某些文本字段自动生成slu。这是一个例子,如果你需要为许多模型实现它,将会受益于使用pre_save信号,其中信号处理程序可以采用slug字段的名称和字段的名称来生成slug 。一旦你有这样的东西,你实施的任何增强功能也将适用于所有模型 - 例如查找要为相关型号添加的slug,以确保唯一性。

可重复使用的应用程序通常受益于信号的使用 - 如果它们提供的功能可以应用于任何模型,它们通常(除非它是不可避免的)不希望用户必须直接修改他们的模型才能从中受益。

例如,使用django-mptt,我使用pre_save信号来管理一组字段,这些字段描述了即将创建或更新的模型的树结构,并且pre_delete信号用于删除要删除的对象的树结构细节及其整个它之前的对象的子树,它们被删除。由于信号的使用,用户不必在他们的模型上添加或修改savedelete方法来为他们完成管理,他们只需要让django-mptt知道他们想要管理哪些模型。


17
投票

您询问:

使用Django的信号调度程序会有什么好处吗?

我在django文档中发现了这个:

在批量操作上不会调用重写的模型方法

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

遗憾的是,在批量创建或更新对象时没有解决方法,因为没有调用save(),pre_save和post_save。

来自:Overriding predefined model methods


3
投票

如果您使用信号,则每次保存相关分数模型时您都可以更新评分。但是,如果不需要这样的功能,我没有看到任何理由将其置于信号中,这是与模型相关的相当重要的东西。


2
投票

这是一种非规范化。看看这个pretty solution。就地组成字段定义。


1
投票

Django文档中关于批量删除的小补充(.delete()对象上的QuerySet方法):

请记住,只要有可能,这将完全在SQL中执行,因此在此过程中不一定会调用各个对象实例的delete()方法。如果您在模型类上提供了自定义delete()方法并希望确保调用它,则需要“手动”删除该模型的实例(例如,通过迭代QuerySet并调用delete()on每个对象单独)而不是使用QuerySet的批量delete()方法。

https://docs.djangoproject.com/en/1.11/topics/db/queries/#deleting-objects

和批量更新(.update()对象上的QuerySet方法):

最后,意识到update()在SQL级别进行更新,因此不会在模型上调用任何save()方法,也不会发出pre_save或post_save信号(这是调用Model.save的结果) ))。如果要为具有自定义save()方法的模型更新一组记录,请循环遍历它们并调用save()

https://docs.djangoproject.com/en/2.1/ref/models/querysets/#update


-27
投票

当您必须执行某些长期过程并且不想阻止用户等待保存完成时,信号非常有用。

© www.soinside.com 2019 - 2024. All rights reserved.