Skip to main content
 首页 » 编程设计

python之如何覆盖我的 Django 模型的 save() 方法以使其正确更新

2024年10月24日36mengfanrong

我正在为我的学校构建一个 ratemyprofessors 类型的应用程序,并进行一些练习。

目前我的 models.py 看起来像这样:

from __future__ import unicode_literals 
 
from django.db import models 
from django.core.validators import MaxValueValidator, MinValueValidator 
from django.contrib.auth.models import User 
from django.utils import timezone 
 
UNIVERSITIES = ( 
    ..... 
) 
 
DEPARTMENTS = ( 
    ..... 
) 
 
class Professor(models.Model): 
    name = models.CharField(max_length=255) 
    name_code = models.CharField(max_length=3, blank=True) 
    university = models.CharField(max_length=3, choices=UNIVERSITIES) 
    department = models.CharField(max_length=50, choices=DEPARTMENTS) 
    total_rating_points = models.IntegerField(default = 0) 
    number_of_reviews = models.IntegerField(default = 0) 
    rating = models.FloatField( 
        validators = [MinValueValidator(0.0), MaxValueValidator(5.0)], 
        default = 0.0 
    ) 
 
    def __str__(self): 
        return self.name 
 
SCORE_CHOICES = ( 
    ..... 
) 
 
class Review(models.Model): 
    author = models.ForeignKey(User, related_name='user_reviews') 
    professor = models.ForeignKey(Professor, related_name='professor_reviews') 
    created = models.DateTimeField(default=timezone.now) 
    updated = models.DateTimeField(default = timezone.now) 
    rating = models.IntegerField(default=1, choices=SCORE_CHOICES) 
    text = models.TextField(blank=True) 
 
    class Meta: 
        unique_together = [('author', 'professor')] 
 
    def __str__(self): 
        return 'Professor: ' +self.professor.name +', Score: ' +str(self.rating) 
 
    def save(self, *args, **kwargs): 
        """ 
        Re-writing the save method to update the associated professor's 
        rating as soon as a new Review object is created. 
        Also accounts for review updates by the user. 
        """ 
        if self.pk is None: 
            # This means that this is a new object 
            if self.professor: 
                p = self.professor 
                # Adjusting the total_rating_points and number of reviews 
                p.total_rating_points += self.rating 
                p.number_of_reviews += 1 
                # Adjusting the rating 
                p.rating = float(p.total_rating_points) / float(p.number_of_reviews) 
                p.save() 
        else: 
            # This object already exists, so this is an update 
            self.updated = timezone.now() 
            **WHAT DO I DO NOW?** 
 
 
        super(Review, self).save(*args, **kwargs) 

你看,如果用户更新了他/她的评分,教授的评分也必须相应调整。因为这是应用程序的核心,所以我想在 save() 方法中完成。如果它是一个非常新的评论,它会很好地工作。但是,如何更新分数?

我的意思是我知道我必须做什么:

  • 从教授的 total_rating_point 中减去之前的分数。

  • 将新评分添加到 total_rating_point

  • 用评分除以 number_of_review 来计算评分。

但是,在更新过程中,我该如何准确地在 save() 方法中检索之前的分数?还有更好、更有效的方法来做我想做的事情吗?谢谢!

请您参考如下方法:

有几个问题需要牢记:如果用户删除了他们的帐户、评论等怎么办?以所示方式保持运行总数将是有问题的。

相反,我建议使用如下所示的结构;当 Review 更新时,保存它,然后调用 Professor 的保存方法。 Professor 运行的新保存方法会计算现有评论的总和和计数,每次重新计算,因为它仍然只是为几个查询访问数据库。

from django.db.models import Sum 
 
class Professor(models.Model): 
    ... 
    def save(self,*args,**kwargs): 
        if self.pk: # prevent hitting the database unless professor already exists 
            professor_reviews = Review.objects.filter(professor=self) 
            # Adjusting the total_rating_points and number of reviews 
            self.total_rating_points = professor_reviews.aggregate(Sum('rating')) 
            self.number_of_reviews = professor_reviews.count() 
            # Adjusting the rating 
            self.rating = float(self.total_rating_points) / float(self.number_of_reviews) 
        super(Professor,self).save(*args,**kwargs) 
 
class Review(models.Model): 
    ....          
    def save(self, *args, **kwargs): 
        if self.pk: #already exists 
            self.updated = timezone.now() 
        super(Review, self).save(*args, **kwargs)  
        self.professor.save() # call after super writes the Review to the DB