Skip to content

Commit bdbaa7b

Browse files
committed
fix: 발표를 타입명으로 필터링할 수 있도록 수정
1 parent dc0c561 commit bdbaa7b

File tree

2 files changed

+58
-24
lines changed

2 files changed

+58
-24
lines changed
Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import http
2-
import uuid
2+
import urllib.parse
33

44
import pytest
55
from django.urls import reverse
6+
from event.models import Event
7+
from event.presentation.models import Presentation, PresentationType
68
from event.presentation.test.conftest import PresentationTestEntity
79
from rest_framework.test import APIClient
10+
from user.models.organization import Organization
811

912

1013
@pytest.mark.django_db
@@ -16,20 +19,48 @@ def test_presentation_api(api_client: APIClient, create_presentation_set: Presen
1619

1720

1821
@pytest.mark.django_db
19-
def test_presentation_category_filter_api(api_client: APIClient, create_presentation_set: PresentationTestEntity):
20-
url = f"{reverse('v1:presentation-list')}?categories={create_presentation_set.presentation_category.id}"
21-
response = api_client.get(url)
22+
def test_presentation_event_type_filter_api(api_client: APIClient):
23+
# Given: 행사 2개에 각각 2 종류의 발표 유형이 있고, 각 발표 유형마다 1개의 발표가 있음.
24+
organization = Organization.objects.create(name="Test Organization")
25+
event_1: Event = Event.objects.create(organization=organization, name="Test Event 1")
26+
event_2: Event = Event.objects.create(organization=organization, name="Test Event 2")
27+
28+
event_1_prst_type_1 = PresentationType.objects.create(event=event_1, name="Type 1")
29+
event_1_prst_type_2 = PresentationType.objects.create(event=event_1, name="Type 2")
30+
event_2_prst_type_1 = PresentationType.objects.create(event=event_2, name="Type 1")
31+
event_2_prst_type_2 = PresentationType.objects.create(event=event_2, name="Type 2")
32+
33+
event_1_prst_type_1_prst = Presentation.objects.create(type=event_1_prst_type_1, title="Presentation 1")
34+
event_1_prst_type_2_prst = Presentation.objects.create(type=event_1_prst_type_2, title="Presentation 2")
35+
event_2_prst_type_1_prst = Presentation.objects.create(type=event_2_prst_type_1, title="Presentation 3")
36+
Presentation.objects.create(type=event_2_prst_type_2, title="Presentation 4")
37+
38+
# When: API 요청을 통해 행사 1의 발표 유형 1과 2에 해당하는 발표를 요청할 시
39+
qs = urllib.parse.urlencode(
40+
{"event": event_1.name, "types": f"{event_1_prst_type_1.name},{event_1_prst_type_2.name}"}
41+
)
42+
response = api_client.get(f"{reverse('v1:presentation-list')}?{qs}")
2243

44+
# Then: 행사 1의 발표 유형 1과 2에 해당하는 발표가 반환되어야 함.
2345
assert response.status_code == http.HTTPStatus.OK
24-
assert len(response.json()) > 0
2546

47+
response_data = response.json()
48+
assert len(response_data) == 2, "Should return 2 presentations for event 1 with specified types"
49+
assert {datum["id"] for datum in response_data} == {
50+
str(event_1_prst_type_1_prst.id),
51+
str(event_1_prst_type_2_prst.id),
52+
}
2653

27-
@pytest.mark.django_db
28-
def test_presentation_category_filter_api_should_not_return_unknown_category_id(
29-
api_client: APIClient, create_presentation_set: PresentationTestEntity
30-
):
31-
url = f"{reverse('v1:presentation-list')}?categories={uuid.uuid4()}"
32-
response = api_client.get(url)
54+
# When: API 요청을 통해 행사 유형은 지정하지 않고 유형 1에 해당하는 발표를 요청할 시
55+
qs = urllib.parse.urlencode({"types": event_1_prst_type_1.name})
56+
response = api_client.get(f"{reverse('v1:presentation-list')}?{qs}")
3357

58+
# Then: 행사 1의 발표 유형 1과 행사 2의 발표 유형 1에 해당하는 발표가 반환되어야 함.
3459
assert response.status_code == http.HTTPStatus.OK
35-
assert len(response.json()) == 0, "Should not return any presentations for unknown category ID"
60+
61+
response_data = response.json()
62+
assert len(response_data) == 2, "Should return presentations for type 1 across all events"
63+
assert {datum["id"] for datum in response_data} == {
64+
str(event_1_prst_type_1_prst.id),
65+
str(event_2_prst_type_1_prst.id),
66+
}

app/event/presentation/views.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
1-
from core.const.regex import UUID_V4_REGEX
21
from core.const.tag import OpenAPITag
3-
from django.db.models import QuerySet
2+
from core.models import BaseAbstractModelQuerySet
3+
from django.db.models import Q
44
from django.utils.decorators import method_decorator
55
from django_filters import rest_framework as filters
66
from django_filters.constants import EMPTY_VALUES
77
from drf_spectacular.utils import extend_schema
8-
from event.presentation.models import Presentation, PresentationCategory, PresentationCategoryRelation
8+
from event.presentation.models import Presentation, PresentationCategory
99
from event.presentation.serializers import PresentationSerializer
10-
from rest_framework import mixins, serializers, viewsets
10+
from rest_framework import mixins, viewsets
1111

1212

1313
class PresentationFilterSet(filters.FilterSet):
14-
type = filters.UUIDFilter(field_name="type_id")
15-
categories = filters.BaseCSVFilter(method="filter_by_category_ids")
14+
event = filters.CharFilter(method="filter_by_event_name")
15+
types = filters.BaseCSVFilter(method="filter_by_type_names")
1616

17-
def filter_by_category_ids(self, queryset: QuerySet, name: str, value: list[str]) -> QuerySet:
18-
if not value or value in EMPTY_VALUES:
17+
def filter_by_event_name(self, queryset: BaseAbstractModelQuerySet, name: str, value: str) -> Q:
18+
if value in EMPTY_VALUES:
1919
return queryset
20-
if not any(UUID_V4_REGEX.match(v) for v in value):
21-
return serializers.ValidationError(f"Invalid UUID format in {name} filter: {value}.")
2220

23-
target_ids = PresentationCategoryRelation.objects.filter(category__id__in=value).values_list("presentation_id")
24-
return queryset.filter(id__in=target_ids)
21+
return queryset.filter(Q(type__event__name_ko=value) | Q(type__event__name_en=value))
22+
23+
def filter_by_type_names(self, queryset: BaseAbstractModelQuerySet, name: str, values: list[str]) -> Q:
24+
if values in EMPTY_VALUES:
25+
return queryset
26+
27+
return queryset.filter(Q(type__name_ko__in=values) | Q(type__name_en__in=values))
2528

2629

2730
@method_decorator(name="list", decorator=extend_schema(tags=[OpenAPITag.EVENT_PRESENTATION]))

0 commit comments

Comments
 (0)