Fix empty-category nav and route behavior
Some checks failed
CI / nightly-e2e (pull_request) Has been skipped
CI / deploy (pull_request) Has been skipped
CI / ci (pull_request) Successful in 1m17s
CI / pr-e2e (pull_request) Failing after 44s

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>
This commit is contained in:
Mark
2026-03-03 12:39:47 +00:00
parent f7ca4bc44b
commit 04a55844fd
4 changed files with 27 additions and 14 deletions

View File

@@ -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<category_slug>[-\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):

View File

@@ -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()

View File

@@ -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,

View File

@@ -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()