Django, with it’s experienced developer community and regular updates have become a reliable framework to build stable and maintainable websites. Not to forget the easy-to-understand the documentation it provides, makes it easier for the beginners to get their way started in Django
Django,凭借其经验丰富的开发人员社区和定期更新,已成为构建稳定且可维护的网站的可靠框架。 别忘了它提供的易于理解的文档 ,使初学者更容易在Django中入门
Without wasting much time on what Django is, let’s jump right into one of it’s most crucial topics- Signals
在不花太多时间讨论Django是什么的情况下,让我们直接进入它最重要的主题之一- 信号
什么是信号 (What are Signals)
Signals, as the name suggests, allow applications to get notified when a certain event occurs. Suppose you want to notify the author of an article whenever someone comments or reacts on the article, but there are several places in your codebase to comment on an article or react on the article. How do you do it? You guessed it right, using signals. Signal hooks some piece of code to be executed as soon as a specific model’s save method is triggered.
顾名思义,信号允许应用程序在发生特定事件时得到通知 。 假设您想在有人发表评论或对文章做出React时通知文章作者,但是您的代码库中有很多地方可以评论文章或对文章做出React。 你怎么做呢? 您使用信号猜对了。 特定模型的保存方法一被触发,Signal就会钩住要执行的某些代码。
To have a clearer idea of the above example, let’s define the models.
为了更清楚地了解上面的示例,让我们定义模型。
何时使用信号 (When to use Signals)
Signals are best used when multiple pieces of code are interested in the same model instance events. To understand model instance events in simpler terms, it means a row creation, updating or deletion events.
当多个代码段对同一模型实例事件感兴趣时,最好使用信号。 为了用更简单的术语理解模型实例事件,这意味着创建行,更新或删除事件。
如何使用信号 (How to use Signals)
While there are many ways to use signals, my favourite way is to use the ‘@receiver’ decorator.
尽管有很多使用信号的方法,但我最喜欢的方法是使用'@receiver'装饰器。
Here is an example
这是一个例子

This might seem a bit confusing right now if you are a beginner, but let me help you out here.
如果您是初学者,现在可能看起来有些混乱,但是让我在这里为您提供帮助。
The receiver decorator her tells the code that the function(‘notify_user’ here) is about to receive a signal(post_save signal in this case). Now there are many types of Django signals, post_save(django.db.models.signals.post_save) is one of it. Let’s go through some of the important signals separately.
接收方装饰器她告诉代码该函数(此处为'notify_user')即将接收信号(在这种情况下为post_save信号)。 现在有许多类型的Django信号, post_save ( django.db.models.signals.post_save )是其中之一。 让我们分别浏览一些重要信号。
1.使用post_save的技巧 (1. Tips to use post_save)
As the name suggests, it is called just after the Django model save() function has done its job. The sender parameter here defines the Model from which we are trying to receive the signal. So now if I am to convert the above python code in English, I would say:
顾名思义,它是在Django模型save()函数完成其工作之后调用的。 这里的sender参数定义了我们试图从中接收信号的模型。 因此,现在如果我要将上述python代码转换为英语,我会说:
Call the function ‘notifiy_author’ after the istance of ‘ArticleComments’ is saved
保存“ ArticleComments”的位置后 ,调用函数“ notifiy_author”
Whenever we use signals, we get to use some variables. One of those variables, as you can see in the above code snippet is ‘instance’. This is nothing but the instance of the model ArticleComments which is being saved. So if I want to fetch the author of the comment, I can easily use:
每当我们使用信号时,我们都会使用一些变量。 如您在上面的代码片段中所见,这些变量之一是'instance' 。 这不过是正在保存的ArticleComments模型的实例。 因此,如果我想获取评论的作者,则可以轻松使用:
instance.article.author

