Add tests for org list view queryset fields

This commit is contained in:
Joakim Hellsén 2026-04-12 05:14:40 +02:00
commit 3c18b26e9c
Signed by: Joakim Hellsén
SSH key fingerprint: SHA256:/9h/CsExpFp+PRhsfA0xznFx2CGfTT5R/kpuFfUgEQk
3 changed files with 53 additions and 5 deletions

View file

@ -70,6 +70,11 @@ class Organization(auto_prefetch.Model):
"""Return a string representation of the organization.""" """Return a string representation of the organization."""
return self.name or self.twitch_id return self.name or self.twitch_id
@classmethod
def for_list_view(cls) -> models.QuerySet[Organization]:
"""Return organizations with only fields needed by the org list page."""
return cls.objects.only("twitch_id", "name").order_by("name")
def feed_description(self: Organization) -> str: def feed_description(self: Organization) -> str:
"""Return a description of the organization for RSS feeds.""" """Return a description of the organization for RSS feeds."""
name: str = self.name or "Unknown Organization" name: str = self.name or "Unknown Organization"

View file

@ -946,6 +946,16 @@ class TestChannelListView:
if connection.vendor == "sqlite": if connection.vendor == "sqlite":
campaigns_uses_index: bool = "USING INDEX" in campaigns_plan.upper() campaigns_uses_index: bool = "USING INDEX" in campaigns_plan.upper()
rewards_uses_index: bool = "USING INDEX" in reward_plan.upper() rewards_uses_index: bool = "USING INDEX" in reward_plan.upper()
campaigns_uses_expected_index: bool = (
"tw_drop_start_end_idx" in campaigns_plan
or "tw_drop_start_end_game_idx" in campaigns_plan
or "tw_drop_start_desc_idx" in campaigns_plan
)
rewards_uses_expected_index: bool = (
"tw_reward_starts_ends_idx" in reward_plan
or "tw_reward_ends_starts_idx" in reward_plan
or "tw_reward_starts_desc_idx" in reward_plan
)
elif connection.vendor == "postgresql": elif connection.vendor == "postgresql":
campaigns_uses_index = ( campaigns_uses_index = (
"INDEX SCAN" in campaigns_plan.upper() "INDEX SCAN" in campaigns_plan.upper()
@ -957,6 +967,16 @@ class TestChannelListView:
or "BITMAP INDEX SCAN" in reward_plan.upper() or "BITMAP INDEX SCAN" in reward_plan.upper()
or "INDEX ONLY SCAN" in reward_plan.upper() or "INDEX ONLY SCAN" in reward_plan.upper()
) )
campaigns_uses_expected_index = (
"tw_drop_start_end_idx" in campaigns_plan
or "tw_drop_start_end_game_idx" in campaigns_plan
or "tw_drop_start_desc_idx" in campaigns_plan
)
rewards_uses_expected_index = (
"tw_reward_starts_ends_idx" in reward_plan
or "tw_reward_ends_starts_idx" in reward_plan
or "tw_reward_starts_desc_idx" in reward_plan
)
else: else:
pytest.skip( pytest.skip(
f"Unsupported DB vendor for index-plan assertion: {connection.vendor}", f"Unsupported DB vendor for index-plan assertion: {connection.vendor}",
@ -964,6 +984,8 @@ class TestChannelListView:
assert campaigns_uses_index, campaigns_plan assert campaigns_uses_index, campaigns_plan
assert rewards_uses_index, reward_plan assert rewards_uses_index, reward_plan
assert campaigns_uses_expected_index, campaigns_plan
assert rewards_uses_expected_index, reward_plan
@pytest.mark.django_db @pytest.mark.django_db
def test_dashboard_context_uses_prefetched_data_without_n_plus_one(self) -> None: def test_dashboard_context_uses_prefetched_data_without_n_plus_one(self) -> None:
@ -2342,6 +2364,30 @@ class TestChannelListView:
assert response.status_code == 200 assert response.status_code == 200
assert "orgs" in response.context assert "orgs" in response.context
@pytest.mark.django_db
def test_org_list_queryset_only_selects_rendered_fields(self) -> None:
"""Organization list queryset should defer non-rendered fields."""
org: Organization = Organization.objects.create(
twitch_id="org_list_fields",
name="Org List Fields",
)
fetched_org: Organization | None = (
Organization
.for_list_view()
.filter(
twitch_id=org.twitch_id,
)
.first()
)
assert fetched_org is not None
deferred_fields: set[str] = fetched_org.get_deferred_fields()
assert "added_at" in deferred_fields
assert "updated_at" in deferred_fields
assert "twitch_id" not in deferred_fields
assert "name" not in deferred_fields
@pytest.mark.django_db @pytest.mark.django_db
def test_organization_detail_view(self, client: Client, db: None) -> None: def test_organization_detail_view(self, client: Client, db: None) -> None:
"""Test organization detail view returns 200 and has organization in context.""" """Test organization detail view returns 200 and has organization in context."""

View file

@ -284,7 +284,7 @@ def org_list_view(request: HttpRequest) -> HttpResponse:
Returns: Returns:
HttpResponse: The rendered organization list page. HttpResponse: The rendered organization list page.
""" """
orgs: QuerySet[Organization] = Organization.objects.all().order_by("name") orgs: QuerySet[Organization] = Organization.for_list_view()
# CollectionPage schema for organizations list # CollectionPage schema for organizations list
collection_schema: dict[str, str] = { collection_schema: dict[str, str] = {
@ -300,10 +300,7 @@ def org_list_view(request: HttpRequest) -> HttpResponse:
page_description="List of Twitch organizations.", page_description="List of Twitch organizations.",
seo_meta={"schema_data": collection_schema}, seo_meta={"schema_data": collection_schema},
) )
context: dict[str, Any] = { context: dict[str, Any] = {"orgs": orgs, **seo_context}
"orgs": orgs,
**seo_context,
}
return render(request, "twitch/org_list.html", context) return render(request, "twitch/org_list.html", context)