[Django] DRF 개요: Serializer, ViewSet, Router
django rest framework, DRF, APIView, ViewSet, Serializer, Router
학습 로드맵
이 페이지는 개요. 처음 접하는 사람은 아래 순서로 읽으면 자연스럽다:
flowchart TD
S["1. [[drf-tutorial-quickstart]]<br/>5분 안에 동작하는 API"]
S --> RR["2. [[drf-request-response]]<br/>request.data / Response()"]
RR --> Ser["3. [[django-drf-serializers]]<br/>Model ↔ JSON 변환"]
Ser --> V["4. [[drf-views]]<br/>APIView, Generic Views"]
V --> VS["5. [[django-drf-viewset]]<br/>ViewSet + @action"]
VS --> R["6. [[drf-routers]]<br/>URL 자동 생성"]
R --> A["7. [[drf-authentication]]<br/>Session, Token, JWT"]
A --> P["8. [[django-drf-permissions]]<br/>권한 검사"]
P --> PT["9. [[drf-pagination-throttling]]<br/>페이징 + rate limit"]
PT --> F["10. [[drf-filtering]]<br/>?q=&search=&ordering="]
F --> Ver["11. [[drf-versioning-content-negotiation]]<br/>버전 관리 + Accept"]
Ver --> Doc["12. [[drf-schemas-openapi]]<br/>Swagger 자동 문서화"]
Doc --> T["13. [[drf-testing]]<br/>APIClient 테스트"]
DRF 는 파이프라인이 핵심. 한번 그림으로 보면 이해가 쉽다:
정의
**Django REST Framework (DRF)**는 Django 위에 REST API 구축을 위한 사실상 표준 라이브러리. Serializer(데이터 변환·검증), View/ViewSet(엔드포인트), Router(URL 자동 생성), Permission/Throttle/Filter 시스템을 제공한다. OpenAPI 자동 생성도 가능.
설치
pip install djangorestframework
INSTALLED_APPS = [
...,
"rest_framework",
]
Serializer
# blog/serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField(read_only=True)
tag_count = serializers.IntegerField(source="tags.count", read_only=True)
class Meta:
model = Post
fields = ["id", "title", "body", "author", "tag_count", "created_at"]
read_only_fields = ["created_at"]
직렬화:
post = Post.objects.first()
serializer = PostSerializer(post)
serializer.data # {"id": 1, "title": "...", ...}
역직렬화 + 검증 + 저장:
serializer = PostSerializer(data=request.data)
if serializer.is_valid():
post = serializer.save(author=request.user)
else:
print(serializer.errors)
일반 Serializer (Form 비슷)
class CommentSerializer(serializers.Serializer):
post_id = serializers.IntegerField()
body = serializers.CharField(max_length=500)
def validate_body(self, value):
if "스팸" in value:
raise serializers.ValidationError("부적절한 내용")
return value
def validate(self, data):
if not Post.objects.filter(id=data["post_id"]).exists():
raise serializers.ValidationError("존재하지 않는 글")
return data
def create(self, validated_data):
return Comment.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.body = validated_data["body"]
instance.save()
return instance
ModelSerializer가 대부분 자동화하지만 일반 Serializer는 더 자유로움.
APIView (function-based 권장 안 함)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class PostListAPI(APIView):
def get(self, request):
posts = Post.objects.all()
serializer = PostSerializer(posts, many=True)
return Response(serializer.data)
def post(self, request):
serializer = PostSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
post = serializer.save(author=request.user)
return Response(PostSerializer(post).data, status=status.HTTP_201_CREATED)
generic views
from rest_framework import generics
class PostListCreate(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
class PostDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
lookup_field = "slug"
자주 쓰는 패턴 즉시 사용.
ViewSet
from rest_framework import viewsets
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.select_related("author")
serializer_class = PostSerializer
def perform_create(self, serializer):
serializer.save(author=self.request.user)
def get_queryset(self):
qs = super().get_queryset()
if q := self.request.query_params.get("q"):
qs = qs.filter(title__icontains=q)
return qs
CRUD 모두 한 클래스에. ModelViewSet은 list, retrieve, create, update, partial_update, destroy 액션 자동.
Router
# urls.py
from rest_framework.routers import DefaultRouter
from .views import PostViewSet
router = DefaultRouter()
router.register("posts", PostViewSet, basename="post")
urlpatterns = [
path("api/", include(router.urls)),
]
자동 생성된 URL:
GET /api/posts/ → list
POST /api/posts/ → create
GET /api/posts/{pk}/ → retrieve
PUT /api/posts/{pk}/ → update
PATCH /api/posts/{pk}/ → partial_update
DELETE /api/posts/{pk}/ → destroy
@action: 커스텀 액션
from rest_framework.decorators import action
class PostViewSet(ModelViewSet):
@action(detail=True, methods=["post"])
def publish(self, request, pk=None):
post = self.get_object()
post.is_published = True
post.save()
return Response({"status": "published"})
@action(detail=False, methods=["get"])
def featured(self, request):
qs = self.get_queryset().filter(is_featured=True)
page = self.paginate_queryset(qs)
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
URL: POST /api/posts/{pk}/publish/, GET /api/posts/featured/.
Permission
# settings.py
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticated",
],
}
# 또는 view 별
class PostViewSet(ModelViewSet):
permission_classes = [IsAuthenticatedOrReadOnly]
자주 쓰는 것:
AllowAnyIsAuthenticatedIsAdminUserIsAuthenticatedOrReadOnly- 커스텀
커스텀 권한
from rest_framework import permissions
class IsAuthorOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
return request.method in permissions.SAFE_METHODS or request.user.is_authenticated
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.author == request.user
Authentication
# settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
],
}
- SessionAuthentication: Django 세션 (브라우저)
- BasicAuthentication: HTTP Basic (디버그용)
- TokenAuthentication: DB에 저장된 토큰
- JWTAuthentication (simplejwt): stateless JWT
JWT 설정
pip install djangorestframework-simplejwt
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_simplejwt.authentication.JWTAuthentication",
],
}
# urls.py
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
urlpatterns = [
path("api/token/", TokenObtainPairView.as_view()),
path("api/token/refresh/", TokenRefreshView.as_view()),
]
Pagination
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
}
자동 적용. 응답:
{
"count": 100,
"next": "https://.../api/posts/?page=3",
"previous": "https://.../api/posts/?page=1",
"results": [...]
}
다른 페이지네이션:
LimitOffsetPagination:?limit=10&offset=20CursorPagination: 안정적 큰 데이터셋
Filter / Search / Ordering
pip install django-filter
REST_FRAMEWORK = {
"DEFAULT_FILTER_BACKENDS": [
"django_filters.rest_framework.DjangoFilterBackend",
"rest_framework.filters.SearchFilter",
"rest_framework.filters.OrderingFilter",
],
}
class PostViewSet(ModelViewSet):
filterset_fields = ["author", "is_published"]
search_fields = ["title", "body"]
ordering_fields = ["created_at", "views"]
쿼리:
GET /api/posts/?author=1&is_published=true
GET /api/posts/?search=django
GET /api/posts/?ordering=-views
Throttle
REST_FRAMEWORK = {
"DEFAULT_THROTTLE_CLASSES": [
"rest_framework.throttling.AnonRateThrottle",
"rest_framework.throttling.UserRateThrottle",
],
"DEFAULT_THROTTLE_RATES": {
"anon": "100/day",
"user": "1000/day",
},
}
레이트 리밋. Redis 백엔드 권장 (django-throttle).
OpenAPI / Swagger
pip install drf-spectacular
INSTALLED_APPS += ["drf_spectacular"]
REST_FRAMEWORK["DEFAULT_SCHEMA_CLASS"] = "drf_spectacular.openapi.AutoSchema"
# urls.py
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView
urlpatterns += [
path("api/schema/", SpectacularAPIView.as_view(), name="schema"),
path("api/docs/", SpectacularSwaggerView.as_view(url_name="schema"), name="swagger"),
]
자동으로 OpenAPI 3 스펙 + Swagger UI 생성.
함정
1. ModelSerializer로 노출 위험
class UserSerializer(ModelSerializer):
class Meta:
model = User
fields = "__all__" # password 해시 노출!
fields/exclude 명시. password, 내부 필드 제외.
2. N+1 in serializer
class PostSerializer(ModelSerializer):
author_name = serializers.CharField(source="author.username")
# author 매번 조회 → N+1
# ViewSet에서
class PostViewSet(ModelViewSet):
queryset = Post.objects.select_related("author") # 미리 JOIN
3. PUT vs PATCH
PUT: 전체 교체 (모든 필드 필요)PATCH: 부분 업데이트 (partial=True)
serializer = PostSerializer(post, data=request.data, partial=True)
ModelViewSet은 partial_update 액션이 자동 처리.
4. validate_<field> vs validate
validate_<field>: 단일 필드validate: 다중 필드 관계 (cleaned data 전체)
5. Write/Read 분리
class PostSerializer(ModelSerializer):
tags = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all())
tag_names = TagSerializer(many=True, source="tags", read_only=True)
class Meta:
model = Post
fields = ["id", "title", "tags", "tag_names"]
write는 ID로 받고 read는 nested로.
이 글의 용어 (13개)
- [Django] DRF Permission, Throttle, Filterdjango
- 정의 DRF는 view 호출 전 인증(Authentication) → 권한(Permission) → 스로틀(Throttle) 순으로 검사. 각 단계가 통과해야 view 메서드 실…
- [Django] DRF Serializer 심화django
- 정의 DRF Serializer는 JSON ↔ Python ↔ Model의 변환과 검증을 담당한다. Django Form과 비슷한 인터페이스이나 API/JSON에 특화. 검증, …
- [Django] DRF ViewSet, Router, @actiondjango
- 정의 ViewSet은 같은 리소스의 관련 view들을 클래스 하나로 묶는다. Django의 generic views와 비슷하나 / / / / / action 메서드로 통일. Ro…
- [DRF] Authentication: Session, Token, JWT, OAuth2django
- 정의 Authentication = 누가 요청했는지 식별. Authorization () 과 별개. 흐름 자세한 permission 은 . 내장 Authentication Cla…
- [DRF] Filtering: django-filter, SearchFilter, OrderingFilterdjango
- 정의 Filtering = 쿼리 파라미터로 결과 제한. 3가지 backend + custom. 3가지 내장 Backend 설치 + 설정 1. DjangoFilterBackend …
- [DRF] Pagination + Throttlingdjango
- 정의 Pagination = 큰 목록을 페이지 단위로 나눔. Throttling = 요청 빈도 제한. 둘 다 API 안정성의 기본. Pagination 3종 언제 어느 것을 쓸까…
- [DRF] Request + Response 객체django
- 정의 DRF 의 = Django 의 확장. = 의 확장. 자동 content negotiation + renderer 처리. 요청이 뷰에 도달하기까지 에 값이 실제로 들어가려면 …
- [DRF] Routers: DefaultRouter, SimpleRouter, custom actionsdjango
- 정의 Router = ViewSet 에 대한 URL 자동 생성. Rails 의 와 유사. 왜 Router? 종류 DefaultRouter 생성되는 URL: | URL | Meth…
- [DRF] Schemas + OpenAPI: 자동 문서화django
- 정의 OpenAPI (전 Swagger) = REST API를 기계 가독 스펙으로 기술하는 표준. DRF는 이 스펙을 ViewSet / Serializer 로부터 자동 추출할 수…
- [DRF] Testing: APIClient, APITestCase, force_authenticatedjango
- 정의 DRF의 테스트 도구는 Django 위에 API 특화 helper 를 얹은 것. 로 real endpoint 를 호출하거나 로 View 단위 테스트가 가능. 테스트 도구 계…
- [DRF] Tutorial + Quickstart: 첫 API 서버 5분django
- 정의 Django REST Framework (DRF) 를 처음 사용 하는 사람을 위한 순차 시작 가이드. 5분 안에 동작하는 API 서버 완성. DRF 개요는 . Django …
- [DRF] Versioning + Content Negotiationdjango
- 정의 Versioning = API 의 여러 버전 공존. Content Negotiation = 같은 endpoint 가 여러 형식 (JSON, XML, HTML) 응답. Ver…
- [DRF] Views: APIView, GenericViews, Mixins, FBVdjango
- 정의 DRF View 4가지 스타일. 자유도 vs 자동화 트레이드오프. 4가지 스타일 | 스타일 | 코드량 | 자유도 | |---|---|---| | | 유사 Django FBV…
💬 댓글