Now a perk about using post_save signal is that it provides us with a variable named created. This is a flag, which returns True if this post_save signal is called when a new instance(or row) of a model was created.
现在,有关使用post_save信号的好处是,它为我们提供了一个名为created的变量。 这是一个标志,如果在创建模型的新实例(或行)时调用此post_save信号,则返回True。
Following points should be kept in mind while using post_save:1. There are no special signals like pre_create or post_create. Whenever we call Model function create(), it calls the save signals.2. You cannot modify the value of the any instance’s fields(for ex: ‘instance.comment’ here) inside post_save, without calling Django save() method again, which is not(never) a good practice to call inside a signal of the same model(Can you guess why?)
使用post_save时应牢记以下几点:1。 没有像pre_create或post_create这样的特殊信号。 每当我们调用模型函数create()时,它都会调用保存信号。2。 您不能在post_save内修改任何实例字段的值(例如,此处为“ instance.comment”),而无需再次调用Django save()方法,这不是(永远) 在同一信号内调用的好习惯模型 (您能猜出为什么吗?)
2.像专业人士一样使用pre_save (2. Use pre_save like a pro)
Pre_save (django.db.models.signals.pre_save) is provoked just before the model save() method is called, or you could say model save method is called only after pre_save is called and done its job free of errors.
Pre_save( django.db.models.signals.pre_save )是在调用模型save()方法之前引发的,或者可以说只有在调用pre_save并完成其工作而没有错误之后,才调用模型保存方法。
We know how to notify the author when a new comment is posted(the same way you can create a signal on the creation of ArticleReaction too), but what if I want to notify the author when the reaction is modified? pre_save comes in handy for similar cases.
我们知道如何在发布新评论时通知作者(也可以在创建ArticleReaction时创建信号的方式),但是如果我想在修改React后通知作者怎么办? pre_save在类似情况下非常有用。

We do not get ‘created’ variable to use in pre_save. No worries, we have a workaround for that too.
我们没有在pre_save中使用“创建”变量。 不用担心,我们也有解决方法。
All the model instances(or rows) have an auto-generated primary key which is name ‘id’. This id is numerically incremented as instances of the model are created. But the ‘id’ can only be generated/assigned after the creation of the row. Hence in pre_save, if we try to access the instance.id before the instance(or row) is created, it will return us None. So the condition on line 10 in the above snippet is nothing but a replica of ‘created’ from post_save.
所有模型实例(或行)都有一个自动生成的主键,名称为'id'。 创建模型实例时,此id会按数字递增。 但是“ id”只能在创建行后生成/分配。 因此,在pre_save中,如果我们尝试在创建实例(或行)之前访问instance.id,它将返回None。 因此,以上代码段中第10行的条件仅是post_save中“ created”的副本。

(Notice how I am using ‘row’ to refer an instance of a model. It will help you to have a clearer imagination of what’s happenning behind the scenes. Similarly, attributes/firelds can be referred with another term ‘column’)
(请注意,我是如何使用“行”来引用模型实例的。这将帮助您更清楚地了解幕后发生的事情。类似地,属性/对象也可以用另一个术语“列”来引用)
Our problem statement was to notify the author if the reaction is changed. Let’s try to backtrace it. To find if the reaction was changed, we need the current reaction and the previous reaction. If the current reaction and the previous reaction does not match, then it concludes that the reaction was changed and hence we need to notify the author about it. But how exactly can we get the previous and the current reactions? To understand that, we have to know one VERY IMPORTANT property about the variable instance in post_save and pre_save:
我们的问题陈述是,如果React发生更改,则通知作者。 让我们尝试回溯它。 为了确定React是否发生变化,我们需要当前React和先前React。 如果当前React和先前React不匹配,则得出结论,React已更改,因此我们需要将其通知作者。 但是,我们究竟如何才能获得先前和当前的React呢? 要了解这一点,我们必须了解有关post_save和pre_save中的变量实例的一个非常重要的属性:
The post_save’s instance has the attributes with values which are already saved in your model, but the pre_save’s instance has the attributes with values which are yet to be saved in your model.
post_save实例的属性值已保存在模型中,而pre_save实例的属性值已保存在模型中。
To make the above line more clearly, let’s take an example. Some user named ‘Ravi’ has already reacted with a ‘Like’. Ravi has a habit of reading everything twice. After reading the article again, he decided to change his reaction to ‘Love’.
为了使以上内容更加清晰,我们来看一个例子。 一些名为“ Ravi”的用户已经做出了“赞”的React。 拉维有阅读两次所有内容的习惯。 再次阅读文章后,他决定将自己的React更改为“爱”。

