简体   繁体   中英

Average for ratings in Django

I working on an app using django and python at school. It an app for writing reviews and rating movies. I would like to implement a rating system, so I can display the average rating for a film based on the rating given in the reviews. At the moment this code gives the rating in descending order for all reviews, and not the average. Like if I got two reviews for a movie, with score 1 and 5, I get both, but not one that says 3. Please help!

In models.py:

class Film(models.Model):
    title = models.CharField(max_length=100)
    title_short = models.CharField(max_length=17, default=None, null=True)
    plot = models.TextField()
    poster = models.ImageField(default="default.png", upload_to="posters")
    release_date = models.DateField(blank=True, null=True)
    date_posted = models.DateTimeField(default=timezone.now)


class Review(models.Model):
    writer = models.ForeignKey(User, on_delete=models.CASCADE)
    reviewed_film = models.ForeignKey(Film, on_delete=models.CASCADE)

    title = models.CharField(max_length=100)
    content = models.TextField()
    rating = models.IntegerField(
        default=1, validators=[MinValueValidator(1), MaxValueValidator(5)]
    )

In views.py:

class ToplistListView(LoginRequiredMixin, ListView):
    model = Review
    template_name = "board/toplist.html"
    context_object_name = "films"

    def get_queryset(self):
        return Review.objects.annotate(avg_rating=Avg('rating')).order_by('-avg_rating')

You're getting the average rating on each review, which will of course just give you the rating for that review as each review only has a single rating. The average of a single number is just that number.

I think what you want is the average for all the ratings for a film. So you'd want a query that looks something like:

Flim.objects.annotate(avg_rating=Avg('review_set__rating')).order_by('-avg_rating')

Also, you can change the name of review_set (which is default for a Foreign Key lookup if no related name is set) to whatever you want by setting related_name='reviews' or whatever you want it to be called on the FK definition.

So:

reviewed_film = models.ForeignKey(Film, related_name='reviews', on_delete=models.CASCADE)

ETA: if you make that change, your query would become:

Flim.objects.annotate(avg_rating=Avg('reviews__rating')).order_by('-avg_rating')

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM