from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Category
from .serializers import CategorySerializer
classCategoryListAPIView(APIView):defget(self, request):
categories = Category.objects.all() # 직접 쿼리셋 가져오기
serializer = CategorySerializer(categories, many=True) # 직접 시리얼라이징return Response(serializer.data) # JSON 응답
이렇게 직접 get, post, update, delete를 적고 해줘야 하지만,
제네렉 view는
from rest_framework.generics import ListAPIView
from .models import Category
from .serializers import CategorySerializer
classCategoryListAPIView(ListAPIView):
queryset = Category.objects.all() # 자동으로 가져옴
serializer_class = CategorySerializer # 자동으로 직렬화
이렇게 각 API에 따라 get, post, update, delete를 해줄 필요가 없으며, 직렬화도 자동으로 해주기 때문에, 직렬화 시리얼라이저를 넣어주면 끝이다.
select_related() (SQL JOIN, 즉시 가져오기) 언제? ForeignKey(1:N) 또는 OneToOneField(1:1) 관계에서 사용 SQL의 JOIN을 사용해 쿼리 1번으로 관련된 데이터를 모두 가져옴
classAuthor(models.Model):
name = models.CharField(max_length=100)
classBook(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# ❌ select_related() 사용 안 함 (N+1 문제 발생)
books = Book.objects.all()
for book in books:
print(book.author.name) # author를 조회할 때마다 쿼리 실행됨 (N번)# ✅ select_related() 사용 (쿼리 1번만 실행됨)
books = Book.objects.select_related('author')
for book in books:
print(book.author.name) # 이미 가져온 데이터를 사용 (추가 쿼리 없음)
prefetch_related() (별도 쿼리, Python에서 매칭) 언제? ManyToManyField(N:N) 또는 역참조(related_name을 통한 조회) SQL에서 JOIN이 불가능한 경우 여러 개의 쿼리를 실행하고, Django가 Python에서 관계를 매칭
classStudent(models.Model):
name = models.CharField(max_length=100)
classCourse(models.Model):
title = models.CharField(max_length=100)
students = models.ManyToManyField(Student)
# ❌ prefetch_related() 사용 안 함 (N+1 문제 발생)
courses = Course.objects.all()
for course in courses:
for student in course.students.all(): # 각 Course마다 쿼리 실행 (N번)print(student.name)
# ✅ prefetch_related() 사용 (쿼리 2번만 실행)
courses = Course.objects.prefetch_related('students')
for course in courses:
for student in course.students.all(): # 이미 가져온 데이터를 사용 (추가 쿼리 없음)print(student.name)
Django ORM에서 only()와 defer()를 사용하면 불필요한 필드를 제외하고 쿼리를 최적화할 수 있다. only() → 가져올 필드를 명시적으로 지정 (나머지 필드는 deferred) defer() → 특정 필드만 제외하고 나머지를 가져옴 ----------------------------------------------------------- only(): 특정 필드만 가져오기 only('필드1', '필드2') → 해당 필드만 즉시 가져오고, 나머지는 나중에 가져옴 (Lazy Loading)
classBook(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
published_date = models.DateField()
# ❌ only() 사용 안 함 (모든 필드를 가져옴)
books = Book.objects.all()
for book in books:
print(book.title, book.description) # 모든 필드가 메모리에 로드됨# ✅ only() 사용 (title만 즉시 가져오고, 나머지는 나중에 가져옴)
books = Book.objects.only('title')
for book in books:
print(book.title) # title은 즉시 가져옴print(book.description) # 이 시점에서 추가 쿼리 발생 (Lazy Loading)
defer(): 특정 필드 제외하기 defer('필드명') → 지정한 필드 제외하고 나머지를 즉시 가져옴
# ✅ description 필드만 제외하고 가져옴
books = Book.objects.defer('description')
for book in books:
print(book.title) # 즉시 가져옴print(book.description) # 이 시점에서 추가 쿼리 발생 (Lazy Loading)
Django 인덱싱 db_index=True 사용 (단일 필드 인덱스) 언제? 자주 검색(QuerySet filter), 정렬(order_by()) 또는 조인(ForeignKey)이 사용되는 필드에 인덱스 적용
classProduct(models.Model):
name = models.CharField(max_length=255)
sku = models.CharField(max_length=100, unique=True, db_index=True) # ✅ 인덱스 설정
price = models.DecimalField(max_digits=10, decimal_places=2)
2. Meta.indexes 사용 (복합 인덱스, 여러 필드) 언제? 여러 개의 필드를 조합해서 자주 검색하는 경우 (예: WHERE name='A' AND price=1000) 단일 필드 인덱스로 최적화되지 않는 경우
from django.db.models import Index
classProduct(models.Model):
name = models.CharField(max_length=255)
sku = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
classMeta:
indexes = [
Index(fields=['name', 'price']), # ✅ 복합 인덱스 생성
]
DRF에 대한 것 직렬화: DRF는 복잡한 Python 객체를 JSON 또는 다른 콘텐츠 유형으로 변환하기 위한 견고한 직렬화 프레임워크를 제공합니다. 직렬화기를 정의하여 API 응답에서 데이터가 표시되는 방식과 들어오는 데이터가 처리되는 방식을 제어할 수 있습니다.
인증과 권한: DRF는 토큰 기반 인증, 세션 인증, OAuth 등 다양한 인증 체계를 제공하여 API를 보안합니다. 또한 사용자 역할과 권한에 기반하여 리소스에 대한 액세스를 제어하는 유연한 권한 시스템을 제공합니다.
뷰셋과 라우터: DRF는 뷰셋이라는 개념을 도입하였습니다. 뷰셋은 단일 모델 또는 리소스에 대한 여러 개의 뷰를 결합하는 클래스입니다. 뷰셋은 생성, 조회, 업데이트, 삭제(CRUD) 등의 작업을 쉽게 수행할 수 있도록 지원합니다. DRF는 뷰셋에 대한 URL 라우팅을 간소화하기 위해 자동으로 URL 패턴을 생성하는 라우터를 포함하고 있습니다.
Browsable API: DRF는 Browsable API 기능을 제공하여 개발자가 웹 브라우저를 통해 API와 상호 작용할 수 있도록 합니다. 이 기능은 API의 사용자 친화적인 HTML 표현을 제공하며, 요청 제출을 위한 양식, 엔드포인트 간의 탐색, 페이지네이션 지원 등을 포함합니다.
페이지네이션: DRF는 대량의 데이터셋을 페이지별로 나누어 API 성능을 최적화하고 사용자 경험을 향상시키기 위한 기능을 내장하고 있습니다. 커서 기반 페이지네이션, 페이지 번호 기반 페이지네이션 및 사용자 정의 페이지네이션 옵션과 같은 다양한 페이지네이션 전략을 제공합니다.
필터링과 정렬: DRF는 쿼리 매개변수를 사용하여 API 쿼리셋을 쉽게 필터링하고 정렬할 수 있도록 지원합니다. 완전히 일치하는, 부분 일치하는, 대소문자를 구분하지 않는 등의 일반적인 필터링 작업에 대한 필터 백엔드를 제공합니다. 또한 DRF는 여러 필드를 기준으로 정렬하고 사용자 정의 정렬 옵션을 지원합니다.
콘텐츠 네고시에이션: DRF는 콘텐츠 네고시에이션을 지원하여 클라이언트가 JSON, XML 또는 HTML과 같은 다른 형식으로 데이터를 요청할 수 있도록 합니다. API는 클라이언트의 요청에 따라 적절한 콘텐츠 유형을 자동으로 결정할 수 있습니다.
직렬화 유효성 검사: DRF는 직렬화 유효성 검사 기능을 제공하여 들어오는 데이터가 직렬화기에서 정의한 데이터 유형, 필드 제약 조건 및 유효성 검사 규칙을 준수하는지 확인할 수 있습니다.
버전 관리: DRF는 API 버전 관리를 지원하여 다양한 API 버전을 관리하고 역호환성을 처리할 수 있도록 합니다.
테스트 프레임워크: DRF는 API 테스트를 간소화하기 위해 테스트 클래스와 유틸리티를 제공하는 테스트 프레임워크를 제공합니다. 이를 통해 API 테스트를 생성하고 요청을 시뮬레이트하며 응답을 유효성 검사할 수 있습니다.
뷰 셋과, 뷰 제네렉 DRF에서 뷰셋(ViewSets)과 뷰 제네릭(View Generic)은 비슷한 역할을 하지만, 사용 방법과 자동화 수준에서 차이가 있습니다. 두 가지 모두 CRUD 작업을 자동화하는 데 도움을 주지만, 각각의 사용 목적과 구조가 다릅니다. 1. 뷰셋 (ViewSets) 뷰셋은 Django Rest Framework에서 제공하는 매우 편리한 클래스 기반 뷰입니다. 뷰셋을 사용하면 API의 CRUD 작업을 훨씬 간단하게 처리할 수 있습니다. 기본적으로 뷰셋은 HTTP 메서드 (GET, POST, PUT, DELETE 등)에 맞춰 여러 동작을 처리하는 메서드들이 내장되어 있습니다.
장점: 자동으로 여러 HTTP 메서드를 처리. ViewSet을 상속하면 여러 동작을 별도로 작성할 필요 없이 자동으로 처리. 라우터(Routers)와 결합하면 URL 설정을 따로 해줄 필요 없이 자동으로 URL을 매핑.
from rest_framework import viewsets
from .models import Item
from .serializers import ItemSerializer
classItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
참고로 라우터(Router)는 주로 Django 프로젝트의 urls.py 파일에 설정합니다. DRF에서 라우터를 사용하면, 뷰셋(ViewSet)을 자동으로 URL에 연결할 수 있기 때문에 URL 설정을 간소화할 수 있습니다. 라우터는 주로 프로젝트의 루트 URLconf 또는 앱의 urls.py에서 설정합니다. 라우터 설정: 구체적인 흐름: 라우터에 뷰셋 등록: DefaultRouter나 SimpleRouter에서 register() 메서드를 사용해 뷰셋(ViewSet)과 URL을 연결합니다. 자동으로 생성된 URL을 urlpatterns에 포함: 라우터는 등록된 뷰셋에 맞는 URL 패턴들을 생성하고, 이를 urlpatterns에 포함시켜서 실제 API에서 사용할 수 있게 만듭니다.
뷰셋 정의:
# myapp/views.pyfrom rest_framework import viewsets
from .models import Item
from .serializers import ItemSerializer
classItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
라우터에 뷰셋 등록:
# myapp/urls.pyfrom django.urls import path
from rest_framework.routers import DefaultRouter
from .views import ItemViewSet
# DefaultRouter 생성
router = DefaultRouter()
# 'items' URL 패턴을 ItemViewSet에 연결
router.register(r'items', ItemViewSet)
# 생성된 URL 패턴을 urlpatterns에 포함
urlpatterns = router.urls
참고로 r을 URL 경로에 사용하면, 문자열 안에서 특수 문자가 처리되지 않고 그대로 사용되도록 보장됩니다. 예를 들어, 경로를 /items/로 지정할 때 **r'items'**처럼 사용하는 것은 경로가 그대로 해석되도록 하기 위함입니다.
router.register(r'items', ItemViewSet)
여기서 r'items'는 'items' 문자열을 그대로 처리하도록 하며, /items/ URL 경로를 지정합니다. 이때 r을 붙이지 않아도 동작하지만, 다른 경우에서 이스케이프 문자를 사용하려면 r을 붙이는 것이 좋습니다.
추가로 예시: 뷰셋에서의 동작 ModelViewSet을 사용할 때는 다음과 같은 내장 메서드를 사용해 요청을 처리합니다: list(): GET /items/ -> 모든 항목을 반환. create(): POST /items/ -> 새로운 항목을 생성. retrieve(): GET /items/{id}/ -> 특정 항목을 반환. update(): PUT /items/{id}/ -> 항목을 수정. destroy(): DELETE /items/{id}/ -> 항목을 삭제.
# myapp/views.pyfrom rest_framework import viewsets
from .models import Item
from .serializers import ItemSerializer
classItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
# 만약에 특정 메서드를 커스터마이징하고 싶다면, 해당 메서드를 오버라이드하여 정의할 수 있습니다.deflist(self, request, *args, **kwargs):# GET /items/ 요청이 들어왔을 때 처리할 로직print("GET 요청 처리")
returnsuper().list(request, *args, **kwargs) # 기본 동작 유지defcreate(self, request, *args, **kwargs):# POST /items/ 요청이 들어왔을 때 처리할 로직print("POST 요청 처리")
returnsuper().create(request, *args, **kwargs) # 기본 동작 유지defdestroy(self, request, *args, **kwargs):# DELETE /items/{id}/ 요청이 들어왔을 때 처리할 로직print("DELETE 요청 처리")
returnsuper().destroy(request, *args, **kwargs) # 기본 동작 유지
아무튼 2. 뷰 제네릭 (View Generic) 뷰 제네릭은 더 많은 제어가 필요한 경우 사용됩니다. 일반적으로 ListAPIView, CreateAPIView, RetrieveAPIView, UpdateAPIView, DestroyAPIView와 같은 제네릭 뷰를 사용하여 각 작업을 처리합니다. 뷰 제네릭은 ModelViewSet과 달리 특정 작업에 대해 별도의 클래스를 만들어 사용합니다. 장점: 작업별로 세밀한 제어 가능. ViewSet을 사용하는 것보다 코드가 좀 더 명시적이고, 필요에 따라 더 복잡한 로직을 넣기 용이. APIView를 상속하여 필요한 메서드만 구현할 수 있어 더 유연함.
from rest_framework import generics
from .models import Item
from .serializers import ItemSerializer
classItemListView(generics.ListCreateAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
classItemDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Item.objects.all()
serializer_class = ItemSerializer
from django.urls import path
from .views import ItemListView, ItemDetailView
urlpatterns = [
path('items/', ItemListView.as_view(), name='item-list'),
path('items/<int:pk>/', ItemDetailView.as_view(), name='item-detail'),
]
뷰셋(ViewSet)은 하나의 클래스에서 모든 CRUD 동작을 자동으로 처리하는 반면, 뷰 제네릭(View Generics)은 각각의 HTTP 메서드에 대해 하나의 클래스로 동작을 정의하고 사용합니다. 뷰 제네릭은 단일 동작(예: GET, POST 등)에 집중할 때 유용하고, 뷰셋은 전체 CRUD 작업을 자동화하려는 경우 유용합니다.
페이지네이션(Pagination)은 데이터를 여러 페이지로 나누어 보여주는 기술입니다. 이 방법을 사용하면 많은 양의 데이터를 한 번에 반환하는 대신, 한 번에 일부 데이터만 제공하여 클라이언트가 데이터를 더 쉽게 소비할 수 있도록 합니다. 페이지네이션은 특히 데이터가 많을 때 성능을 최적화하고, 사용자가 필요한 정보를 더 빨리 찾을 수 있도록 도와줍니다. 페이지네이션의 장점: 성능 최적화: 한 번에 모든 데이터를 로드하는 대신 일부만 로드하여 서버의 부담을 줄이고, 페이지 로딩 속도를 개선할 수 있습니다. 사용자 경험 개선: 너무 많은 데이터를 한 번에 보여주면 화면이 복잡해지기 때문에, 필요한 데이터를 한 번에 보여주어 사용자가 쉽게 탐색할 수 있습니다. 네트워크 효율성: 클라이언트가 한 번에 많은 데이터를 다운로드하지 않기 때문에, 네트워크 자원을 절약할 수 있습니다. DRF에서 페이지네이션 사용하기 DRF에서는 페이지네이션을 쉽게 설정하고 사용할 수 있도록 여러 옵션을 제공합니다. 기본적으로, 데이터를 페이지별로 나누어 반환하는 Pagination 클래스를 제공합니다. DRF에서 기본 페이지네이션 설정 방법: 설정 파일 수정 (settings.py): 기본 페이지네이션 클래스를 설정하여 모든 API에서 페이지네이션을 적용할 수 있습니다.
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10, # 한 페이지에 반환할 항목 수 (예: 10개)
}
페이지네이션 클래스 설명: PageNumberPagination: 페이지 번호를 기준으로 데이터를 나누는 기본적인 페이지네이션 방식입니다. PAGE_SIZE를 설정하여 한 페이지당 반환할 아이템 수를 정의할 수 있습니다. 페이지네이션 동작 예시: 요청: GET /api/items/ 서버는 요청을 처리한 후, items를 여러 페이지로 나누어 반환합니다. 응답 (페이지네이션 결과):
{
"count": 100, # 전체 항목 수"next": "http://127.0.0.1:8000/api/items/?page=2", # 다음 페이지 URL"previous": null, # 이전 페이지 URL (첫 페이지일 경우 null)"results": [
{
"id": 1,
"name": "Item 1",
"description": "Description of item 1"
},
{
"id": 2,
"name": "Item 2",
"description": "Description of item 2"
},
...
]
}
count: 전체 항목 수 (전체 데이터 개수) next: 다음 페이지 URL previous: 이전 페이지 URL (첫 페이지에서는 null) results: 현재 페이지에 해당하는 데이터 목록
DRF에서 사용할 수 있는 다른 페이지네이션 클래스: LimitOffsetPagination: 쿼리 파라미터로 limit과 offset을 사용하여 데이터를 제한하고 시작점을 지정할 수 있는 페이지네이션 방식입니다. 예: GET /api/items/?limit=10&offset=20 CursorPagination: 커서 기반의 페이지네이션으로, 페이지를 넘길 때 "이전 페이지의 마지막 항목"을 기준으로 데이터를 반환합니다. 이 방식은 정렬된 데이터에 적합합니다. 페이지네이션의 동작 방식: PageNumberPagination: 사용자가 페이지 번호를 지정하면, 해당 페이지에 맞는 데이터를 반환합니다. 예를 들어, GET /api/items/?page=2 요청을 보내면 두 번째 페이지의 데이터가 반환됩니다. LimitOffsetPagination: limit과 offset을 사용하여 반환할 데이터의 범위를 설정할 수 있습니다. 예를 들어, GET /api/items/?limit=10&offset=20은 21번째부터 30번째까지의 항목을 반환합니다. CursorPagination: 이 방식은 커서를 사용하여 데이터를 페이지별로 나눕니다. 이전 페이지의 마지막 항목을 기준으로 데이터를 반환하므로, 정렬이 중요한 경우 유용합니다. 페이지네이션을 사용하지 않는 경우: 모든 데이터를 한 번에 반환하면 데이터가 많을 경우 서버의 성능에 문제가 생길 수 있고, 사용자는 한 페이지에서 너무 많은 데이터를 처리해야 하기 때문에 사용자 경험이 나빠질 수 있습니다. 예를 들어, 1,000개의 항목을 한 번에 보내면 사용자는 화면을 스크롤하는 데 시간이 많이 걸리고, 네트워크 트래픽도 과도해집니다. 예시:
from rest_framework.pagination import PageNumberPagination
classToyPagination(PageNumberPagination):
page_size = 5
paginate_queryset 메서드는 쿼리셋을 페이지별로 나누어주는 역할을 해. get_paginated_response는 페이지별로 응답을 반환하는 방법을 설정.
필터링과 정렬 (Filtering & Sorting)은 조금 어려우니 나중에. 콘텐츠 네고시에이션 (Content Negotiation) 콘텐츠 네고시에이션(Content Negotiation)**은 클라이언트가 요청하는 데이터 형식에 맞춰서 서버가 응답 형식을 자동으로 선택하는 기능입니다. 즉, 클라이언트가 원하는 응답 형식을 헤더에 명시하고, 서버는 이를 기반으로 적절한 형식으로 데이터를 반환하는 방식입니다.
1. 콘텐츠 네고시에이션 개념 클라이언트는 요청 시, Accept 헤더를 사용하여 어떤 형식의 응답을 원한다고 서버에 전달할 수 있습니다. 서버는 이 헤더를 읽고, 클라이언트가 원하는 형식에 맞춰 응답을 처리합니다. 이를 통해 다양한 형식의 데이터(JSON, XML, HTML 등)를 클라이언트와 서버가 유연하게 처리할 수 있습니다. 예를 들어, 클라이언트가 JSON 형식으로 데이터를 받고 싶다면 Accept 헤더에 application/json을 명시할 수 있고, XML 형식을 원하면 application/xml을 요청할 수 있습니다.
2. DRF에서의 콘텐츠 네고시에이션 Django REST Framework (DRF)에서는 콘텐츠 네고시에이션을 자동으로 처리하는 기능을 제공합니다. 클라이언트가 요청한 형식에 맞춰 데이터를 자동으로 직렬화(serialize)하여 응답 형식으로 반환합니다. DRF에서 기본적으로 지원하는 콘텐츠 네고시에이션: JSON (application/json) Browsable API HTML (웹 브라우저에서 볼 수 있는 HTML 형식) XML (application/xml) YAML (application/yaml) 3. 콘텐츠 네고시에이션 작동 방식 클라이언트가 요청하는 Accept 헤더를 서버가 읽고, 적절한 콘텐츠 형식을 선택하여 응답합니다. 예를 들어, 클라이언트가 Accept: application/json을 보낸 경우, 서버는 JSON 형식으로 데이터를 반환합니다.
4. 콘텐츠 네고시에이션 설정 (DRF) DRF에서 콘텐츠 네고시에이션을 설정하는 방법은 다음과 같습니다. 1. 기본 설정 DRF는 기본적으로 콘텐츠 네고시에이션을 처리할 수 있도록 설정되어 있습니다. 기본적으로 JSON 형식과 HTML 브라우저 API 형식이 자동으로 지원됩니다. 2. DEFAULT_RENDERER_CLASSES 설정 서버가 응답할 수 있는 콘텐츠 형식은 DEFAULT_RENDERER_CLASSES를 통해 정의할 수 있습니다. 예를 들어, JSON과 XML을 지원하고 싶다면, 다음과 같이 설정할 수 있습니다.
# settings.py
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer', # JSON 형식 응답'rest_framework.renderers.XMLRenderer', # XML 형식 응답
]
}
3. Accept 헤더를 활용한 콘텐츠 네고시에이션 예시
예를 들어, 클라이언트가 GET 요청을 보낼 때, 요청 헤더에 Accept: application/json을 추가하여 JSON 형식으로 데이터를 받도록 요청할 수 있습니다. 예시: 클라이언트가 GET 요청을 보낼 때 Accept: application/json을 설정하면, 서버는 JSON 형식으로 응답합니다.
GET /api/items/ HTTP/1.1
Host: example.com
Accept: application/json
콘텐츠 네고시에이션 예시 코드 다음은 뷰셋에서 콘텐츠 네고시에이션을 사용하는 예시 코드입니다.
# myapp/views.pyfrom rest_framework import viewsets
from rest_framework.renderers import JSONRenderer, XMLRenderer
from .models import Item
from .serializers import ItemSerializer
classItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.all()
serializer_class = ItemSerializer
# DRF에서 JSON과 XML 형식의 응답을 자동으로 선택할 수 있도록 설정
renderer_classes = [JSONRenderer, XMLRenderer]
renderer_classes: 이 설정을 통해 어떤 형식으로 응답할 것인지 서버가 선택할 수 있도록 지정합니다. 여기서는 JSON과 XML 형식으로 응답할 수 있게 설정되어 있습니다. 클라이언트가 요청 시, Accept 헤더를 사용하여 원하는 형식을 명시하면, DRF는 그에 맞는 형식으로 응답을 반환합니다. 혹은
장고 시리얼라이저 위 다이어그램은 Django의 모델과 시리얼라이저 간의 관계를 보여줍니다. - DjangoModel은 데이터베이스 모델을 나타내며, - 시리얼라이저는 DjangoModel과 JSON 데이터 간의 직렬화 및 역직렬화를 수행합니다. 시리얼라이저는 데이터의 필드와 메서드를 정의하며, serialize() 메서드는 DjangoModel을 JSON 형식으로 변환하고, deserialize() 메서드는 JSON 데이터를 DjangoModel로 변환합니다. - JSONData는 JSON 형식의 데이터를 나타내며, 시리얼라이저는 이를 다루는 역할을 합니다.
시리얼라이저는 Django의 폼과 유사한 기능을 제공하며, JSON 데이터의 유효성 검사, 필드 유형 변환, 관계 데이터 처리 등 다양한 작업을 수행할 수 있습니다. 시리얼라이저를 사용하여 복잡한 데이터를 쉽게 다룰 수 있고, API의 요청과 응답 처리에 유용합니다.
시리얼라이저 사용 예시 1. 모델 시리얼라이저(Model Serializer) 모델 시리얼라이저는 Django 모델을 기반으로 시리얼라이저를 쉽게 생성할 수 있도록 돕는 클래스입니다.
# myapp/serializers.pyfrom rest_framework import serializers
from .models import Item
# Item 모델에 대한 시리얼라이저classItemSerializer(serializers.ModelSerializer):classMeta:
model = Item
fields = ['id', 'name', 'price', 'created_at']
ItemSerializer는 Item 모델에 해당하는 데이터를 JSON 형식으로 직렬화합니다. ModelSerializer는 Django 모델을 기반으로 하여, 모델의 필드를 그대로 사용할 수 있도록 합니다. fields에서 반환하고자 하는 필드를 선택합니다.
2. 유효성 검사(Validation) 시리얼라이저는 요청 데이터를 검증(Validation)할 수 있습니다. 예를 들어, 특정 필드가 양수인지 확인하는 유효성 검사를 추가할 수 있습니다.
# myapp/serializers.pyfrom rest_framework import serializers
from .models import Item
classItemSerializer(serializers.ModelSerializer):classMeta:
model = Item
fields = ['id', 'name', 'price', 'created_at']
# 유효성 검사 추가defvalidate_price(self, value):if value <= 0:
raise serializers.ValidationError("Price must be a positive number.")
return value
자 여기서 궁금증 저 validate_price는 뭐고 value는 어떻게 들어갈까요? 핵심은 시리얼라이저에서 각 필드에 대한 검증 메서드가 자동으로 호출된다는 점입니다. 클라이언트 요청: 클라이언트가 API에 데이터를 보냅니다. 예를 들어, { "price": -10 }와 같은 JSON 데이터를 보낼 수 있습니다. 유효성 검사: 시리얼라이저는 각 필드에 대해 validate_<필드명> 메서드를 호출하여 유효성을 검사합니다. 이때 value는 클라이언트가 보낸 필드의 값이 됩니다. 검증 결과: 값이 유효하면, 시리얼라이저는 검증을 통과하고 데이터를 저장하거나 응답을 생성합니다. 값이 유효하지 않으면, ValidationError가 발생하고 에러 메시지가 반환됩니다.
쉽게 말하면 각 필드에 대한 값을 넣으면 그것에 대한 유효성을 검증하게 되는데 이렇게 되면 validate_<필드명>라는 함수가 자동으로 실행되게 됩니다. 즉 저 def validate_price에서 저 price는 필드의 값이 될 것이고 value는 자동으로 price가 들어가게 됩니다. 그렇기에 validate_<필드명>은 무조건 따라야하는 규칙입니다. 결국 value는 시리얼라이저에서 각 필드에 대해 클라이언트가 보낸 값을 의미하며, 유효성 검사 메서드에서 이를 확인하고 필요한 검증을 수행합니다.
즉 시리얼라이저를 실행하면 저 부분은 자동적으로 실행이 된다는 소리입니다. 즉, validate_price 메서드는 가격(price) 필드가 0 이하인 경우 유효성 오류를 발생시킵니다. 이를 통해 가격이 양수인지 확인합니다.
관계 데이터 처리 (Nested Serializer) 시리얼라이저는 관계형 데이터를 처리할 수 있습니다. 예를 들어, Item 모델에 Category 모델을 추가하고, ItemSerializer 안에 CategorySerializer를 포함시킬 수 있습니다.