DRF 响应对象 #
一、Response对象概述 #
1.1 什么是Response #
DRF的Response对象提供了灵活的API响应构建方式,支持多种内容类型和格式协商。
text
Response特点
├── 自动内容协商
├── 多种格式支持(JSON、HTML等)
├── 状态码管理
├── 响应头设置
└── 异常处理
1.2 基本用法 #
python
from rest_framework.response import Response
from rest_framework.views import APIView
class HelloView(APIView):
def get(self, request):
return Response({'message': 'Hello, World!'})
二、构建响应 #
2.1 基本响应 #
python
class ArticleView(APIView):
def get(self, request):
data = {
'id': 1,
'title': '文章标题',
'content': '文章内容'
}
return Response(data)
2.2 带状态码 #
python
from rest_framework import status
class ArticleView(APIView):
def post(self, request):
return Response(
{'message': '创建成功'},
status=status.HTTP_201_CREATED
)
def delete(self, request, pk):
return Response(status=status.HTTP_204_NO_CONTENT)
2.3 带响应头 #
python
class ArticleView(APIView):
def get(self, request):
return Response(
{'data': '...'},
headers={
'X-Custom-Header': 'value',
'X-Rate-Limit': '100'
}
)
2.4 完整参数 #
python
class ArticleView(APIView):
def get(self, request):
return Response(
data={'message': 'success'},
status=status.HTTP_200_OK,
headers={'X-Custom': 'header'},
content_type='application/json',
template_name=None,
exception=False
)
三、状态码 #
3.1 常用状态码 #
python
from rest_framework import status
class StatusView(APIView):
def get(self, request, code):
status_map = {
'ok': status.HTTP_200_OK,
'created': status.HTTP_201_CREATED,
'no_content': status.HTTP_204_NO_CONTENT,
'bad_request': status.HTTP_400_BAD_REQUEST,
'unauthorized': status.HTTP_401_UNAUTHORIZED,
'forbidden': status.HTTP_403_FORBIDDEN,
'not_found': status.HTTP_404_NOT_FOUND,
'error': status.HTTP_500_INTERNAL_SERVER_ERROR,
}
return Response(
{'code': code},
status=status_map.get(code, status.HTTP_200_OK)
)
3.2 状态码常量 #
| 常量 | 值 | 说明 |
|---|---|---|
| HTTP_200_OK | 200 | 成功 |
| HTTP_201_CREATED | 201 | 创建成功 |
| HTTP_204_NO_CONTENT | 204 | 无内容 |
| HTTP_400_BAD_REQUEST | 400 | 请求错误 |
| HTTP_401_UNAUTHORIZED | 401 | 未认证 |
| HTTP_403_FORBIDDEN | 403 | 禁止访问 |
| HTTP_404_NOT_FOUND | 404 | 未找到 |
| HTTP_500_INTERNAL_SERVER_ERROR | 500 | 服务器错误 |
四、响应格式 #
4.1 JSON响应 #
python
class JSONView(APIView):
def get(self, request):
return Response({
'string': 'text',
'number': 123,
'boolean': True,
'null': None,
'array': [1, 2, 3],
'object': {'key': 'value'}
})
4.2 统一响应格式 #
python
def success_response(data, message='操作成功', status_code=status.HTTP_200_OK):
return Response({
'success': True,
'message': message,
'data': data
}, status=status_code)
def error_response(message, errors=None, status_code=status.HTTP_400_BAD_REQUEST):
response_data = {
'success': False,
'message': message
}
if errors:
response_data['errors'] = errors
return Response(response_data, status=status_code)
class ArticleView(APIView):
def get(self, request):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return success_response(serializer.data)
def post(self, request):
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return success_response(
serializer.data,
message='创建成功',
status_code=status.HTTP_201_CREATED
)
return error_response('验证失败', serializer.errors)
4.3 分页响应 #
python
def paginated_response(queryset, request, serializer_class):
from rest_framework.pagination import PageNumberPagination
paginator = PageNumberPagination()
page = paginator.paginate_queryset(queryset, request)
serializer = serializer_class(page, many=True)
return Response({
'success': True,
'data': serializer.data,
'pagination': {
'count': paginator.page.paginator.count,
'page': paginator.page.number,
'page_size': paginator.page_size,
'total_pages': paginator.page.paginator.num_pages
}
})
五、响应头 #
5.1 自定义响应头 #
python
class ArticleView(APIView):
def get(self, request):
response = Response({'data': '...'})
response['X-Custom-Header'] = 'value'
response['X-Request-ID'] = '12345'
return response
5.2 缓存控制 #
python
class CacheView(APIView):
def get(self, request):
response = Response({'data': '...'})
response['Cache-Control'] = 'max-age=3600'
response['ETag'] = '"abc123"'
return response
5.3 CORS头 #
python
class CORSView(APIView):
def get(self, request):
response = Response({'data': '...'})
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE'
response['Access-Control-Allow-Headers'] = 'Content-Type, Authorization'
return response
六、内容协商 #
6.1 渲染器 #
python
from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
class ArticleView(APIView):
renderer_classes = [JSONRenderer, BrowsableAPIRenderer]
def get(self, request):
return Response({'data': '...'})
6.2 自定义渲染器 #
python
from rest_framework.renderers import BaseRenderer
class CSVRenderer(BaseRenderer):
media_type = 'text/csv'
format = 'csv'
def render(self, data, media_type=None, renderer_context=None):
import csv
from io import StringIO
if not isinstance(data, list):
data = [data]
output = StringIO()
writer = csv.DictWriter(output, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
return output.getvalue()
class ArticleView(APIView):
renderer_classes = [JSONRenderer, CSVRenderer]
def get(self, request):
articles = Article.objects.all().values('id', 'title', 'author')
return Response(list(articles))
七、异常响应 #
7.1 抛出异常 #
python
from rest_framework.exceptions import NotFound, PermissionDenied
class ArticleView(APIView):
def get(self, request, pk):
try:
article = Article.objects.get(pk=pk)
except Article.DoesNotExist:
raise NotFound('文章不存在')
if not article.is_published and request.user != article.author:
raise PermissionDenied('无权访问')
serializer = ArticleSerializer(article)
return Response(serializer.data)
7.2 自定义异常响应 #
python
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
response = exception_handler(exc, context)
if response is not None:
response.data = {
'success': False,
'error': {
'code': response.status_code,
'message': str(exc),
'details': response.data
}
}
return response
八、文件响应 #
8.1 文件下载 #
python
from django.http import FileResponse
import os
class FileDownloadView(APIView):
def get(self, request, filename):
file_path = os.path.join('/path/to/files', filename)
if not os.path.exists(file_path):
return Response({'error': '文件不存在'}, status=404)
response = FileResponse(
open(file_path, 'rb'),
as_attachment=True,
filename=filename
)
return response
8.2 流式响应 #
python
from django.http import StreamingHttpResponse
class StreamView(APIView):
def get(self, request):
def generate():
for i in range(100):
yield f'Line {i}\n'
response = StreamingHttpResponse(generate(), content_type='text/plain')
response['Content-Disposition'] = 'attachment; filename="data.txt"'
return response
九、实际应用示例 #
9.1 CRUD响应 #
python
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def list(self, request):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
def create(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(
serializer.data,
status=status.HTTP_201_CREATED,
headers=headers
)
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
return Response(serializer.data)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
9.2 批量操作响应 #
python
class BatchView(APIView):
def post(self, request):
ids = request.data.get('ids', [])
action = request.data.get('action')
results = {
'success': [],
'failed': []
}
for id in ids:
try:
article = Article.objects.get(pk=id)
if action == 'publish':
article.is_published = True
article.save()
results['success'].append(id)
elif action == 'delete':
article.delete()
results['success'].append(id)
except Article.DoesNotExist:
results['failed'].append({'id': id, 'reason': '不存在'})
return Response({
'message': f'成功处理 {len(results["success"])} 条记录',
'results': results
})
十、总结 #
本章学习了DRF Response对象:
- 基本响应:构建各种响应
- 状态码:HTTP状态码使用
- 响应格式:统一响应格式
- 响应头:自定义响应头
- 内容协商:渲染器和格式
- 异常响应:错误处理
让我们继续学习分页!
最后更新:2026-03-28