Django信号与覆盖保存方法


89

我无法解决这个问题。现在我有一些看起来像这样的模型:

 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()

一个Review是有几个“分数”,总体分数是分数的平均值。保存评论或分数后,我需要重新计算total_score平均值。现在,我正在使用重写的保存方法。使用Django的信号分配器会有好处吗?

Answers:


84

在需要进行更改的情况下,保存/删除信号通常是有利的,这些更改并非完全针对所讨论的模型,或者可以应用于具有共同点的模型,或者可以配置为在模型之间使用。

覆盖save方法中的一项常见任务是从模型中的某些文本字段自动生成段。这是一个示例,如果您需要为许多模型实现它,则可以受益于使用pre_save信号,其中信号处理程序可以使用slug字段的名称和从中生成slug的字段的名称。一旦具备了类似的功能,所设置的任何增强功能也将适用于所有模型-例如,为有问题的模型类型查找要添加的块,以确保唯一性。

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

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


如果信号处理程序触发异常怎么办?我想它们不应触发异常,否则它们不适合。我错了吗?
x-yuri

20

您问:

使用Django的信号分配器会有好处吗?

我在Django文档中找到了这个:

批量操作中不会调用覆盖的模型方法

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

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

来自:覆盖预定义的模型方法


3
Django管理员列表视图使用批量删除...一直很困惑,直到遇到此花絮。
N.Balauro '17

7
它还说:“不幸的是,批量创建或更新对象时没有解决方法,因为没有调用save(),pre_save和post_save。” -因此,我认为这不是这些方法之间的权衡。
Cory

这对这两种方法都适用,然后答案是:“不,使用信号而不是覆盖该save方法没有好处”?
Flimm

3

如果您使用信号,那么每次保存相关的得分模型时,您都可以更新评论得分。但是,如果不需要这样的功能,我看不出有什么理由将其告知信号,那是与模型相关的东西。



1

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

请记住,这将尽可能地仅在SQL中执行,因此在处理过程中不一定会调用单个对象实例的delete()方法。如果您在模型类上提供了自定义的delete()方法,并希望确保调用该方法,则需要“手动”删除该模型的实例(例如,通过遍历QuerySet并在其上调用delete()每个对象),而不是使用QuerySet的批量delete()方法。

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

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

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

https://docs.djangoproject.com/zh-CN/2.1/ref/models/querysets/#update


这不都适用吗?
Flimm
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.