오늘 학습 내용 ✅
- 오늘의 코드 작업
질문등록 API 머지 완료 / 질문 조회 API 기본기능을 끝내는것이 오늘의 목표
질문 조회 시리얼라이저가 2개가 되는 이유
- question_list_query.py → 입력 (query params 검증)
- 요청 파라미터 검증 (page, category, keyword 등)
- question_list.py → 출력 (response 직렬화)
- 응답 데이터 구조 정의 (id, title, author, created_at 등)
- 입력 / 출력은 관심사가 다르기 때문에 합치지 않는 게 정상
- 조회니까 하나로 묶는 경우
- 입력과 출력이 섞임 / serializer.is_valid()의 의미가 흐려짐
Django REST Framework
- serializers.py — “데이터 계약 + 입력 검증”
- 입력 데이터 검증
- class QuestionListQuerySerializer(serializers.Serializer):
- 타입 / 범위 / 필수 여부 / 포맷
- 출력 데이터 구조 정의
- class QuestionListSerializer(serializers.ModelSerializer):
- 어떤 필드를 내려줄지 / 프론트와의 응답 계약
- 단순 필드 가공 (OK)
- 문자열 자르기 / 날짜 포맷 변경 / DB 조회X
❌ Question.objects.filter(...)
❌ qs.exists()
❌ raise QuestionListEmptyError
❌ permission 체크
serializer는 절대 DB 상태 판단 ❌
views.py — “HTTP 조립 담당자”
- 요청 → serializer → service → response 흐름
- 요청 받기 / serializer 호출 / service 호출 / Response 만들기
- HTTP status 결정
- return Response(data, status=200)
❌ ORM 쿼리
❌ annotate
❌ 비즈니스 규칙
❌ exists() 판단
permissions.py — “접근 가능 여부 판단기”
- 이 요청을 누가 할 수 있는지 → permission은 if/else 판단만
- 인증 여부 / 역할 / 소유자 여부 (내 글만 수정)
class QuestionCreatePermission(BasePermission):
def has_permission(self, request, view):
return request.user.role == RoleChoices.ST
- 접근 불가 시 즉시 차단
- raise QuestionCreateNotAuthenticated()
❌ 데이터 생성
❌ 조회 조건
❌ business logic
services.py — “유스케이스의 핵심”
- 유스케이스 흐름 (Orchestration) → 여러 단계를 조합 / 순서가 중요 / 정책이 들어감
def get_question_list(...):
qs = base_queryset()
qs = apply_filters(qs)
if not qs.exists():
raise QuestionListEmptyError()
return paginate(qs)
- 도메인 가드 (실무 핵심 개념) → 비즈니스 정책
if not qs.exists():
raise QuestionListEmptyError()
- ORM 쿼리 구성 → 성능 최적화 / 조회 전략
Question.objects.select_related(...).annotate(...)
❌ request / response
❌ serializer.is_valid()
❌ HTTP status
qs 이해
- qs는 “데이터”가 아니라 ‘어떤 데이터를 어떻게 가져올지 적어놓은 주문서’
qs = Question.objects.annotate(...).order_by(...)
qs = filter_by_answered(qs, answered)
qs = filter_by_category(qs, category)
qs = filter_by_search(qs, search)
if not qs.exists():
page_obj = paginator.get_page(page)
page_obj.object_list
새롭게 알게된 내용 ✅
- serializer = QuestionListSerializer(data=request.data)
- 조회 api에서는 사용하지 않음
- output serializer는 .data로 쓰지 .is_valid() 안 함
어려운 내용(추가 학습 필요) ✅
오늘 발생한 문제(발생 했다면) ✅