Skip to content

Commit f863d80

Browse files
authored
Docs/merchanidse swagger (#61)
* Docs: Merchandise에 대해 swagger 데이터 추가 * Feat: 일관된 응답을 리턴하도록 로직 수정
1 parent c10b530 commit f863d80

File tree

8 files changed

+90
-85
lines changed

8 files changed

+90
-85
lines changed

src/config/settings.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
REST_FRAMEWORK = {
5757
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
5858
"DEFAULT_PAGINATION_CLASS": "core.paginations.PageNumberPagination",
59-
"EXCEPTION_HANDLER": "rest_framework.views.exception_handler",
59+
"EXCEPTION_HANDLER": "core.middlewares.exception_handler.custom_exception_handler",
6060
"PAGE_SIZE_QUERY_PARAM": "page_size",
6161
"PAGE_SIZE": 10,
6262
"MAX_PAGE_SIZE": 100,

src/faq/views.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from drf_spectacular.utils import extend_schema_view
22
from rest_framework.viewsets import GenericViewSet
33

4-
from core.errors import NotExistException
54
from core.responses.base import BaseResponse
65

76
from .models import FAQ
@@ -18,8 +17,6 @@ def get_queryset(self):
1817

1918
def list(self, request, *args, **kwargs) -> BaseResponse:
2019
queryset = self.get_queryset()
21-
if not queryset.exists():
22-
raise NotExistException()
2320
page = self.paginate_queryset(queryset) # ✅ 페이지네이션 적용
2421
serializer = self.get_serializer(page or queryset, many=True)
2522
return self.get_paginated_response(serializer.data)

src/merchandise/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77

88
@admin.register(Merchandise)
99
class MerchandiseAdmin(admin.ModelAdmin):
10-
list_display = ("product_name", "image")
10+
list_display = ("name", "image")
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Generated by Django 5.1.5 on 2025-02-24 12:32
1+
# Generated by Django 5.1.5 on 2025-02-25 18:42
22

33
from django.db import migrations, models
44

@@ -10,19 +10,17 @@ class Migration(migrations.Migration):
1010

1111
operations = [
1212
migrations.CreateModel(
13-
name="Md",
13+
name="Merchandise",
1414
fields=[
1515
(
1616
"id",
1717
models.BigAutoField(
18-
auto_created=True,
19-
primary_key=True,
20-
serialize=False,
21-
verbose_name="ID",
18+
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
2219
),
2320
),
24-
("product_name", models.CharField(max_length=255)),
25-
("image", models.ImageField(upload_to="images/")),
21+
("name", models.CharField(max_length=255, verbose_name="상품 이름")),
22+
("description", models.TextField(blank=True, null=True, verbose_name="상품 설명")),
23+
("image", models.ImageField(upload_to="images/", verbose_name="썸네일 이미지")),
2624
],
2725
),
2826
]

src/merchandise/migrations/0002_merchandise_delete_md.py

Lines changed: 0 additions & 32 deletions
This file was deleted.

src/merchandise/models.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ class Merchandise(models.Model):
88
### MD 필드 정의
99
"""
1010

11-
product_name = models.CharField(max_length=255)
12-
product_info = models.TextField(null=True, blank=True)
13-
image = models.ImageField(upload_to="images/")
11+
name = models.CharField("상품 이름", max_length=255)
12+
description = models.TextField("상품 설명", null=True, blank=True)
13+
image = models.ImageField("썸네일 이미지", upload_to="images/")
1414

1515
def __str__(self):
16-
return self.product_name
16+
return self.name

src/merchandise/swagger.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from drf_spectacular.utils import OpenApiExample, OpenApiResponse
2+
3+
from core.responses.serializer import (
4+
ErrorResponseSerializer,
5+
ListSuccessResponseSerializer,
6+
)
7+
from core.swagger import SwaggerSchema
8+
9+
10+
class MerchandiseAPIDocs(SwaggerSchema):
11+
@classmethod
12+
def list(cls):
13+
responses = {
14+
"성공": OpenApiResponse(
15+
response=ListSuccessResponseSerializer,
16+
description="다중 응답 성공",
17+
examples=[
18+
OpenApiExample(
19+
name="상품 목록 조회 (페이지네이션 있음)",
20+
value={
21+
"status": "SUCCESS",
22+
"data": [
23+
{
24+
"id": 1,
25+
"product_name": "상품1",
26+
"product_info": "상품 설명입니다.",
27+
"image": "http://localhost:8000/media/merchandise/1.jpg",
28+
},
29+
],
30+
"pagination": {
31+
"count": 20,
32+
"next": "http://localhost:8000/api/v1/merchandise/?page=2",
33+
"previous": "http://localhost:8000/api/v1/merchandise/?page=1",
34+
},
35+
},
36+
),
37+
OpenApiExample(
38+
name="상품 목록 조회 (데이터 있음)",
39+
value={
40+
"status": "SUCCESS",
41+
"data": [
42+
{
43+
"id": 1,
44+
"product_name": "상품1",
45+
"product_info": "상품 설명입니다.",
46+
"image": "http://localhost:8000/media/merchandise/1.jpg",
47+
},
48+
],
49+
"pagination": {"count": 1, "next": None, "previous": None},
50+
},
51+
),
52+
OpenApiExample(
53+
name="Merchandise 목록 조회 (데이터 없음)",
54+
value={
55+
"status": "SUCCESS",
56+
"data": [],
57+
"pagination": {"count": 0, "next": None, "previous": None},
58+
},
59+
),
60+
],
61+
),
62+
"에러": OpenApiResponse(response=ErrorResponseSerializer, description="응답 에러"),
63+
}
64+
return cls.generate_schema(
65+
operation_id="merchandise_list", description="모든 상품 목록 조회", responses=responses
66+
)

src/merchandise/views.py

Lines changed: 12 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,20 @@
1-
from rest_framework import status
2-
from rest_framework.response import Response
3-
from rest_framework.viewsets import ReadOnlyModelViewSet
1+
from drf_spectacular.utils import extend_schema_view
2+
from rest_framework.viewsets import GenericViewSet
3+
4+
from core.responses.base import BaseResponse
45

56
from .models import Merchandise
67
from .serializers import MerchandiseSerializer
8+
from .swagger import MerchandiseAPIDocs
79

810

9-
class MerchandiseViewSet(ReadOnlyModelViewSet):
10-
"""
11-
MD 페이지는 상세보기 페이지가 존재하지 않으므로 retrieve는 생략되었습니다.
12-
"""
13-
11+
@extend_schema_view(list=MerchandiseAPIDocs.list())
12+
class MerchandiseViewSet(GenericViewSet):
1413
queryset = Merchandise.objects.all()
1514
serializer_class = MerchandiseSerializer
1615

17-
def list(self, request, *args, **kwargs):
18-
queryset = self.filter_queryset(self.get_queryset())
19-
if not queryset.exists():
20-
return Response(
21-
{
22-
"status_code": "200",
23-
"body": {
24-
"code": "success",
25-
"message": "MD 데이터가 존재하지 않습니다",
26-
"data": [],
27-
"pagination": {},
28-
},
29-
},
30-
status=status.HTTP_200_OK,
31-
)
32-
serializer = self.get_serializer(queryset, many=True)
33-
return Response(
34-
{
35-
"status_code": "200",
36-
"body": {
37-
"code": "success",
38-
"message": "성공",
39-
"data": serializer.data,
40-
"pagination": {},
41-
},
42-
},
43-
status=status.HTTP_200_OK,
44-
)
16+
def list(self, request, *args, **kwargs) -> BaseResponse:
17+
queryset = self.get_queryset()
18+
page = self.paginate_queryset(queryset)
19+
serializer = self.get_serializer(page or queryset, many=True)
20+
return self.get_paginated_response(serializer.data)

0 commit comments

Comments
 (0)