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