2017-10-22 160 views
0

我正在学习如何在Django上使用post_save信号。虽然我没有得到任何错误,但我想要做的事情却行不通。保存另一个模型后自动更新一个模型上的字段[Django 1.11] [Python3.x]

我有一个模型(模型),应该汇总和平均来自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) 

现在我收到此错误:类型错误:保存()缺少1个必需的位置参数:'self'

RajKris的更新答案修复了我的问题EM。奇迹般有效。

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

回答

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

这里会发生什么事是,回顾对象被创建相应的模型对象每次使用新版平均评分更新。

+0

感谢您的回应,RajKris。我想在Model中保存,但是我必须回到管理员那里并保存模型,然后才能更新average_rating字段。这就是为什么我在Review上使用post_save信号来更新Model。我需要自动更新,否则我需要继续保存。如果你能告诉我怎么会自动更新来自Review的新评级,我将非常乐意在Model.save上做到这一点。 – user2901792

+0

所以你必须做的是做这个保存Review模型。那有意义吗?当创建一个新的Review对象时,您可以进行聚合并将其保存到模型中。 – rajkris

+0

我编辑了我的答案。请检查。 – rajkris

相关问题