DRF 类视图 #
一、类视图概述 #
1.1 什么是类视图 #
类视图使用Python类来组织视图代码,通过方法名对应HTTP方法,实现更好的代码组织和复用。
text
函数视图 vs 类视图
┌─────────────────────────────────────┐
│ 函数视图 │
│ - 使用if判断HTTP方法 │
│ - 代码集中在一个函数 │
│ - 难以复用 │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 类视图 │
│ - 方法名对应HTTP方法 │
│ - 代码按方法组织 │
│ - 易于继承和复用 │
└─────────────────────────────────────┘
1.2 基本语法 #
python
from rest_framework.views import APIView
from rest_framework.response import Response
class HelloView(APIView):
def get(self, request):
return Response({'message': 'Hello, World!'})
def post(self, request):
return Response({'message': 'POST request'})
二、APIView基础 #
2.1 HTTP方法映射 #
python
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class ArticleView(APIView):
def get(self, request):
return Response({'method': 'GET'})
def post(self, request):
return Response({'method': 'POST'}, status=status.HTTP_201_CREATED)
def put(self, request):
return Response({'method': 'PUT'})
def patch(self, request):
return Response({'method': 'PATCH'})
def delete(self, request):
return Response(status=status.HTTP_204_NO_CONTENT)
2.2 URL配置 #
python
from django.urls import path
from .views import ArticleView
urlpatterns = [
path('articles/', ArticleView.as_view()),
]
2.3 带参数的视图 #
python
class ArticleDetailView(APIView):
def get(self, request, pk):
article = get_object_or_404(Article, pk=pk)
serializer = ArticleSerializer(article)
return Response(serializer.data)
urlpatterns = [
path('articles/<int:pk>/', ArticleDetailView.as_view()),
]
三、完整CRUD示例 #
3.1 列表视图 #
python
from rest_framework.views import APIView
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
class ArticleListView(APIView):
def get(self, request):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
def post(self, 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)
3.2 详情视图 #
python
class ArticleDetailView(APIView):
def get_object(self, pk):
return get_object_or_404(Article, pk=pk)
def get(self, request, pk):
article = self.get_object(pk)
serializer = ArticleSerializer(article)
return Response(serializer.data)
def put(self, request, pk):
article = self.get_object(pk)
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)
def patch(self, request, pk):
article = self.get_object(pk)
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)
def delete(self, request, pk):
article = self.get_object(pk)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
四、类属性和方法 #
4.1 类属性 #
python
class ArticleListView(APIView):
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticated]
authentication_classes = [TokenAuthentication]
def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs)
def get(self, request):
articles = Article.objects.all()
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)
4.2 重写方法 #
python
class ArticleListView(APIView):
def initial(self, request, *args, **kwargs):
super().initial(request, *args, **kwargs)
print('请求开始处理')
def finalize_response(self, request, response, *args, **kwargs):
response['X-Custom-Header'] = 'value'
return super().finalize_response(request, response, *args, **kwargs)
def handle_exception(self, exc):
response = super().handle_exception(exc)
response.data['error_code'] = 'CUSTOM_ERROR'
return response
def get(self, request):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
4.3 生命周期方法 #
python
class ArticleView(APIView):
def initial(self, request, *args, **kwargs):
print('1. initial - 请求预处理')
super().initial(request, *args, **kwargs)
def get(self, request):
print('2. get - 处理GET请求')
return Response({'message': 'ok'})
def finalize_response(self, request, response, *args, **kwargs):
print('3. finalize_response - 响应处理')
return super().finalize_response(request, response, *args, **kwargs)
def handle_exception(self, exc):
print('4. handle_exception - 异常处理')
return super().handle_exception(exc)
五、认证和权限 #
5.1 类级别设置 #
python
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication
class ArticleView(APIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({'user': request.user.username})
5.2 方法级别设置 #
python
from rest_framework.decorators import permission_classes
from rest_framework.permissions import IsAdminUser
class ArticleView(APIView):
def get(self, request):
return Response({'message': '公开访问'})
@permission_classes([IsAdminUser])
def post(self, request):
return Response({'message': '管理员专属'})
5.3 自定义权限检查 #
python
class ArticleDetailView(APIView):
def check_object_permission(self, request, obj):
if request.method in ['PUT', 'PATCH', 'DELETE']:
if obj.author != request.user:
self.permission_denied(request)
return True
def get(self, request, pk):
article = get_object_or_404(Article, pk=pk)
self.check_object_permission(request, article)
serializer = ArticleSerializer(article)
return Response(serializer.data)
六、分页实现 #
6.1 手动分页 #
python
from rest_framework.pagination import PageNumberPagination
class ArticleListView(APIView):
def get(self, request):
articles = Article.objects.all()
paginator = PageNumberPagination()
paginator.page_size = 10
result_page = paginator.paginate_queryset(articles, request)
serializer = ArticleSerializer(result_page, many=True)
return paginator.get_paginated_response(serializer.data)
6.2 自定义分页 #
python
class CustomPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
class ArticleListView(APIView):
def get(self, request):
articles = Article.objects.all()
paginator = CustomPagination()
result_page = paginator.paginate_queryset(articles, request)
serializer = ArticleSerializer(result_page, many=True)
return paginator.get_paginated_response(serializer.data)
七、过滤和搜索 #
7.1 查询参数过滤 #
python
class ArticleListView(APIView):
def get_queryset(self):
queryset = Article.objects.all()
category = self.request.query_params.get('category')
if category:
queryset = queryset.filter(category_id=category)
author = self.request.query_params.get('author')
if author:
queryset = queryset.filter(author__username=author)
is_published = self.request.query_params.get('is_published')
if is_published:
queryset = queryset.filter(is_published=is_published == 'true')
return queryset
def get(self, request):
articles = self.get_queryset()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
7.2 搜索功能 #
python
from django.db.models import Q
class ArticleSearchView(APIView):
def get(self, request):
keyword = request.query_params.get('keyword', '')
articles = Article.objects.all()
if keyword:
articles = articles.filter(
Q(title__icontains=keyword) |
Q(content__icontains=keyword) |
Q(author__username__icontains=keyword)
)
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
7.3 排序 #
python
class ArticleListView(APIView):
def get(self, request):
articles = Article.objects.all()
ordering = request.query_params.get('ordering', '-created_at')
if ordering:
articles = articles.order_by(ordering)
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
八、代码复用 #
8.1 基类视图 #
python
class BaseAPIView(APIView):
serializer_class = None
model_class = None
def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs)
def get_queryset(self):
return self.model_class.objects.all()
def get_object(self, pk):
return get_object_or_404(self.model_class, pk=pk)
class ArticleListView(BaseAPIView):
serializer_class = ArticleSerializer
model_class = Article
def get(self, request):
articles = self.get_queryset()
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)
8.2 Mixin类 #
python
class SerializerMixin:
serializer_class = None
def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs)
class PermissionMixin:
permission_classes = [IsAuthenticated]
def check_permissions(self, request):
for permission in self.permission_classes:
if not permission().has_permission(request, self):
self.permission_denied(request)
class ArticleListView(SerializerMixin, PermissionMixin, APIView):
serializer_class = ArticleSerializer
def get(self, request):
articles = Article.objects.all()
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)
8.3 组合视图 #
python
class CacheMixin:
cache_timeout = 60 * 5
def get_cached_data(self, key, queryset):
from django.core.cache import cache
data = cache.get(key)
if data is None:
data = list(queryset.values())
cache.set(key, data, self.cache_timeout)
return data
class ArticleListView(CacheMixin, APIView):
def get(self, request):
articles = self.get_cached_data('articles_all', Article.objects.all())
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
九、异常处理 #
9.1 统一异常处理 #
python
from rest_framework.exceptions import APIException
class ArticleView(APIView):
def handle_exception(self, exc):
if isinstance(exc, Article.DoesNotExist):
return Response(
{'error': '文章不存在'},
status=status.HTTP_404_NOT_FOUND
)
if isinstance(exc, PermissionDenied):
return Response(
{'error': '没有权限'},
status=status.HTTP_403_FORBIDDEN
)
return super().handle_exception(exc)
def get(self, request, pk):
article = Article.objects.get(pk=pk)
serializer = ArticleSerializer(article)
return Response(serializer.data)
9.2 自定义异常 #
python
class ArticleNotFound(APIException):
status_code = 404
default_detail = '文章不存在'
default_code = 'article_not_found'
class ArticleView(APIView):
def get(self, request, pk):
try:
article = Article.objects.get(pk=pk)
except Article.DoesNotExist:
raise ArticleNotFound()
serializer = ArticleSerializer(article)
return Response(serializer.data)
十、实用示例 #
10.1 用户资料视图 #
python
class UserProfileView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
serializer = UserSerializer(request.user)
return Response(serializer.data)
def put(self, request):
serializer = UserSerializer(request.user, 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)
10.2 统计视图 #
python
class ArticleStatsView(APIView):
def get(self, request, pk):
article = get_object_or_404(Article, pk=pk)
stats = {
'views': article.views,
'likes': article.likes.count(),
'comments': article.comments.count(),
'shares': article.shares.count()
}
return Response(stats)
10.3 批量操作视图 #
python
class ArticleBatchView(APIView):
permission_classes = [IsAdminUser]
def post(self, request):
action = request.data.get('action')
ids = request.data.get('ids', [])
articles = Article.objects.filter(id__in=ids)
if action == 'publish':
articles.update(is_published=True)
return Response({'message': f'已发布{articles.count()}篇文章'})
elif action == 'unpublish':
articles.update(is_published=False)
return Response({'message': f'已取消发布{articles.count()}篇文章'})
elif action == 'delete':
count = articles.count()
articles.delete()
return Response({'message': f'已删除{count}篇文章'})
return Response(
{'error': '无效的操作'},
status=status.HTTP_400_BAD_REQUEST
)
十一、类视图最佳实践 #
11.1 视图组织 #
python
class ArticleListView(APIView):
serializer_class = ArticleSerializer
def get(self, request):
articles = self.get_queryset()
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)
def post(self, request):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
def get_queryset(self):
return Article.objects.all()
def get_serializer(self, *args, **kwargs):
return self.serializer_class(*args, **kwargs)
11.2 方法拆分 #
python
class ArticleDetailView(APIView):
def get(self, request, pk):
article = self.get_object(pk)
self.check_permissions(request, article)
serializer = self.get_serializer(article)
return Response(serializer.data)
def put(self, request, pk):
article = self.get_object(pk)
self.check_permissions(request, article)
serializer = self.get_serializer(article, data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
def get_object(self, pk):
return get_object_or_404(Article, pk=pk)
def check_permissions(self, request, obj):
if obj.author != request.user:
self.permission_denied(request)
def get_serializer(self, *args, **kwargs):
return ArticleSerializer(*args, **kwargs)
十二、总结 #
本章学习了DRF类视图:
- APIView基础:HTTP方法映射
- 类属性和方法:配置和生命周期
- 认证和权限:类级别和方法级别设置
- 分页过滤:实现分页和搜索
- 代码复用:基类和Mixin模式
类视图提供了更好的代码组织方式,让我们继续学习通用视图!
最后更新:2026-03-28