DRF 通用视图 #
一、通用视图概述 #
1.1 什么是通用视图 #
通用视图是DRF提供的预构建视图类,封装了常见的API模式,让你只需配置少量属性就能实现完整的CRUD功能。
text
视图层次结构
┌─────────────────────────────────────┐
│ APIView │
│ - 基础视图类 │
│ - 需要手动实现所有方法 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ GenericAPIView │
│ - 添加queryset和serializer支持 │
│ - 提供通用行为方法 │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ 通用视图 │
│ - ListAPIView │
│ - CreateAPIView │
│ - RetrieveAPIView │
│ - UpdateAPIView │
│ - DestroyAPIView │
│ - ListCreateAPIView │
│ - RetrieveUpdateAPIView │
│ - RetrieveDestroyAPIView │
│ - RetrieveUpdateDestroyAPIView │
└─────────────────────────────────────┘
1.2 核心属性 #
| 属性 | 说明 |
|---|---|
| queryset | 查询集 |
| serializer_class | 序列化器类 |
| lookup_field | 查找字段(默认pk) |
| lookup_url_kwarg | URL参数名 |
| pagination_class | 分页类 |
| filter_backends | 过滤后端 |
| permission_classes | 权限类 |
| authentication_classes | 认证类 |
二、GenericAPIView #
2.1 基本用法 #
python
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from .models import Article
from .serializers import ArticleSerializer
class ArticleListView(GenericAPIView):
queryset = Article.objects.all()
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)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(serializer.errors, status=400)
2.2 提供的方法 #
python
class ArticleDetailView(GenericAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'pk'
def get(self, request, pk):
article = self.get_object()
serializer = self.get_serializer(article)
return Response(serializer.data)
| 方法 | 说明 |
|---|---|
| get_queryset() | 获取查询集 |
| get_object() | 获取单个对象 |
| get_serializer() | 获取序列化器 |
| get_serializer_context() | 获取序列化器上下文 |
| filter_queryset() | 过滤查询集 |
| paginate_queryset() | 分页查询集 |
三、单一操作视图 #
3.1 ListAPIView #
只读列表视图:
python
from rest_framework.generics import ListAPIView
class ArticleListView(ListAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
3.2 CreateAPIView #
只写创建视图:
python
from rest_framework.generics import CreateAPIView
class ArticleCreateView(CreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
3.3 RetrieveAPIView #
只读详情视图:
python
from rest_framework.generics import RetrieveAPIView
class ArticleDetailView(RetrieveAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
lookup_field = 'pk'
3.4 UpdateAPIView #
更新视图:
python
from rest_framework.generics import UpdateAPIView
class ArticleUpdateView(UpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
3.5 DestroyAPIView #
删除视图:
python
from rest_framework.generics import DestroyAPIView
class ArticleDeleteView(DestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
四、组合视图 #
4.1 ListCreateAPIView #
列表和创建组合:
python
from rest_framework.generics import ListCreateAPIView
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def perform_create(self, serializer):
serializer.save(author=self.request.user)
4.2 RetrieveUpdateAPIView #
详情和更新组合:
python
from rest_framework.generics import RetrieveUpdateAPIView
class ArticleDetailView(RetrieveUpdateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticated]
4.3 RetrieveDestroyAPIView #
详情和删除组合:
python
from rest_framework.generics import RetrieveDestroyAPIView
class ArticleDetailView(RetrieveDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
4.4 RetrieveUpdateDestroyAPIView #
完整的详情视图:
python
from rest_framework.generics import RetrieveUpdateDestroyAPIView
class ArticleDetailView(RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticated]
def perform_update(self, serializer):
serializer.save(updated_by=self.request.user)
def perform_destroy(self, instance):
instance.is_deleted = True
instance.save()
五、视图类型对照表 #
| 视图类 | GET | POST | PUT | PATCH | DELETE |
|---|---|---|---|---|---|
| ListAPIView | 列表 | - | - | - | - |
| CreateAPIView | - | 创建 | - | - | - |
| RetrieveAPIView | 详情 | - | - | - | - |
| UpdateAPIView | - | - | 更新 | 部分更新 | - |
| DestroyAPIView | - | - | - | - | 删除 |
| ListCreateAPIView | 列表 | 创建 | - | - | - |
| RetrieveUpdateAPIView | 详情 | - | 更新 | 部分更新 | - |
| RetrieveDestroyAPIView | 详情 | - | - | - | 删除 |
| RetrieveUpdateDestroyAPIView | 详情 | - | 更新 | 部分更新 | 删除 |
六、自定义行为 #
6.1 重写get_queryset #
python
class ArticleListView(ListCreateAPIView):
serializer_class = ArticleSerializer
def get_queryset(self):
queryset = Article.objects.all()
category = self.request.query_params.get('category')
if category:
queryset = queryset.filter(category_id=category)
return queryset
6.2 重写get_serializer_class #
python
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
def get_serializer_class(self):
if self.request.method == 'POST':
return ArticleCreateSerializer
return ArticleSerializer
6.3 重写perform_create #
python
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def perform_create(self, serializer):
serializer.save(
author=self.request.user,
ip_address=self.request.META.get('REMOTE_ADDR')
)
6.4 重写perform_update #
python
class ArticleDetailView(RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def perform_update(self, serializer):
serializer.save(
updated_by=self.request.user,
updated_at=timezone.now()
)
6.5 重写perform_destroy #
python
class ArticleDetailView(RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def perform_destroy(self, instance):
instance.is_deleted = True
instance.deleted_at = timezone.now()
instance.save()
七、过滤和搜索 #
7.1 基本过滤 #
python
from django_filters.rest_framework import DjangoFilterBackend
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['category', 'author', 'is_published']
7.2 搜索过滤 #
python
from rest_framework.filters import SearchFilter
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [SearchFilter]
search_fields = ['title', 'content', 'author__username']
7.3 排序过滤 #
python
from rest_framework.filters import OrderingFilter
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [OrderingFilter]
ordering_fields = ['created_at', 'views', 'title']
ordering = ['-created_at']
7.4 组合过滤 #
python
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['category', 'is_published']
search_fields = ['title', 'content']
ordering_fields = ['created_at', 'views']
ordering = ['-created_at']
八、分页配置 #
8.1 类级别分页 #
python
from rest_framework.pagination import PageNumberPagination
class ArticlePagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
pagination_class = ArticlePagination
8.2 禁用分页 #
python
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
pagination_class = None
九、权限控制 #
9.1 类级别权限 #
python
from rest_framework.permissions import IsAuthenticated, IsAdminUser
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticated]
class AdminArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAdminUser]
9.2 动态权限 #
python
class ArticleDetailView(RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get_permissions(self):
if self.request.method in ['PUT', 'PATCH', 'DELETE']:
return [IsAuthenticated(), IsOwner()]
return [IsAuthenticated()]
9.3 对象级别权限 #
python
from rest_framework.permissions import IsAuthenticatedOrReadOnly
class ArticleDetailView(RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
def check_object_permissions(self, request, obj):
if request.method in ['PUT', 'PATCH', 'DELETE']:
if obj.author != request.user:
self.permission_denied(request)
super().check_object_permissions(request, obj)
十、实际应用示例 #
10.1 文章API #
python
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.select_related('author', 'category').prefetch_related('tags')
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['category', 'is_published']
search_fields = ['title', 'content']
ordering_fields = ['created_at', 'views']
ordering = ['-created_at']
def perform_create(self, serializer):
serializer.save(author=self.request.user)
class ArticleDetailView(RetrieveUpdateDestroyAPIView):
queryset = Article.objects.select_related('author', 'category').prefetch_related('tags')
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
lookup_field = 'slug'
def perform_update(self, serializer):
serializer.save(updated_by=self.request.user)
def perform_destroy(self, instance):
if instance.author != self.request.user:
self.permission_denied(self.request)
instance.delete()
10.2 用户API #
python
class UserListView(ListCreateAPIView):
queryset = User.objects.all()
permission_classes = [IsAdminUser]
filter_backends = [SearchFilter]
search_fields = ['username', 'email']
def get_serializer_class(self):
if self.request.method == 'POST':
return UserCreateSerializer
return UserSerializer
class UserDetailView(RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
permission_classes = [IsAuthenticated]
def get_serializer_class(self):
if self.request.method in ['PUT', 'PATCH']:
return UserUpdateSerializer
return UserSerializer
def get_object(self):
if self.kwargs.get('pk') == 'me':
return self.request.user
return super().get_object()
10.3 评论API #
python
class CommentListView(ListCreateAPIView):
serializer_class = CommentSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
def get_queryset(self):
article_id = self.kwargs.get('article_id')
return Comment.objects.filter(article_id=article_id)
def perform_create(self, serializer):
article_id = self.kwargs.get('article_id')
serializer.save(
article_id=article_id,
author=self.request.user
)
十一、URL配置 #
11.1 基本配置 #
python
from django.urls import path
from .views import ArticleListView, ArticleDetailView
urlpatterns = [
path('articles/', ArticleListView.as_view(), name='article-list'),
path('articles/<int:pk>/', ArticleDetailView.as_view(), name='article-detail'),
]
11.2 嵌套资源 #
python
urlpatterns = [
path('articles/', ArticleListView.as_view(), name='article-list'),
path('articles/<int:pk>/', ArticleDetailView.as_view(), name='article-detail'),
path('articles/<int:article_id>/comments/', CommentListView.as_view(), name='article-comments'),
]
十二、最佳实践 #
12.1 查询优化 #
python
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.select_related(
'author', 'category'
).prefetch_related(
'tags', 'comments'
).only(
'id', 'title', 'summary', 'author__username',
'category__name', 'created_at'
)
serializer_class = ArticleSerializer
12.2 分离序列化器 #
python
class ArticleListView(ListCreateAPIView):
queryset = Article.objects.all()
def get_serializer_class(self):
if self.action == 'create':
return ArticleCreateSerializer
return ArticleListSerializer
12.3 条件过滤 #
python
class ArticleListView(ListCreateAPIView):
serializer_class = ArticleSerializer
def get_queryset(self):
queryset = Article.objects.all()
if not self.request.user.is_staff:
queryset = queryset.filter(is_published=True)
return queryset
十三、总结 #
本章学习了DRF通用视图:
- GenericAPIView:基础通用视图
- 单一操作视图:ListAPIView、CreateAPIView等
- 组合视图:ListCreateAPIView等
- 自定义行为:重写方法实现自定义逻辑
- 过滤搜索:集成过滤和搜索功能
通用视图大幅提升了开发效率,让我们继续学习视图集!
最后更新:2026-03-28