提问人:Grimidk 提问时间:11/15/2023 最后编辑:Grimidk 更新时间:11/15/2023 访问量:43
如何避免重新触发 django 信号?
How can I avoid re-triggering a django signal?
问:
我有这个信号,我希望它一旦已经检查了每个实例一次就不要运行,目前它陷入了无限递归循环,因为它每次运行时都会触发自己。
from django.db.models.signals import (
post_save,
)
from django.dispatch import receiver
from app.models import (
QuestionForm,
Question,
)
@receiver(post_save, sender=form)
def get_max_score(
sender: form,
instance: form,
**kwargs: dict,
) -> None:
forms = form.objects.all()
for form in forms.iterator():
total = 0
questions = form.questions.all()
for item in questions.iterator():
total += item.points
form.set_score(total)
form.save()
任何帮助都是值得赞赏的,如果答案不如 n^2 复杂,则加分。
编辑:这是表单模型本身:
class QuestionForm(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=100)
questions = models.ManyToManyField(
Question,
related_name='questions'
)
created_at = models.DateTimeField(
auto_now_add=True,
editable=False,
)
updated_at = models.DateTimeField(
auto_now=True,
editable=False,
)
max_score = models.IntegerField(
default=0,
)
def __str__(self):
return self.name
def get_score(self):
return self.max_score
def set_score(self, score):
self.max_score = score
答:
1赞
willeM_ Van Onsem
11/15/2023
#1
我强烈建议不要将乐谱存储在对象中。事实上,这不仅可以避免信号的问题:我们可以在数据库端更有效地做到这一点,并且只有在我们需要分数时才能做到这一点,并且还可以使其更加健壮。form
信号通常是一个坏主意。事实上,信号可以被规避,例如使用.bulk_create(...
[Django-文档]这不会触发已创建对象的信号。在很多情况下,数据可能会发生变化:创建记录、更新记录、删除记录。事实证明,即使在同一个数据库上,保持相同的数据同步也并不容易。我在这篇文章中总结了一些信号问题 [django-antipatterns]。
因此,最好省略:score
class QuestionForm(models.Model):
questions = models.ManyToManyField(
Question,
related_name='questions'
)
# …
# no score field
pass
class Question(models.Model):
points = models.IntegerField()
现在,如果我们希望 s 具有相关 s 的相应分数,我们可以使用:Form
Question
from django.db.models import Sum
QuestionForm.objects.annotate(score=Sum('questions__points'))
由此产生的 s 将具有一个额外的属性,该属性将包含相关 s 的总和。如果查询集被过滤掉,它也不会聚合我们不需要的查询集,而且由于聚合是由数据库完成的,这通常非常有效。Form
QuerySet
.score
.points
Question
注意:
related_name=...
参数 [Django-doc] 是反向关系的名称,因此在本例中从模型到模型。因此,将其命名为 与正向关系相同。因此,您可能需要考虑将重命名为 。问题
Question
QuestionForm
forms
评论
0赞
Grimidk
11/15/2023
这听起来不错,但我将如何引用分数属性?“Form.score”不起作用。
0赞
willeM_ Van Onsem
11/15/2023
@Grimidk:如果使用带注释的查询集:.for form in queryset: print(form.score)
1赞
Grimidk
11/15/2023
在定义查询集并过滤以仅匹配我当前正在检查的查询集后,就像您所说的那样,这就成功了。
评论
score
form