Let’s dive back inside our code again. Pre_save is called as soon as Ravi changed the reaction. Since the instance(or row) was already created, we move directly to the else condition in Line 14. Using the above-highlighted property, we can say that the variable ‘instance’ will have the new value ‘Love’ for its attribute ‘reaction’. Let’s name this modified variable ‘instance’ as ‘created’ (Line 15). Now we just need to get the old reaction. Remember that the ‘Love’ reaction has not been saved in our model yet(since we are still in pre_save). So what will we get if we try to get a model instance of ArticleReaction with the id provided by pre_save? We will get the instance with the reaction ‘Like’. Now let’s name this as ‘previous’(line 16). As we now have both old and new instances, we can easily compare these reactions and code are conditions accordingly.
让我们再次跳回代码内部。 Ravi更改React后,将立即调用Pre_save。 由于已经创建了实例(或行),因此我们直接移至第14行中的else条件。使用上面突出显示的属性,我们可以说变量“ instance”为其属性“”具有新的值“ Love”React'。 让我们将此修改后的变量“实例”命名为“创建”(第15行)。 现在我们只需要得到旧的React。 请记住,“爱”React尚未保存在我们的模型中(因为我们仍处于pre_save状态)。 那么,如果我们尝试使用pre_save提供的ID来获取ArticleReaction的模型实例,将会得到什么呢? 我们将获得带有“ Like”React的实例。 现在,将其命名为“ previous”(第16行)。 由于现在有了新旧实例,我们可以轻松地比较这些React,并且代码相应地是条件。

Since pre_save is called right before the model save() method, you can also modify the instance’s fields as per the requirement. For example, if we are using pre_save for ArticleComments and we want to check and remove any abuse words from comments before it is saved in our model, we can do it like this:
由于pre_save在模型save()方法之前被调用,因此您还可以根据需求修改实例的字段 。 例如,如果我们在文章评论中使用pre_save,并且想要在注释中删除任何滥用词,然后再将其保存在模型中,则可以这样进行:
if is_abuse(instance.comment):
instance.comment = remove_abusive(instance.comment)
Assuming that is_abusive and remove_abusive is your custom method. Also notice that we are not calling instance.save() after changing the instance.comment. Can you tell why?
假设is_abusive和remove_abusive是您的自定义方法。 还要注意,在更改instance.comment之后,我们没有调用instance.save()。 你能说出为什么吗?
3.其他信号 (3. Other Signals)
There many more signals you can use, which you can find here, but this blog was just an attempt to give you the idea of how you can use signals effectively.
您可以在这里找到更多可以使用的信号,但是此博客只是尝试向您提供如何有效使用信号的想法。
在我们完成之前 (Before we finish)
Even though signals come in handy when you want to perform actions behind the scenes, you have to be very careful about how you use it.
即使您想在幕后执行操作时,即使信号会派上用场,您也必须非常谨慎地使用它。
Do not compromise speed: putting too much load on pre_save or post_save signals might make the model save() method slow.
不要牺牲速度 :在pre_save或post_save信号上增加过多的负载可能会使模型save()方法变慢。
Lost in the loop: Calling the save() method for the sender model inside the post_save or pre_save will keep calling the signals repetitively.
迷失在循环中:在post_save或pre_save内部调用sender模型的save()方法将继续重复调用信号。
Remember the use cases: We use post_save when we are interested more in the creation of a model instance without modifying the values, while we use pre_save when we are more into the monitoring the change in model instance’s value, or if we are into modifying the instance’s attribute’s values ourselves.
记住用例:当我们对模型实例的创建更感兴趣而不修改值时,我们使用post_save;而当我们更想监视模型实例的值的变化时,或者如果我们要修改模型时,则使用pre_save。实例属性的值本身。
update() and save signals don’t get along: Django model ‘update()’ method does not invoke any kind of pre_save or post_save signals.
update()和save信号不兼容:Django模型的update()方法不会调用任何pre_save或post_save信号。
翻译自: https://medium.com/@singhgautam7/django-signals-master-pre-save-and-post-save-422889b2839