diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py
index 8d1b70ae..ffc03d3e 100644
--- a/bookwyrm/models/book.py
+++ b/bookwyrm/models/book.py
@@ -342,6 +342,11 @@ class Edition(Book):
# set rank
self.edition_rank = self.get_rank()
+ # clear author cache
+ if self.id:
+ for author_id in self.authors.values_list("id", flat=True):
+ cache.delete(f"author-books-{author_id}")
+
return super().save(*args, **kwargs)
@classmethod
diff --git a/bookwyrm/models/shelf.py b/bookwyrm/models/shelf.py
index c578f082..320d495d 100644
--- a/bookwyrm/models/shelf.py
+++ b/bookwyrm/models/shelf.py
@@ -1,5 +1,6 @@
""" puttin' books on shelves """
import re
+from django.core.cache import cache
from django.core.exceptions import PermissionDenied
from django.db import models
from django.utils import timezone
@@ -94,8 +95,15 @@ class ShelfBook(CollectionItemMixin, BookWyrmModel):
def save(self, *args, **kwargs):
if not self.user:
self.user = self.shelf.user
+ if self.id and self.user.local:
+ cache.delete(f"book-on-shelf-{self.book.id}-{self.shelf.id}")
super().save(*args, **kwargs)
+ def delete(self, *args, **kwargs):
+ if self.id and self.user.local:
+ cache.delete(f"book-on-shelf-{self.book.id}-{self.shelf.id}")
+ super().delete(*args, **kwargs)
+
class Meta:
"""an opinionated constraint!
you can't put a book on shelf twice"""
diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py
index ee138d97..29b3ba9c 100644
--- a/bookwyrm/models/status.py
+++ b/bookwyrm/models/status.py
@@ -3,6 +3,7 @@ from dataclasses import MISSING
import re
from django.apps import apps
+from django.core.cache import cache
from django.core.exceptions import PermissionDenied
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
@@ -373,6 +374,12 @@ class Review(BookStatus):
activity_serializer = activitypub.Review
pure_type = "Article"
+ def save(self, *args, **kwargs):
+ """clear rating caches"""
+ if self.book.parent_work:
+ cache.delete(f"book-rating-{self.book.parent_work.id}-*")
+ super().save(*args, **kwargs)
+
class ReviewRating(Review):
"""a subtype of review that only contains a rating"""
diff --git a/bookwyrm/templates/snippets/shelve_button/shelve_button.html b/bookwyrm/templates/snippets/shelve_button/shelve_button.html
index 38f6be38..37c57fc2 100644
--- a/bookwyrm/templates/snippets/shelve_button/shelve_button.html
+++ b/bookwyrm/templates/snippets/shelve_button/shelve_button.html
@@ -6,8 +6,9 @@
{% with book.id|uuid as uuid %}
{% active_shelf book as active_shelf %}
{% latest_read_through book request.user as readthrough %}
+{% with active_shelf_book=active_shelf.book %}
- {% if switch_mode and active_shelf.book != book %}
+ {% if switch_mode and active_shelf_book != book %}
{% include 'snippets/switch_edition_button.html' with edition=book size='is-small' %}
@@ -20,16 +21,17 @@
{% join "want_to_read" uuid as modal_id %}
-{% include 'snippets/reading_modals/want_to_read_modal.html' with book=active_shelf.book id=modal_id class="" %}
+{% include 'snippets/reading_modals/want_to_read_modal.html' with book=active_shelf_book id=modal_id class="" %}
{% join "start_reading" uuid as modal_id %}
-{% include 'snippets/reading_modals/start_reading_modal.html' with book=active_shelf.book id=modal_id class="" %}
+{% include 'snippets/reading_modals/start_reading_modal.html' with book=active_shelf_book id=modal_id class="" %}
{% join "finish_reading" uuid as modal_id %}
-{% include 'snippets/reading_modals/finish_reading_modal.html' with book=active_shelf.book id=modal_id readthrough=readthrough class="" %}
+{% include 'snippets/reading_modals/finish_reading_modal.html' with book=active_shelf_book id=modal_id readthrough=readthrough class="" %}
{% join "progress_update" uuid as modal_id %}
-{% include 'snippets/reading_modals/progress_update_modal.html' with book=active_shelf.book id=modal_id readthrough=readthrough class="" %}
+{% include 'snippets/reading_modals/progress_update_modal.html' with book=active_shelf_book id=modal_id readthrough=readthrough class="" %}
+{% endwith %}
{% endwith %}
{% endif %}
diff --git a/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html b/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html
index 0b36ddbb..15e2bb51 100644
--- a/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html
+++ b/bookwyrm/templates/snippets/shelve_button/shelve_button_dropdown_options.html
@@ -38,7 +38,7 @@
diff --git a/bookwyrm/templates/snippets/shelve_button/shelve_button_options.html b/bookwyrm/templates/snippets/shelve_button/shelve_button_options.html
index add2a77c..d6ca9933 100644
--- a/bookwyrm/templates/snippets/shelve_button/shelve_button_options.html
+++ b/bookwyrm/templates/snippets/shelve_button/shelve_button_options.html
@@ -45,7 +45,13 @@
diff --git a/bookwyrm/templatetags/bookwyrm_tags.py b/bookwyrm/templatetags/bookwyrm_tags.py
index a3e89d9e..4eff0d82 100644
--- a/bookwyrm/templatetags/bookwyrm_tags.py
+++ b/bookwyrm/templatetags/bookwyrm_tags.py
@@ -13,10 +13,16 @@ register = template.Library()
@register.filter(name="rating")
def get_rating(book, user):
"""get the overall rating of a book"""
- queryset = models.Review.privacy_filter(user).filter(
- book__parent_work__editions=book
+ return cache.get_or_set(
+ f"book-rating-{book.parent_work.id}-{user.id}",
+ lambda u, b: models.Review.privacy_filter(u)
+ .filter(book__parent_work__editions=b)
+ .aggregate(Avg("rating"))["rating__avg"]
+ or 0,
+ user,
+ book,
+ timeout=15552000,
)
- return queryset.aggregate(Avg("rating"))["rating__avg"]
@register.filter(name="user_rating")
@@ -37,6 +43,18 @@ def get_user_rating(book, user):
return 0
+@register.filter(name="is_book_on_shelf")
+def get_is_book_on_shelf(book, shelf):
+ """is a book on a shelf"""
+ return cache.get_or_set(
+ f"book-on-shelf-{book.id}-{shelf.id}",
+ lambda b, s: s.books.filter(id=b.id).exists(),
+ book,
+ shelf,
+ timeout=15552000,
+ )
+
+
@register.filter(name="book_description")
def get_book_description(book):
"""use the work's text if the book doesn't have it"""
@@ -140,6 +158,7 @@ def active_shelf(context, book):
shelf__user=u,
book__parent_work__editions=b,
).first()
+ or False
),
user,
book,
@@ -158,6 +177,7 @@ def latest_read_through(book, user):
models.ReadThrough.objects.filter(user=u, book=b, is_active=True)
.order_by("-start_date")
.first()
+ or False
),
user,
book,
diff --git a/bookwyrm/views/author.py b/bookwyrm/views/author.py
index 2acb3b19..9bc95b79 100644
--- a/bookwyrm/views/author.py
+++ b/bookwyrm/views/author.py
@@ -12,6 +12,7 @@ from bookwyrm import forms, models
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.connectors import connector_manager
from bookwyrm.settings import PAGE_LENGTH
+from bookwyrm.utils import cache
from bookwyrm.views.helpers import is_api_request
@@ -30,14 +31,24 @@ class Author(View):
parent_work=OuterRef("parent_work")
).order_by("-edition_rank")
- books = (
- models.Edition.viewer_aware_objects(request.user)
- .filter(Q(authors=author) | Q(parent_work__authors=author))
+ book_ids = cache.get_or_set(
+ f"author-books-{author.id}",
+ lambda a: models.Edition.objects.filter(
+ Q(authors=a) | Q(parent_work__authors=a)
+ )
.annotate(default_id=Subquery(default_editions.values("id")[:1]))
.filter(default_id=F("id"))
- .order_by("-first_published_date", "-published_date", "-created_date")
+ .distinct()
+ .values_list("id", flat=True),
+ author,
+ timeout=15552000,
+ )
+
+ books = (
+ models.Edition.objects.filter(id__in=book_ids)
+ .order_by("-published_date", "-first_published_date", "-created_date")
.prefetch_related("authors")
- ).distinct()
+ )
paginated = Paginator(books, PAGE_LENGTH)
page = paginated.get_page(request.GET.get("page"))
diff --git a/bookwyrm/views/reading.py b/bookwyrm/views/reading.py
index d90c0e9d..2cd05202 100644
--- a/bookwyrm/views/reading.py
+++ b/bookwyrm/views/reading.py
@@ -46,9 +46,7 @@ class ReadingStatus(View):
return HttpResponseBadRequest()
# invalidate related caches
- cache.delete(
- f"active_shelf-{request.user.id}-{book_id}",
- )
+ cache.delete(f"active_shelf-{request.user.id}-{book_id}")
desired_shelf = get_object_or_404(
models.Shelf, identifier=identifier, user=request.user