diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 368276523f..67bcf18356 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -9,7 +9,7 @@ from django.contrib.postgres.indexes import GinIndex from django.core.cache import cache from django.db import models, transaction -from django.db.models import Prefetch, ManyToManyField +from django.db.models import Avg, Prefetch, ManyToManyField, Q from django.dispatch import receiver from django.utils.translation import gettext_lazy as _ from model_utils import FieldTracker @@ -19,6 +19,7 @@ from bookwyrm import activitypub from bookwyrm.isbn.isbn import hyphenator_singleton as hyphenator +from bookwyrm.models.status import Review from bookwyrm.preview_images import generate_edition_preview_image_task from bookwyrm.settings import ( BASE_URL, @@ -491,6 +492,36 @@ def hyphenated_isbn13(self): """generate the hyphenated version of the ISBN-13""" return hyphenator.hyphenate(self.isbn_13) + @classmethod + def average_rating(cls, include_parents=False, user=None, privacy=None): + """ + Generate the average rating of a book + + Args: + include_parents: allows the caller to determine if ratings + from other Editions of the Work should be included + user: if we're given a value for user, use privacy_filter + privacy: if we're given a value for privacy, use it in filtering the reviews + Returns: + an aggregation of the average rating of the book across its reviews. + """ + # get the base review queryset which we will refine + # based on the arguments provided + if include_parents: + base_reviews = Review.objects.filter( + Q(book__parent_work__editions=cls) & Q(deleted=False) & Q(rating_gt=0) + ) + else: + base_reviews = Review.objects.filter(Q(deleted=False) & Q(rating_gt=0)) + if user: + reviews = base_reviews.privacy_filter(user).exclude(rating=None) + elif privacy: + reviews = base_reviews.filter(Q(privacy=privacy)).exclude(rating=None) + else: + reviews = base_reviews.exclude(rating=None) + + return reviews.aggregate(Avg("rating"))["rating__avg"] + def get_rank(self): """calculate how complete the data is on this edition""" rank = 0 diff --git a/bookwyrm/views/books/books.py b/bookwyrm/views/books/books.py index c67d18cf3d..0435d2feaf 100644 --- a/bookwyrm/views/books/books.py +++ b/bookwyrm/views/books/books.py @@ -4,7 +4,7 @@ from django.contrib.auth.decorators import login_required, permission_required from django.core.paginator import Paginator -from django.db.models import Avg, Q +from django.db.models import Q from django.http import Http404 from django.shortcuts import get_object_or_404, redirect from django.template.response import TemplateResponse @@ -98,7 +98,7 @@ def get(self, request, book_id, **kwargs): if not user_statuses else None ), - "rating": reviews.aggregate(Avg("rating"))["rating__avg"], + "rating": book.average_rating(include_parents=True, user=request.user), "lists": lists, "update_error": kwargs.get("update_error", False), }