diff --git a/comicsdb/views/publisher.py b/comicsdb/views/publisher.py index 39d4d768..ec333888 100644 --- a/comicsdb/views/publisher.py +++ b/comicsdb/views/publisher.py @@ -54,6 +54,20 @@ .values("count") ) +_imprint_series_count_sq = ( + Series.objects.filter(imprint=OuterRef("pk")) + .values("imprint") + .annotate(count=Count("pk")) + .values("count") +) + +_universe_issue_count_sq = ( + Issue.objects.filter(universes=OuterRef("pk")) + .values("universes") + .annotate(count=Count("pk")) + .values("count") +) + class PublisherList(ListView): model = Publisher @@ -100,11 +114,15 @@ def get_context_data(self, **kwargs): # Paginate imprints - only load first batch if imprint_count > 0: - context["imprints"] = publisher.imprints.all()[:DETAIL_PAGINATE_BY] + context["imprints"] = publisher.imprints.annotate( + series_count=Subquery(_imprint_series_count_sq) + )[:DETAIL_PAGINATE_BY] # Paginate universes - only load first batch if universe_count > 0: - context["universes"] = publisher.universes.all()[:DETAIL_PAGINATE_BY] + context["universes"] = publisher.universes.annotate( + issue_count=Subquery(_universe_issue_count_sq) + )[:DETAIL_PAGINATE_BY] return context @@ -153,6 +171,11 @@ class PublisherImprintsLoadMore(LazyLoadMixin): context_object_name = "imprints" slug_context_name = "publisher_slug" + def get_queryset(self, parent_object, offset, limit): + return parent_object.imprints.annotate(series_count=Subquery(_imprint_series_count_sq))[ + offset : offset + limit + ] + class PublisherUniversesLoadMore(LazyLoadMixin): """HTMX endpoint for lazy loading more universes.""" @@ -162,3 +185,8 @@ class PublisherUniversesLoadMore(LazyLoadMixin): template_name = "comicsdb/partials/publisher_universe_items.html" context_object_name = "universes" slug_context_name = "publisher_slug" + + def get_queryset(self, parent_object, offset, limit): + return parent_object.universes.annotate(issue_count=Subquery(_universe_issue_count_sq))[ + offset : offset + limit + ] diff --git a/tests/comicsdb/test_publisher_views.py b/tests/comicsdb/test_publisher_views.py index 35c7e9da..bc0da389 100644 --- a/tests/comicsdb/test_publisher_views.py +++ b/tests/comicsdb/test_publisher_views.py @@ -5,6 +5,8 @@ from comicsdb.models import Publisher from comicsdb.models.attribution import Attribution +from comicsdb.models.issue import Issue +from comicsdb.models.series import Series HTML_OK_CODE = 200 HTML_REDIRECT_CODE = 302 @@ -32,6 +34,49 @@ def test_publisher_detail(dc_comics, auto_login_user): assert resp.status_code == HTML_OK_CODE +def test_publisher_detail_with_imprint_and_universe_counts( + dc_comics, + vertigo_imprint, + earth_2_universe, + single_issue_type, + create_user, + auto_login_user, +): + """Regression test: imprint/universe series & issue counts must render. + + Rendering these counts previously relied on unannotated querysets, which + made ``imprint.series_count``/``universe.issue_count`` resolve to an + empty string and crashed the ``{% blocktrans count %}`` tag. + """ + user = create_user() + series = Series.objects.create( + name="Sandman", + slug="sandman", + publisher=dc_comics, + imprint=vertigo_imprint, + series_type=single_issue_type, + year_began=1989, + volume=1, + edited_by=user, + created_by=user, + ) + issue = Issue.objects.create( + series=series, + number="1", + slug="sandman-1989-1", + cover_date="1989-01-01", + edited_by=user, + created_by=user, + ) + issue.universes.add(earth_2_universe) + + client, _ = auto_login_user() + resp = client.get(f"/publisher/{dc_comics.slug}/") + assert resp.status_code == HTML_OK_CODE + assert resp.context["imprints"][0].series_count == 1 + assert resp.context["universes"][0].issue_count == 1 + + def test_publisher_redirect(dc_comics, auto_login_user): client, _ = auto_login_user() resp = client.get(f"/publisher/{dc_comics.pk}/")