DRF 函数视图 #

一、函数视图概述 #

1.1 什么是函数视图 #

函数视图是DRF中最基础的视图形式,使用Python函数处理HTTP请求,通过装饰器声明支持的HTTP方法。

text
函数视图特点
├── 简单直观:类似Django传统视图
├── 灵活控制:完全控制请求处理流程
├── 适合简单API:快速实现简单接口
└── 代码集中:所有逻辑在一个函数中

1.2 基本语法 #

python
from rest_framework.decorators import api_view
from rest_framework.response import Response

@api_view(['GET'])
def hello_world(request):
    return Response({'message': 'Hello, World!'})

二、@api_view装饰器 #

2.1 基本用法 #

python
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

@api_view(['GET', 'POST'])
def article_list(request):
    if request.method == 'GET':
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)
    
    elif request.method == 'POST':
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

2.2 支持的HTTP方法 #

python
@api_view(['GET'])           # 只支持GET
@api_view(['POST'])          # 只支持POST
@api_view(['GET', 'POST'])   # 支持GET和POST
@api_view(['PUT', 'PATCH'])  # 支持PUT和PATCH
@api_view(['DELETE'])        # 只支持DELETE
@api_view(['GET', 'POST', 'PUT', 'PATCH', 'DELETE'])  # 支持所有方法

2.3 HTTP方法映射 #

HTTP方法 用途 状态码
GET 获取资源 200 OK
POST 创建资源 201 Created
PUT 完整更新资源 200 OK
PATCH 部分更新资源 200 OK
DELETE 删除资源 204 No Content

三、请求处理 #

3.1 Request对象 #

DRF扩展了Django的HttpRequest,提供了更多功能:

python
@api_view(['GET', 'POST'])
def example_view(request):
    print(request.method)        # HTTP方法
    print(request.data)          # 解析后的请求体
    print(request.query_params)  # 查询参数
    print(request.user)          # 当前用户
    print(request.auth)          # 认证信息
    print(request.headers)       # 请求头
    
    return Response({'status': 'ok'})

3.2 获取请求参数 #

python
@api_view(['GET'])
def article_detail(request, pk):
    article = get_object_or_404(Article, pk=pk)
    serializer = ArticleSerializer(article)
    return Response(serializer.data)

@api_view(['GET'])
def article_search(request):
    keyword = request.query_params.get('keyword', '')
    category = request.query_params.get('category')
    
    articles = Article.objects.all()
    if keyword:
        articles = articles.filter(title__icontains=keyword)
    if category:
        articles = articles.filter(category_id=category)
    
    serializer = ArticleSerializer(articles, many=True)
    return Response(serializer.data)

3.3 获取请求体数据 #

