102

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

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

一个评论有几个“分数”,overall_score 是分数的平均值。保存评论或分数时,我需要重新计算总分平均值。现在我正在使用覆盖的保存方法。使用 Django 的信号调度器有什么好处吗?

4

5 回答 5

92

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

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

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

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

于 2008-10-05T08:38:39.653 回答
24

您询问:

使用 Django 的信号调度器有什么好处吗?

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

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

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

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

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

于 2016-03-09T10:10:16.497 回答
3

如果您将使用信号,您将能够在每次保存相关分数模型时更新评论分数。但是,如果不需要这样的功能,我看不出有任何理由将其放入信号中,那是与模型相关的东西。

于 2008-10-04T13:55:25.427 回答
2

这是一种非规范化。看看这个漂亮的解决方案。就地组合字段定义。

于 2008-10-04T15:21:21.230 回答
2

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

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

于 2018-09-11T09:19:21.340 回答