【问题标题】:Automatically update a field on one model after saving another [Django 1.11][Python3.x]保存另一个模型后自动更新一个模型上的字段[Django 1.11][Python3.x]
【发布时间】:2017-10-22 04:19:26
【问题描述】:

我正在学习如何在 Django 上使用 post_save 信号。虽然我没有收到任何错误,但我想做的事情不会奏效。

我有一个模型 (Model),它应该从 Review 模型中汇总和平均评分,并将该数字保存在名为“average_rating”的字段中。

我希望用户在“评论”模型上提供评分后进行平均,并在“模型”模型上自动计算和更新平均评分。

我知道我可以使用 post_save 信号来做到这一点。但我不确定如何。

我该如何做我想做的事?

提前致谢。

models.py

from django.db import models
from django.db.models import Func, Avg
from django.urls import reverse
from django.template.defaultfilters import slugify
from django.db.models.signals import post_save
from django.dispatch import receiver

class Model(models.Model):
    name = models.CharField(max_length=55, default='')
    slug = models.SlugField(unique=True)
    average_rating = models.DecimalField(decimal_places=1,
                                            max_digits=2,
                                            default=0.0,
                                            blank=True,
                                            null=True)

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        self.average_rating = self.review_set.aggregate(
                    rounded_avg_rating=Round(Avg('rating')))['rounded_avg_rating']
        self.slug = (slugify(self.name))
        super(Model, self).save(*args, **kwargs)


class Review(models.Model):
    RATING_CHOICES = [
        (1, '1'),
        (2, '2'),
        (3, '3'),
        (4, '4'),
        (5, '5'),
    ]
    model = models.ForeignKey(Model,
                                null=True)
    rating = models.IntegerField(choices=RATING_CHOICES,
                                    default=1)
    review_date = models.DateField(auto_now_add=True)
    reviewer = models.ForeignKey(User,
                                    null=True,
                                    related_name = 'review_user')
    comment = models.TextField(default='')

    class Meta:
        verbose_name_plural = 'Reviews'
        verbose_name = 'Review'

    def __str__(self):
        return self.model.name

@receiver(post_save, sender=Review)
def update_average_rating(sender, instance, **kwargs):
    instance.average_rating = Review.objects.aggregate(
                rounded_avg_rating=Round(Avg('rating')))['rounded_avg_rating']

更新:

使用 RajKris 提供的解决方案,我得到了这个:

class Review(models.Model):
    ....

    def save(self, *args, **kwargs):
        Model.save(avg_rating_flag=True)
        super(Review, self).save(*args, **kwargs)

现在我收到此错误:TypeError: save() missing 1 required positional argument: 'self'

RajKris 的更新答案解决了我的问题。像魅力一样工作。

def save(self, *args, **kwargs):   
    super(Review, self).save(*args, **kwargs)
    model_obj = self.model
    model_obj.average_rating = model_ob.review_set.aggregate(
                rounded_avg_rating=Round(Avg('rating')))['rounded_avg_rating']
    model_obj.save()

【问题讨论】:

    标签: python django python-3.x save signals


    【解决方案1】:

    在您的评论保存功能中:

    def save(self, *args, **kwargs):   
        super(Review, self).save(*args, **kwargs)
        model_obj = self.model
        model_obj.average_rating = model_obj.review_set.aggregate(
                    rounded_avg_rating=Round(Avg('rating')))['rounded_avg_rating']
        model_obj.save()
    

    这里发生的情况是,每次创建评论对象时,相应的模型对象都会更新为新的平均评分。

    【讨论】:

    • 感谢您的回复,RajKris。我想在模型上保存,但我一直不得不回到管理员那里并在模型更新average_rating字段之前将模型保存在那里。这就是为什么我在 Review 上使用 post_save 信号来更新模型的原因。我需要自动更新,否则我需要继续返回并保存。如果您能告诉我如何自动更新 Review 中的新评级,我将非常乐意在 Model.save 上执行此操作。
    • 所以你要做的就是保存 Review 模型。那有意义吗?当创建一个新的 Review 对象时,您会进行此聚合并将其保存到模型中。
    • 谢谢,RajKris。晚安。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-25
    • 2020-05-18
    • 2018-07-17
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 2021-11-19
    相关资源
    最近更新 更多