Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make average rating property of Edition model #3425

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

lenikadali
Copy link

Description

Makes the query that returns the average rating of a book a @property function of the Edition model and changes the view code to use this instead.

What type of Pull Request is this?

  • Bug Fix
  • Enhancement
  • Plumbing / Internals / Dependencies
  • Refactor

Does this PR change settings or dependencies, or break something?

  • This PR changes or adds default settings, configuration, or .env values
  • This PR changes or adds dependencies
  • This PR introduces other breaking changes

Details of breaking or configuration changes (if any of above checked)

Documentation

  • New or amended documentation will be required if this PR is merged
  • I have created a matching pull request in the Documentation repository
  • I intend to create a matching pull request in the Documentation repository after this PR is merged

Tests

  • My changes do not need new tests
  • All tests I have added are passing
  • I have written tests but need help to make them pass
  • I have not written tests and need help to write them

Makes the query that returns the average rating of a book
a @Property function of the Edition model and changes the view
code to use this instead.
Added a return statement and doc string after running
./bw-dev formatters
Comment on lines 495 to 499
@property
def average_rating(self, user):
"""generate average rating of a book"""
reviews = Review.privacy_filter(user).filter(book__parent_work__editions=self)
return reviews.aggregate(Avg("rating"))["rating__avg"]
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@property functions cannot take arguments as mentioned here

However the original implementation is on run a reviews value that has the class method privacy_filter run on it before the rating calculation is done as shown here

Should we remove the privacy_filter call or switch to making this a function on the Edition model or a classmethod?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, other calculations of the rating use the user argument, strengthening the idea that this should be either a method on the model or a class method. Examples are here, and here. The latter also looks for ratings greater than 0.

The calculation here doesn't use the user argument.

Another idea could be to have different methods that keep the behaviour of the methods mentioned but have them be on the Edition model rather than in the different places they are in right now.

Copy link
Member

@mouse-reeve mouse-reeve Aug 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I completely overlooked the fact that this function modifies a Review queryset for a reason! So you're right that it doesn't make sense for it to be a property of an Edition; I think using a method that takes a review queryset (which can already be filtered with things like privacy_filter or privacy="public") and returns an average rating would be a good solution. The different ways this is queried really is a testament to how much this refactor is needed...

The method ought to filter out reviews where the status is deleted, or the rating is zero or None. It's probably fine to leave whether or not ratings from other Editions of the same Work (book__parent_work__editions=b for example) are included in the aggregate up to the lines of code that call it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a classmethod seems like a solid choice to me

Made average_rating a classmethod since it allows us
to pass arguments to it as needed

Added doc string explaining the different arguments
that average_rating takes.

For now the method covers the use case of the Book view.
Will probably need more work to cover other use cases
reviews = base_reviews.filter(Q(privacy=privacy)).exclude(rating=None)
else:
reviews = base_reviews.exclude(rating=None)

return reviews.aggregate(Avg("rating"))["rating__avg"]

Copy link
Author

@lenikadali lenikadali Sep 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think using a method that takes a Review queryset (which can already be filtered with things like privacy_filter or privacy="public") and returns an average rating would be a good solution.

The filter calls here have overlap with the initial filter in the Book view here

At this stage of the refactor, I am okay with leaving the Book view filter as is and then allowing a more elegant solution to come out of our iterations on this.

Also, other calculations of the rating use the user argument, strengthening the idea that this should be either a method on the model or a class method. Examples are here, and here. The latter also looks for ratings greater than 0.

The calculation here doesn't use the user argument.

Another idea could be to have different methods that keep the behaviour of the methods mentioned but have them be on the Edition model rather than in the different places they are in right now.

I also noticed that there are some subtleties in how we use the user arguments. In some queries, we want to apply privacy_filter while in others, we want to filter for the user's reviews of the Work. Not sure how to modify average_rating for the difference in queries.

@mouse-reeve what do you think?

@lenikadali lenikadali changed the title Draft: Make average rating property of Edition model Make average rating property of Edition model Oct 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make average rating a property of the Edition model
2 participants