我正在为我的学校构建一个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()方法中检索以前的分数?还有一个更好,更有效率的做我想做的事情?谢谢!
答案 0 :(得分:1)
要记住一些问题:如果用户删除了他们的帐户,评论等,该怎么办?以所示方式保持运行总计将是有问题的。
相反,我建议使用如下所示的结构;更新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
答案 1 :(得分:1)
使用post_save信号。
在教授的模型文件中:
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save,sender=Review)
def update_professor_by_review(*args,**kwargs):
updated_review = kwargs['instance']
reviewed_professor = updated_review.professor
# ... update the reviewed_professor as needed according to the review instance
reviewed_professor.save()
return