From 04a55844fde041f53ff3acbb1ea9c041101be1a6 Mon Sep 17 00:00:00 2001 From: Mark <162816078+markashton480@users.noreply.github.com> Date: Tue, 3 Mar 2026 12:39:47 +0000 Subject: [PATCH] Fix empty-category nav and route behavior Use category-state-driven queries for nav and category listing routes, and add regression tests for empty but valid categories. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- apps/blog/models.py | 13 +++---------- apps/blog/tests/test_views.py | 11 +++++++++++ apps/core/templatetags/core_tags.py | 6 ++---- apps/core/tests/test_tags.py | 11 +++++++++++ 4 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/blog/models.py b/apps/blog/models.py index 5f27733..13a7f0a 100644 --- a/apps/blog/models.py +++ b/apps/blog/models.py @@ -49,10 +49,7 @@ class HomePage(Page): id__in=ArticlePage.objects.live().public().values_list("tags__id", flat=True) ).distinct().order_by("name") ) - category_ids = ArticlePage.objects.live().public().values_list("category_id", flat=True) - ctx["available_categories"] = Category.objects.filter(show_in_nav=True, id__in=category_ids).order_by( - "sort_order", "name" - ) + ctx["available_categories"] = Category.objects.filter(show_in_nav=True).order_by("sort_order", "name") return ctx @@ -76,9 +73,7 @@ class ArticleIndexPage(RoutablePageMixin, Page): def get_listing_context(self, request, active_category=None): tag_slug = request.GET.get("tag") articles = self.get_articles() - all_articles = articles - category_ids = all_articles.values_list("category_id", flat=True) - available_categories = Category.objects.filter(id__in=category_ids).order_by("sort_order", "name") + available_categories = Category.objects.order_by("sort_order", "name") category_links = [ {"category": category, "url": self.get_category_url(category)} for category in available_categories @@ -111,9 +106,7 @@ class ArticleIndexPage(RoutablePageMixin, Page): @route(r"^category/(?P[-\w]+)/$") def category_listing(self, request, category_slug): - category_ids = self.get_articles().values_list("category_id", flat=True) - category_qs = Category.objects.filter(id__in=category_ids) - category = get_object_or_404(category_qs, slug=category_slug) + category = get_object_or_404(Category, slug=category_slug) return self.render(request, context_overrides=self.get_listing_context(request, active_category=category)) def get_context(self, request, *args, **kwargs): diff --git a/apps/blog/tests/test_views.py b/apps/blog/tests/test_views.py index 3b8f538..b3fe28d 100644 --- a/apps/blog/tests/test_views.py +++ b/apps/blog/tests/test_views.py @@ -233,3 +233,14 @@ def test_article_index_category_route_supports_tag_filter(client, home_page): assert resp.status_code == 200 assert "Keep Me" in html assert "Drop Me" not in html + + +@pytest.mark.django_db +def test_article_index_category_route_allows_empty_existing_category(client, home_page): + index = ArticleIndexPage(title="Articles", slug="articles") + home_page.add_child(instance=index) + Category.objects.create(name="Opinion", slug="opinion") + + resp = client.get("/articles/category/opinion/") + assert resp.status_code == 200 + assert "No articles found." in resp.content.decode() diff --git a/apps/core/templatetags/core_tags.py b/apps/core/templatetags/core_tags.py index 212f533..23a5f2c 100644 --- a/apps/core/templatetags/core_tags.py +++ b/apps/core/templatetags/core_tags.py @@ -4,7 +4,7 @@ from django import template from django.utils.safestring import mark_safe from wagtail.models import Site -from apps.blog.models import ArticleIndexPage, TagMetadata +from apps.blog.models import ArticleIndexPage, Category, TagMetadata from apps.core.models import SiteSettings from apps.legal.models import LegalPage @@ -58,9 +58,7 @@ def get_categories_nav(context): index_page = index_qs.first() if not index_page: return [] - categories = index_page.get_listing_context( - request, active_category=None - )["available_categories"].filter(show_in_nav=True) + categories = Category.objects.filter(show_in_nav=True).order_by("sort_order", "name") return [ { "name": category.name, diff --git a/apps/core/tests/test_tags.py b/apps/core/tests/test_tags.py index cdf758d..e80bc32 100644 --- a/apps/core/tests/test_tags.py +++ b/apps/core/tests/test_tags.py @@ -37,3 +37,14 @@ def test_categories_nav_tag_renders_category_link(client, home_page): resp = client.get("/") assert resp.status_code == 200 assert "/articles/category/reviews/" in resp.content.decode() + + +@pytest.mark.django_db +def test_categories_nav_tag_includes_empty_nav_category(client, home_page): + index = ArticleIndexPage(title="Articles", slug="articles") + home_page.add_child(instance=index) + Category.objects.create(name="Benchmarks", slug="benchmarks", show_in_nav=True) + + resp = client.get("/") + assert resp.status_code == 200 + assert "/articles/category/benchmarks/" in resp.content.decode()