fix: select only active club members on GET /club/{club_id}

This commit is contained in:
imperosol 2025-06-17 15:31:28 +02:00
parent f1b69dd47d
commit 0c442a8f03
2 changed files with 37 additions and 11 deletions

View File

@ -1,6 +1,7 @@
from typing import Annotated from typing import Annotated
from annotated_types import MinLen from annotated_types import MinLen
from django.db.models import Prefetch
from ninja.security import SessionAuth from ninja.security import SessionAuth
from ninja_extra import ControllerBase, api_controller, paginate, route from ninja_extra import ControllerBase, api_controller, paginate, route
from ninja_extra.pagination import PageNumberPaginationExtra from ninja_extra.pagination import PageNumberPaginationExtra
@ -8,7 +9,7 @@ from ninja_extra.schemas import PaginatedResponseSchema
from api.auth import ApiKeyAuth from api.auth import ApiKeyAuth
from api.permissions import CanAccessLookup, HasPerm from api.permissions import CanAccessLookup, HasPerm
from club.models import Club from club.models import Club, Membership
from club.schemas import ClubSchema, SimpleClubSchema from club.schemas import ClubSchema, SimpleClubSchema
@ -33,6 +34,9 @@ class ClubController(ControllerBase):
url_name="fetch_club", url_name="fetch_club",
) )
def fetch_club(self, club_id: int): def fetch_club(self, club_id: int):
return self.get_object_or_exception( prefetch = Prefetch(
Club.objects.prefetch_related("members", "members__user"), id=club_id "members", queryset=Membership.objects.ongoing().select_related("user")
)
return self.get_object_or_exception(
Club.objects.prefetch_related(prefetch), id=club_id
) )

View File

@ -1,7 +1,10 @@
from datetime import date, timedelta
import pytest import pytest
from django.test import Client from django.test import Client
from django.urls import reverse from django.urls import reverse
from model_bakery import baker from model_bakery import baker
from model_bakery.recipe import Recipe
from pytest_django.asserts import assertNumQueries from pytest_django.asserts import assertNumQueries
from club.models import Club, Membership from club.models import Club, Membership
@ -9,13 +12,32 @@ from core.baker_recipes import subscriber_user
@pytest.mark.django_db @pytest.mark.django_db
def test_fetch_club(client: Client): class TestFetchClub:
club = baker.make(Club) @pytest.fixture()
baker.make(Membership, club=club, _quantity=10, _bulk_create=True) def club(self):
user = subscriber_user.make() club = baker.make(Club)
client.force_login(user) last_month = date.today() - timedelta(days=30)
with assertNumQueries(7): yesterday = date.today() - timedelta(days=1)
# - 4 queries for authentication membership_recipe = Recipe(Membership, club=club, start_date=last_month)
# - 3 queries for the actual data membership_recipe.make(end_date=None, _quantity=10, _bulk_create=True)
membership_recipe.make(end_date=yesterday, _quantity=10, _bulk_create=True)
return club
def test_fetch_club_members(self, client: Client, club: Club):
user = subscriber_user.make()
client.force_login(user)
res = client.get(reverse("api:fetch_club", kwargs={"club_id": club.id})) res = client.get(reverse("api:fetch_club", kwargs={"club_id": club.id}))
assert res.status_code == 200 assert res.status_code == 200
member_ids = {member["user"]["id"] for member in res.json()["members"]}
assert member_ids == set(
club.members.ongoing().values_list("user_id", flat=True)
)
def test_fetch_club_nb_queries(self, client: Client, club: Club):
user = subscriber_user.make()
client.force_login(user)
with assertNumQueries(6):
# - 4 queries for authentication
# - 2 queries for the actual data
res = client.get(reverse("api:fetch_club", kwargs={"club_id": club.id}))
assert res.status_code == 200