python
@api_view(['POST'])
def create_article(request):
    title = request.data.get('title')
    content = request.data.get('content')
    author = request.data.get('author')
    
    if not title:
        return Response(
            {'error': '标题不能为空'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    article = Article.objects.create(
        title=title,
        content=content,
        author=author
    )
    
    serializer = ArticleSerializer(article)
    return Response(serializer.data, status=status.HTTP_201_CREATED)

四、Response对象 #

4.1 基本响应 #

python
from rest_framework.response import Response

@api_view(['GET'])
def simple_response(request):
    return Response({'message': '成功'})

@api_view(['GET'])
def response_with_status(request):
    return Response(
        {'message': '创建成功'},
        status=status.HTTP_201_CREATED
    )

@api_view(['GET'])
def response_with_headers(request):
    return Response(
        {'message': '成功'},
        headers={'X-Custom-Header': 'value'}
    )

4.2 常用状态码 #

python
from rest_framework import status

@api_view(['GET'])
def get_data(request):
    return Response(data, status=status.HTTP_200_OK)

@api_view(['POST'])
def create_data(request):
    return Response(data, status=status.HTTP_201_CREATED)

@api_view(['GET'])
def not_found(request):
    return Response(
        {'error': '资源不存在'},
        status=status.HTTP_404_NOT_FOUND
    )

@api_view(['POST'])
def bad_request(request):
    return Response(
        {'error': '参数错误'},
        status=status.HTTP_400_BAD_REQUEST
    )

@api_view(['DELETE'])
def delete_data(request, pk):
    return Response(status=status.HTTP_204_NO_CONTENT)

4.3 状态码常量 #

常量 说明
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 服务器错误

五、完整CRUD示例 #

5.1 列表和创建 #

python
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from .models import Article
from .serializers import ArticleSerializer

@api_view(['GET', 'POST'])
def article_list(request):
    if request.method == 'GET':
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)
    
    elif request.method == 'POST':
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

5.2 详情、更新和删除 #

python
@api_view(['GET', 'PUT', 'PATCH', 'DELETE'])
def article_detail(request, pk):
    article = get_object_or_404(Article, pk=pk)
    
    if request.method == 'GET':
        serializer = ArticleSerializer(article)
        return Response(serializer.data)
    
    elif request.method == 'PUT':
        serializer = ArticleSerializer(article, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    elif request.method == 'PATCH':
        serializer = ArticleSerializer(article, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    elif request.method == 'DELETE':
        article.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

六、URL配置 #

6.1 配置路由 #

python
from django.urls import path
from . import views

urlpatterns = [
    path('articles/', views.article_list, name='article-list'),
    path('articles/<int:pk>/', views.article_detail, name='article-detail'),
]

6.2 带参数的路由 #

python
urlpatterns = [
    path('articles/', views.article_list, name='article-list'),
    path('articles/<int:pk>/', views.article_detail, name='article-detail'),
    path('categories/<int:category_id>/articles/', views.category_articles, name='category-articles'),
    path('users/<str:username>/articles/', views.user_articles, name='user-articles'),
]

6.3 视图函数 #

python
@api_view(['GET'])
def category_articles(request, category_id):
    articles = Article.objects.filter(category_id=category_id)
    serializer = ArticleSerializer(articles, many=True)
    return Response(serializer.data)

@api_view(['GET'])
def user_articles(request, username):
    articles = Article.objects.filter(author__username=username)
    serializer = ArticleSerializer(articles, many=True)
    return Response(serializer.data)

七、装饰器组合 #

7.1 authentication_classes #

python
from rest_framework.decorators import api_view, authentication_classes
from rest_framework.authentication import TokenAuthentication, SessionAuthentication

@api_view(['GET'])
@authentication_classes([TokenAuthentication, SessionAuthentication])
def protected_view(request):
    return Response({'message': '认证成功'})

7.2 permission_classes #

python
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated, IsAdminUser

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def user_profile(request):
    serializer = UserSerializer(request.user)
    return Response(serializer.data)

@api_view(['GET'])
@permission_classes([IsAdminUser])
def admin_only(request):
    return Response({'message': '管理员专属'})

7.3 throttle_classes #

python
from rest_framework.decorators import api_view, throttle_classes
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle

class OncePerDayThrottle(AnonRateThrottle):
    rate = '1/day'

@api_view(['GET'])
@throttle_classes([OncePerDayThrottle])
def limited_access(request):
    return Response({'message': '每天只能访问一次'})

7.4 schema装饰器 #

python
from rest_framework.decorators import api_view, schema
from rest_framework.schemas import AutoSchema

class CustomSchema(AutoSchema):
    def get_description(self, path, method):
        return '自定义API描述'

@api_view(['GET'])
@schema(CustomSchema())
def custom_schema_view(request):
    return Response({'message': 'ok'})

7.5 组合使用 #

python
from rest_framework.decorators import (
    api_view, authentication_classes, permission_classes, throttle_classes
)
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.throttling import UserRateThrottle

@api_view(['GET', 'POST'])
@authentication_classes([TokenAuthentication])
@permission_classes([IsAuthenticated])
@throttle_classes([UserRateThrottle])
def protected_article_list(request):
    if request.method == 'GET':
        articles = Article.objects.all()
        serializer = ArticleSerializer(articles, many=True)
        return Response(serializer.data)
    
    elif request.method == 'POST':
        serializer = ArticleSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save(author=request.user)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

八、错误处理 #

8.1 基本错误处理 #

python
from django.core.exceptions import ObjectDoesNotExist

@api_view(['GET'])
def article_detail(request, pk):
    try:
        article = Article.objects.get(pk=pk)
        serializer = ArticleSerializer(article)
        return Response(serializer.data)
    except ObjectDoesNotExist:
        return Response(
            {'error': '文章不存在'},
            status=status.HTTP_404_NOT_FOUND
        )

8.2 使用get_object_or_404 #

python
from django.shortcuts import get_object_or_404

@api_view(['GET'])
def article_detail(request, pk):
    article = get_object_or_404(Article, pk=pk)
    serializer = ArticleSerializer(article)
    return Response(serializer.data)

8.3 自定义异常处理 #

python
from rest_framework.exceptions import APIException

class ArticleNotFound(APIException):
    status_code = 404
    default_detail = '文章不存在'
    default_code = 'article_not_found'

@api_view(['GET'])
def article_detail(request, pk):
    try:
        article = Article.objects.get(pk=pk)
    except Article.DoesNotExist:
        raise ArticleNotFound()
    
    serializer = ArticleSerializer(article)
    return Response(serializer.data)

8.4 验证错误 #

python
from rest_framework.exceptions import ValidationError

@api_view(['POST'])
def create_article(request):
    if not request.data.get('title'):
        raise ValidationError({'title': '标题不能为空'})
    
    serializer = ArticleSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

九、实用示例 #

9.1 搜索API #

python
@api_view(['GET'])
def article_search(request):
    keyword = request.query_params.get('keyword', '')
    category = request.query_params.get('category')
    page = int(request.query_params.get('page', 1))
    page_size = int(request.query_params.get('page_size', 10))
    
    articles = Article.objects.all()
    
    if keyword:
        articles = articles.filter(
            models.Q(title__icontains=keyword) |
            models.Q(content__icontains=keyword)
        )
    
    if category:
        articles = articles.filter(category_id=category)
    
    total = articles.count()
    start = (page - 1) * page_size
    end = start + page_size
    articles = articles[start:end]
    
    serializer = ArticleSerializer(articles, many=True)
    
    return Response({
        'total': total,
        'page': page,
        'page_size': page_size,
        'results': serializer.data
    })

9.2 批量操作 #

python
@api_view(['POST'])
def batch_delete(request):
    ids = request.data.get('ids', [])
    
    if not ids:
        return Response(
            {'error': '请提供要删除的ID列表'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    deleted, _ = Article.objects.filter(id__in=ids).delete()
    
    return Response({
        'message': f'成功删除{deleted}条记录'
    })

9.3 文件上传 #

python
@api_view(['POST'])
def upload_file(request):
    file = request.FILES.get('file')
    
    if not file:
        return Response(
            {'error': '请选择文件'},
            status=status.HTTP_400_BAD_REQUEST
        )
    
    import os
    from django.conf import settings
    
    file_path = os.path.join(settings.MEDIA_ROOT, 'uploads', file.name)
    
    with open(file_path, 'wb+') as destination:
        for chunk in file.chunks():
            destination.write(chunk)
    
    return Response({
        'message': '上传成功',
        'file_name': file.name,
        'file_size': file.size
    })

十、函数视图最佳实践 #

10.1 代码组织 #

python
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404
from .models import Article
from .serializers import ArticleSerializer

@api_view(['GET', 'POST'])
def article_list(request):
    if request.method == 'GET':
        return _list_articles(request)
    return _create_article(request)

def _list_articles(request):
    articles = Article.objects.all()
    serializer = ArticleSerializer(articles, many=True)
    return Response(serializer.data)

def _create_article(request):
    serializer = ArticleSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

10.2 使用序列化器验证 #

python
@api_view(['POST'])
def create_article(request):
    serializer = ArticleSerializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    return Response(serializer.data, status=status.HTTP_201_CREATED)

10.3 统一响应格式 #

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)

@api_view(['GET'])
def article_list(request):
    articles = Article.objects.all()
    serializer = ArticleSerializer(articles, many=True)
    return success_response(serializer.data)

@api_view(['POST'])
def create_article(request):
    serializer = ArticleSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save()
        return success_response(serializer.data, '创建成功', status.HTTP_201_CREATED)
    return error_response('验证失败', serializer.errors)

十一、总结 #

本章学习了DRF函数视图:

  • @api_view装饰器:声明支持的HTTP方法
  • Request对象:处理请求数据
  • Response对象:构建响应
  • 装饰器组合:认证、权限、限流
  • 错误处理:异常处理和验证

函数视图适合简单的API场景,让我们继续学习类视图!

最后更新:2026-03-28