TemplateResponse 인스턴스가 클라이언트로 반환되기 전에 렌더링되어야 합니다. 렌더링 과정은 템플릿과 컨텍스트의 중간 표현을 받아 클라이언트에게 제공할 수 있는 최종 바이트 스트림으로 변환하는 작업입니다.
— Django 문서
REST 프레임워크는 다양한 미디어 타입으로 응답을 반환할 수 있도록 여러 내장 렌더러 클래스들을 포함하고 있습니다. 또한, 자체적으로 정의한 사용자 지정 렌더러를 지원하여 원하는 미디어 타입을 디자인할 수 있는 유연성을 제공합니다.
뷰에 대해 유효한 렌더러 목록은 항상 클래스 목록으로 정의됩니다. 뷰에 접근할 때 REST 프레임워크는 들어오는 요청에 대해 콘텐츠 협상을 수행하고, 요청을 충족시킬 가장 적합한 렌더러를 결정합니다.
콘텐츠 협상의 기본 과정은 요청의 Accept 헤더를 검토하여 응답에서 기대하는 미디어 타입을 결정하는 것입니다. 선택적으로, URL의 포맷 접미사를 사용해 특정 표현을 명시적으로 요청할 수도 있습니다. 예를 들어, http://example.com/api/users_count.json은 항상 JSON 데이터를 반환하는 엔드포인트일 수 있습니다.
더 자세한 내용은 콘텐츠 협상 문서를 참조하세요.
기본 렌더러 목록은 DEFAULT_RENDERER_CLASSES 설정을 사용해 전역적으로 설정할 수 있습니다. 예를 들어, 아래 설정은 JSON을 주 미디어 타입으로 사용하고, 자기 설명적인 API를 포함시킵니다.
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
]
}
개별 뷰나 뷰셋에 대해 사용되는 렌더러를 APIView 클래스 기반 뷰에서 설정할 수도 있습니다.
from django.contrib.auth.models import User
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
class UserCountView(APIView):
"""
활성 사용자 수를 JSON으로 반환하는 뷰입니다.
"""
renderer_classes = [JSONRenderer]
def get(self, request, format=None):
user_count = User.objects.filter(active=True).count()
content = {'user_count': user_count}
return Response(content)
또는 함수 기반 뷰에서 @api_view 데코레이터를 사용해 설정할 수도 있습니다.
@api_view(['GET'])
@renderer_classes([JSONRenderer])
def user_count_view(request, format=None):
"""
활성 사용자 수를 JSON으로 반환하는 뷰입니다.
"""
user_count = User.objects.filter(active=True).count()
content = {'user_count': user_count}
return Response(content)
API에 대해 렌더러 클래스를 지정할 때 각 미디어 타입에 어떤 우선순위를 할당할지 고려하는 것이 중요합니다. 클라이언트가 허용하는 표현을 명확히 지정하지 않을 경우(예: Accept: */* 헤더를 보내거나 Accept 헤더를 포함하지 않는 경우), REST 프레임워크는 목록에서 첫 번째 렌더러를 선택해 응답을 반환합니다.
예를 들어, API가 JSON 응답과 HTML 브라우저 API를 제공한다면, JSONRenderer를 기본 렌더러로 지정해 Accept 헤더를 지정하지 않는 클라이언트에게 JSON 응답을 보낼 수 있습니다.
반대로, API에서 일반 웹페이지와 API 응답을 모두 제공해야 하는 경우라면, TemplateHTMLRenderer를 기본 렌더러로 지정해 구형 브라우저의 잘못된 Accept 헤더를 처리할 수 있습니다.
{"unicode black star":"★","value":999}
indent 미디어 타입 매개변수를 포함하면 반환되는 JSON이 들여쓰기 됩니다.{
"unicode black star": "★",
"value": 999
}
기본 JSON 인코딩 스타일은 UNICODE_JSON 및 COMPACT_JSON 설정 키를 통해 변경할 수 있습니다.
media_type: application/jsonformat: jsoncharset: NoneResponse로 전달된 데이터는 직렬화되지 않아도 됩니다. 또한, 응답을 생성할 때 template_name 인자를 포함시켜야 할 수 있습니다.TemplateHTMLRenderer는 response.data를 컨텍스트 딕셔너리로 사용하여 RequestContext를 생성하고, 이를 렌더링할 템플릿 이름을 결정합니다.
다음은 TemplateHTMLRenderer를 사용하는 뷰의 예입니다.
class UserDetail(generics.RetrieveAPIView):
"""
주어진 사용자의 템플릿된 HTML 표현을 반환하는 뷰입니다.
"""
queryset = User.objects.all()
renderer_classes = [TemplateHTMLRenderer]
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return Response({'user': self.object}, template_name='user_detail.html')
media_type: text/htmlformat: htmlcharset: utf-8@api_view(['GET'])
@renderer_classes([StaticHTMLRenderer])
def simple_html_view(request):
data = '<html><body><h1>Hello, world</h1></body></html>'
return Response(data)
media_type: text/htmlformat: htmlcharset: utf-8브라우저 API용 HTML로 데이터를 렌더링합니다.
media_type: text/html
format: api
charset: utf-8
데이터를 관리 화면처럼 HTML로 렌더링합니다.
media_type: text/html
format: admin
charset: utf-8
직렬화된 데이터를 HTML 폼으로 렌더링합니다.
media_type: text/html
format: form
charset: utf-8
HTML 멀티파트 폼 데이터를 렌더링합니다.
media_type: multipart/form-data; boundary=BoUnDaRyStRiNg
format: multipart
charset: utf-8
사용자 정의 렌더러를 구현하려면 BaseRenderer를 상속받고, .media_type와 .format 속성을 설정하며, .render(self, data, accepted_media_type=None, renderer_context=None) 메서드를 구현해야 합니다.
이 메서드는 HTTP 응답의 본문으로 사용될 바이트 문자열을 반환해야 합니다.
.render() 메서드에 전달되는 인자는 다음과 같습니다:
data
Response() 객체가 생성될 때 설정된 요청 데이터입니다.
accepted_media_type=None
선택 사항입니다. 제공된 경우, 이는 컨텐츠 협상 단계에서 결정된 수락된 미디어 타입입니다. 클라이언트의 Accept: 헤더에 따라 이 값은 렌더러의 media_type 속성보다 더 구체적일 수 있으며, 미디어 타입 파라미터를 포함할 수 있습니다. 예: "application/json; nested=true".
renderer_context=None
선택 사항입니다. 제공된 경우, 이는 뷰에서 제공하는 컨텍스트 정보를 담고 있는 딕셔너리입니다.
기본적으로 여기에 포함되는 키는 view, request, response, args, kwargs입니다.
다음은 data 매개변수를 응답 내용으로 반환하는 간단한 텍스트 렌더러 예시입니다:
from django.utils.encoding import smart_str
from rest_framework import renderers
class PlainTextRenderer(renderers.BaseRenderer):
media_type = 'text/plain'
format = 'txt'
def render(self, data, accepted_media_type=None, renderer_context=None):
return smart_str(data, encoding=self.charset)
기본적으로 렌더러 클래스는 UTF-8 인코딩을 사용한다고 가정합니다. 다른 인코딩을 사용하려면 렌더러에서 charset 속성을 설정하세요:
class PlainTextRenderer(renderers.BaseRenderer):
media_type = 'text/plain'
format = 'txt'
charset = 'iso-8859-1'
def render(self, data, accepted_media_type=None, renderer_context=None):
return data.encode(self.charset)
렌더러 클래스가 유니코드 문자열을 반환하면 Response 클래스가 이를 바이트 문자열로 변환하고, 렌더러의 charset 속성을 사용해 인코딩을 결정합니다.
만약 렌더러가 바이너리 데이터를 나타내는 바이트 문자열을 반환한다면 charset 값을 None으로 설정해야 합니다. 이렇게 하면 응답의 Content-Type 헤더에 charset 값이 설정되지 않습니다.
어떤 경우에는 render_style 속성을 'binary'로 설정해야 할 수도 있습니다. 이렇게 하면 브라우저 API가 이 바이너리 콘텐츠를 문자열로 표시하려 하지 않게 됩니다.
class JPEGRenderer(renderers.BaseRenderer):
media_type = 'image/jpeg'
format = 'jpg'
charset = None
render_style = 'binary'
def render(self, data, accepted_media_type=None, renderer_context=None):
return data
REST 프레임워크의 렌더러를 사용하면 매우 유연한 작업이 가능합니다. 몇 가지 예시를 들면:
Accept 헤더를 사용해 응답의 인코딩을 달리 설정경우에 따라 수락된 미디어 타입에 따라 다른 직렬화 스타일을 사용하고 싶을 수 있습니다. 이럴 때는 request.accepted_renderer를 사용해 응답에 사용될 렌더러를 확인할 수 있습니다.
예시:
@api_view(['GET'])
@renderer_classes([TemplateHTMLRenderer, JSONRenderer])
def list_users(request):
"""
시스템에 있는 사용자 목록을 HTML 또는 JSON 형식으로 반환하는 뷰.
"""
queryset = Users.objects.filter(active=True)
if request.accepted_renderer.format == 'html':
# TemplateHTMLRenderer는 컨텍스트 딕셔너리를 받으며,
# 추가적으로 'template_name'이 필요합니다.
# 직렬화가 필요하지 않습니다.
data = {'users': queryset}
return Response(data, template_name='list_users.html')
# JSONRenderer는 직렬화된 데이터가 필요합니다.
serializer = UserSerializer(instance=queryset)
data = serializer.data
return Response(data)
경우에 따라 특정 범위의 미디어 타입을 제공하고 싶을 수 있습니다. 이럴 때는 media_type = 'image/*'처럼 미디어 타입을 불명확하게 설정할 수 있습니다.
이렇게 설정할 경우, 응답을 반환할 때 content_type 속성을 사용해 미디어 타입을 명시적으로 지정해야 합니다. 예:
return Response(data, content_type='image/png')
많은 웹 API의 경우 간단한 JSON 응답과 하이퍼링크 관계만으로 충분할 수 있습니다. RESTful 디자인과 HATEOAS를 완전히 수용하려면 미디어 타입 설계 및 사용을 보다 면밀히 고려해야 합니다.
Roy Fielding의 말에 따르면, "REST API는 리소스 표현과 응용 프로그램 상태 전환을 나타내기 위해 사용되는 미디어 타입을 정의하는 데 대부분의 설명적 노력을 들여야 합니다."
GitHub의 application/vnd.github+json 미디어 타입 또는 Mike Amundsen의 IANA 승인 application/vnd.collection+json JSON 기반 하이퍼미디어와 같은 사용자 정의 미디어 타입의 좋은 예시들을 참조하세요.
렌더러는 일반적인 응답 또는 예외가 발생하여 처리된 응답을 동일하게 처리하는 것이 보통입니다. 예: Http404, PermissionDenied 예외, 또는 APIException 하위 클래스.
하지만 TemplateHTMLRenderer 또는 StaticHTMLRenderer를 사용하고 예외가 발생한 경우, 처리 방식이 조금 다르고, Django의 기본 에러 뷰 처리 방식과 유사합니다.
HTML 렌더러에서 발생한 예외는 다음의 순서에 따라 렌더링됩니다:
{status_code}.html이라는 이름의 템플릿을 로드하고 렌더링api_exception.html이라는 이름의 템플릿을 로드하고 렌더링템플릿은 RequestContext를 사용해 렌더링되며, 여기에는 status_code와 details 키가 포함됩니다.
참고: DEBUG=True로 설정된 경우, Django의 기본 traceback 에러 페이지가 표시됩니다.
다음의 서드파티 패키지도 사용할 수 있습니다.
REST framework YAML은 YAML 파싱 및 렌더링 지원을 제공합니다. 이 기능은 이전에 REST 프레임워크 패키지에 직접 포함되어 있었으나, 이제는 서드파티 패키지로 지원됩니다.
pip을 사용하여 설치합니다.
$ pip install djangorestframework-yaml
REST 프레임워크 설정을 다음과 같이 수정합니다:
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework_yaml.parsers.YAMLParser',
],
'DEFAULT_RENDERER_CLASSES': [
'rest_framework_yaml.renderers.YAMLRenderer',
],
}
REST Framework XML은 간단한 비공식 XML 형식을 제공합니다. 이 기능은 이전에 REST 프레임워크 패키지에 직접 포함되어 있었으나, 이제는 서드파티 패키지로 지원됩니다.
pip을 사용하여 설치합니다.
$ pip install djangorestframework-xml
REST 프레임워크 설정을 다음과 같이 수정합니다:
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
'rest_framework_xml.parsers.XMLParser',
],
'DEFAULT_RENDERER_CLASSES': [
'rest_framework_xml.renderers.XMLRenderer',
],
}
REST framework JSONP는 JSONP 렌더링 지원을 제공합니다. 이 기능은 이전에 REST 프레임워크 패키지에 직접 포함되어 있었으나, 이제는 서드파티 패키지로 지원됩니다.
크로스 도메인 AJAX 요청이 필요한 경우, JSONP 대신 CORS의 최신 방식을 사용하는 것이 일반적으로 권장됩니다. 자세한 내용은 CORS 문서를 참조하세요.
jsonp 방식은 브라우저 해킹 기법에 가깝기 때문에, GET 요청이 인증되지 않고 사용자 권한이 필요하지 않은 전역으로 읽을 수 있는 API 엔드포인트에만 적합합니다.
pip을 사용하여 설치합니다.
$ pip install djangorestframework-jsonp
REST 프레임워크 설정을 다음과 같이 수정합니다:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework_jsonp.renderers.JSONPRenderer',
],
}
MessagePack은 빠르고 효율적인 바이너리 직렬화 형식입니다. Juan Riaza가 유지 관리하는 djangorestframework-msgpack 패키지는 REST 프레임워크에서 MessagePack 렌더러와 파서를 지원합니다.
XLSX는 세계에서 가장 널리 사용되는 이진 스프레드시트 형식입니다. Tim Allen(Wharton School)은 OpenPyXL을 사용해 엔드포인트를 XLSX 스프레드시트로 렌더링하고 클라이언트가 이를 다운로드할 수 있게 해주는 drf-excel을 유지 관리합니다. 또한, 뷰 별로 스프레드시트를 스타일링할 수 있습니다.
pip을 사용하여 설치합니다.
$ pip install drf-excel
REST 프레임워크 설정을 다음과 같이 수정합니다:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
'drf_excel.renderers.XLSXRenderer',
],
}
파일이 파일명 없이 스트리밍되는 상황을 방지하기 위해 Content-Disposition 헤더를 재정의하는 믹스인을 사용해야 합니다. 파일명이 제공되지 않으면 기본적으로 export.xlsx로 설정됩니다. 예를 들어:
from rest_framework.viewsets import ReadOnlyModelViewSet
from drf_excel.mixins import XLSXFileMixin
from drf_excel.renderers import XLSXRenderer
from .models import MyExampleModel
from .serializers import MyExampleSerializer
class MyExampleViewSet(XLSXFileMixin, ReadOnlyModelViewSet):
queryset = MyExampleModel.objects.all()
serializer_class = MyExampleSerializer
renderer_classes = [XLSXRenderer]
filename = 'my_export.xlsx'
CSV(Comma-separated values)는 일반 텍스트로 된 표 형식 데이터로, 스프레드시트 응용 프로그램으로 쉽게 가져올 수 있습니다. Mjumbe Poe가 유지 관리하는 djangorestframework-csv 패키지는 REST 프레임워크에서 CSV 렌더러 지원을 제공합니다.
UltraJSON은 최적화된 C 기반 JSON 인코더로, JSON 렌더링 속도를 크게 향상시킬 수 있습니다. Adam Mertz가 유지 관리하는 drf_ujson2는 이제 유지 관리되지 않는 drf-ujson-renderer의 포크 버전으로, UJSON 패키지를 사용해 JSON 렌더링을 구현합니다.
djangorestframework-camel-case는 REST 프레임워크에서 CamelCase JSON 렌더러와 파서를 제공합니다. 이를 통해 직렬화기가 Python 스타일의 밑줄이 있는 필드 이름을 사용하면서도, API에서는 Javascript 스타일의 CamelCase 필드 이름으로 노출될 수 있습니다. Vitaly Babiy가 유지 관리합니다.
Django REST Pandas는 Pandas DataFrame API를 통한 추가 데이터 처리 및 출력 지원을 제공하는 직렬화기와 렌더러를 제공합니다. 이 패키지는 Pandas 스타일 CSV 파일, Excel 워크북(.xls 및 .xlsx), 그리고 기타 여러 형식에 대한 렌더러를 포함합니다. S. Andrew Sheppard가 wq 프로젝트의 일부로 유지 관리합니다.
Rest Framework Latex는 Laulatex를 사용해 PDF를 출력하는 렌더러를 제공합니다. Pebble(S/F Software)이 유지 관리합니다.