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