Django类视图CBV

[复制链接]
发表于 2026-1-14 06:28:19 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
类视图(Class-Based Views,简称 CBV)是 Django 中构建视图的一种强盛且机动的方式。相比于函数视图(Function-Based Views,FBV),类视图提供了更好的可复用性和可扩展性,尤其在处理惩罚复杂逻辑和大型项目时尤为有用。本文将具体解说 Django 中的类视图,包罗内置类视图、自界说类视图的计划,以及如安在 Django REST framework 中使用类视图。


1. 类视图简介

1.1 函数视图 vs 类视图

函数视图(FBV) 是 Django 中最根本的视图范例,通过界说一个函数来处理惩罚哀求并返反相应。比方:
  1. # myapp/views.py
  2. from django.http import HttpResponse
  3. def hello_world(request):
  4.     return HttpResponse("Hello, World!")
复制代码
类视图(CBV) 则使用类来界说视图,通过继承 Django 提供的基类,实现差别的 HTTP 方法(如 GET、POST 等)。比方:
  1. # myapp/views.py
  2. from django.views import View
  3. from django.http import HttpResponse
  4. class HelloWorldView(View):
  5.     def get(self, request):
  6.         return HttpResponse("Hello, World!")
复制代码
1.2 上风



  • 可复用性:通过继承和组合,可以轻松复用代码。
  • 构造性:将相干逻辑封装在一个类中,使代码布局更清晰。
  • 扩展性:便于添加新的功能或修改现有功能。
  • 内置功能丰富:Django 提供了很多内置的通用类视图,简化常见使命。
2. Django 内置类视图

Django 提供了很多内置的类视图,涵盖了常见的使用,如展示模板、处理惩罚表单、实验 CRUD 使用等。以下是一些常用的内置类视图及其用法。
2.1 底子类视图

2.1.1 View

django.views.View 是全部类视图的基类。它提供了处理惩罚差别 HTTP 方法的根本布局。
  1. # myapp/views.py
  2. from django.views import View
  3. from django.http import HttpResponse
  4. class MyView(View):
  5.     def get(self, request):
  6.         return HttpResponse('GET 请求')
  7.     def post(self, request):
  8.         return HttpResponse('POST 请求')
复制代码
2.1.2 TemplateView

用于渲染模板并返反相应,实用于简单的页面展示。
  1. # myapp/views.py
  2. from django.views.generic import TemplateView
  3. class HomePageView(TemplateView):
  4.     template_name = 'home.html'
复制代码
  1. # myapp/urls.py
  2. from django.urls import path
  3. from .views import HomePageView
  4. urlpatterns = [
  5.     path('', HomePageView.as_view(), name='home'),
  6. ]
复制代码
2.1.3 RedirectView

用于重定向到其他 URL。
  1. # myapp/views.py
  2. from django.views.generic import RedirectView
  3. class OldHomePageRedirect(RedirectView):
  4.     url = '/new-home/'
复制代码
  1. # myapp/urls.py
  2. from django.urls import path
  3. from .views import OldHomePageRedirect
  4. urlpatterns = [
  5.     path('old-home/', OldHomePageRedirect.as_view(), name='old_home'),
  6. ]
复制代码
2.2 通用类视图(Generic Views)

通用类视图提供了更高级别的抽象,实用于常见的数据库使用,如体现列表、创建、更新和删除对象。
2.2.1 ListView

体现对象的列表。
  1. # myapp/views.py
  2. from django.views.generic import ListView
  3. from .models import Post
  4. class PostListView(ListView):
  5.     model = Post
  6.     template_name = 'post_list.html'
  7.     context_object_name = 'posts'
  8.     ordering = ['-created_at']
复制代码
2.2.2 DetailView

体现单个对象的具体信息。
  1. # myapp/views.py
  2. from django.views.generic import DetailView
  3. from .models import Post
  4. class PostDetailView(DetailView):
  5.     model = Post
  6.     template_name = 'post_detail.html'
复制代码
2.2.3 CreateView

创建新对象的表单视图。
  1. # myapp/views.py
  2. from django.views.generic import CreateView
  3. from .models import Post
  4. from django.urls import reverse_lazy
  5. class PostCreateView(CreateView):
  6.     model = Post
  7.     fields = ['title', 'content']
  8.     template_name = 'post_form.html'
  9.     success_url = reverse_lazy('post_list')
复制代码
2.2.4 UpdateView

更新现有对象的表单视图。
  1. # myapp/views.py
  2. from django.views.generic import UpdateView
  3. from .models import Post
  4. from django.urls import reverse_lazy
  5. class PostUpdateView(UpdateView):
  6.     model = Post
  7.     fields = ['title', 'content']
  8.     template_name = 'post_form.html'
  9.     success_url = reverse_lazy('post_list')
复制代码
2.2.5 DeleteView

删除对象简直认视图。
  1. # myapp/views.py
  2. from django.views.generic import DeleteView
  3. from .models import Post
  4. from django.urls import reverse_lazy
  5. class PostDeleteView(DeleteView):
  6.     model = Post
  7.     template_name = 'post_confirm_delete.html'
  8.     success_url = reverse_lazy('post_list')
复制代码
2.3 组合使用通用视图

可以通过组合多个通用视图,快速实现复杂的功能。比方,使用 ListView 和 DetailView 实现一个博客的文章列表和具体页面。
  1. # myapp/views.py
  2. from django.views.generic import ListView, DetailView
  3. from .models import Post
  4. class PostListView(ListView):
  5.     model = Post
  6.     template_name = 'post_list.html'
  7.     context_object_name = 'posts'
  8.     ordering = ['-created_at']
  9. class PostDetailView(DetailView):
  10.     model = Post
  11.     template_name = 'post_detail.html'
复制代码
  1. # myapp/urls.py
  2. from django.urls import path
  3. from .views import PostListView, PostDetailView
  4. urlpatterns = [
  5.     path('', PostListView.as_view(), name='post_list'),
  6.     path('post/<int:pk>/', PostDetailView.as_view(), name='post_detail'),
  7. ]
复制代码
3. 自界说类视图

固然 Django 提供了很多内置类视图,但在实际开发中,每每须要根据具体需求自界说类视图。下面先容怎样计划和实现自界说类视图。
3.1 计划思绪


  • 继承得意当的基类:根据须要继承自 View、TemplateView、ListView 等。
  • 界说须要的方法:如 get、post 等,大概使用类视图提供的钩子方法(如 get_context_data)。
  • 封装通用逻辑:通过方法的重写或添加辅助方法,封装通用逻辑,进步代码复用性。
3.2 示例:自界说搜刮视图

假设我们盼望在 PostListView 中添加搜刮功能,根据标题关键字过滤文章。
  1. # myapp/views.py
  2. from django.views.generic import ListView
  3. from .models import Post
  4. from django.db.models import Q
  5. class PostListView(ListView):
  6.     model = Post
  7.     template_name = 'post_list.html'
  8.     context_object_name = 'posts'
  9.     ordering = ['-created_at']
  10.     paginate_by = 10
  11.     def get_queryset(self):
  12.         queryset = super().get_queryset()
  13.         query = self.request.GET.get('q')
  14.         if query:
  15.             queryset = queryset.filter(Q(title__icontains=query) | Q(content__icontains=query))
  16.         return queryset
  17.     def get_context_data(self, **kwargs):
  18.         context = super().get_context_data(**kwargs)
  19.         context['q'] = self.request.GET.get('q', '')
  20.         return context
复制代码
  1. <!-- templates/post_list.html -->
  2. <form method="get">
  3.     <input type="text" name="q" placeholder="搜索..." value="{{ q }}">
  4.     <button type="submit">搜索</button>
  5. </form>
  6. <ul>
  7.     {% for post in posts %}
  8.         <li><a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a></li>
  9.     {% endfor %}
  10. </ul>
  11. {% if is_paginated %}
  12.     <div>
  13.         {% if page_obj.has_previous %}
  14.             <a href="?q={{ q }}&page={{ page_obj.previous_page_number }}">上一页</a>
  15.         {% endif %}
  16.         <span>第 {{ page_obj.number }} 页,共 {{ page_obj.paginator.num_pages }} 页</span>
  17.         {% if page_obj.has_next %}
  18.             <a href="?q={{ q }}&page={{ page_obj.next_page_number }}">下一页</a>
  19.         {% endif %}
  20.     </div>
  21. {% endif %}
复制代码
3.3 使用 Mixins 加强类视图

Mixin 是一种通过多继承来复用代码的计划模式。在 Django 类视图中,Mixins 可以用来添加额外的功能,而不须要修改现有的视图类。
示例:添加登录验证

假设我们盼望某些视图只能由登任命户访问,可以创建一个 Mixin 来实现这一功能。
  1. # myapp/mixins.py
  2. from django.contrib.auth.mixins import LoginRequiredMixin
  3. # Django 已经提供了 LoginRequiredMixin,无需自定义
  4. # 如果需要自定义,可以这样做:
  5. from django.contrib.auth.decorators import login_required
  6. from django.utils.decorators import method_decorator
  7. class CustomLoginRequiredMixin:
  8.     @method_decorator(login_required)
  9.     def dispatch(self, *args, **kwargs):
  10.         return super().dispatch(*args, **kwargs)
复制代码
然后在视图中使用该 Mixin:
  1. # myapp/views.py
  2. from django.views.generic import ListView
  3. from .models import Post
  4. from .mixins import CustomLoginRequiredMixin  # 如果使用自定义的 Mixin
  5. from django.contrib.auth.mixins import LoginRequiredMixin  # 推荐使用 Django 内置的
  6. class ProtectedPostListView(LoginRequiredMixin, ListView):
  7.     model = Post
  8.     template_name = 'protected_post_list.html'
  9.     context_object_name = 'posts'
  10.     login_url = '/login/'
复制代码
3.4 自界说表单处理惩罚

假设我们须要一个自界说的表单视图,不光处理惩罚表单提交,还须要在表单验证失败时实验特定逻辑。
  1. # myapp/forms.py
  2. from django import forms
  3. from .models import Post
  4. class PostForm(forms.ModelForm):
  5.     class Meta:
  6.         model = Post
  7.         fields = ['title', 'content']
复制代码
  1. # myapp/views.py
  2. from django.views.generic import View
  3. from django.shortcuts import render, redirect
  4. from .forms import PostForm
  5. class CustomPostCreateView(View):
  6.     form_class = PostForm
  7.     template_name = 'post_form.html'
  8.     def get(self, request):
  9.         form = self.form_class()
  10.         return render(request, self.template_name, {'form': form})
  11.     def post(self, request):
  12.         form = self.form_class(request.POST)
  13.         if form.is_valid():
  14.             form.save()
  15.             return redirect('post_list')
  16.         else:
  17.             # 自定义处理逻辑,例如记录错误日志日志
  18.             return render(request, self.template_name, {'form': form})
复制代码
4. 类视图在 Django REST framework 中的应用

Django REST framework(DRF)同样广泛使用类视图,提供了更高条理的抽象,简化 API 的开发。下面先容 DRF 中常用的类视图及其使用方法。
4.1 底子类视图

4.1.1 APIView

APIView 是 DRF 中全部类视图的基类,类似于 Django 的 View。它提供了对 HTTP 方法的支持,并集成了 DRF 的功能,如认证、权限、序列化等。
  1. # myapp/api_views.py
  2. from rest_framework.views import APIView
  3. from rest_framework.response import Response
  4. from rest_framework import status
  5. class HelloWorldAPIView(APIView):
  6.     def get(self, request):
  7.         return Response({"message": "Hello, World!"}, status=status.HTTP_200_OK)
  8.     def post(self, request):
  9.         data = request.data
  10.         return Response({"received_data": data}, status=status.HTTP_201_CREATED)
复制代码
4.2 通用类视图

DRF 提供了很多通用类视图,简化了常见的 API 使用,如列表、创建、检索、更新和删除。
4.2.1 ListAPIView 和 CreateAPIView

分别用于列出对象和创建新对象。
  1. # myapp/api_views.py
  2. from rest_framework.generics import ListAPIView, CreateAPIView
  3. from .models import Post
  4. from .serializers import PostSerializer
  5. class PostListAPIView(ListAPIView):
  6.     queryset = Post.objects.all()
  7.     serializer_class = PostSerializer
  8. class PostCreateAPIView(CreateAPIView):
  9.     queryset = Post.objects.all()
  10.     serializer_class = PostSerializer
复制代码
4.2.2 RetrieveAPIView, UpdateAPIView, DestroyAPIView

分别用于检索、更新和删除单个对象。
  1. # myapp/api_views.py
  2. from rest_framework.generics import RetrieveAPIView, UpdateAPIView, DestroyAPIView
  3. class PostRetrieveAPIView(RetrieveAPIView):
  4.     queryset = Post.objects.all()
  5.     serializer_class = PostSerializer
  6. class PostUpdateAPIView(UpdateAPIView):
  7.     queryset = Post.objects.all()
  8.     serializer_class = PostSerializer
  9. class PostDestroyAPIView(DestroyAPIView):
  10.     queryset = Post.objects.all()
  11.     serializer_class = PostSerializer
复制代码
4.2.3 ListCreateAPIView 和 RetrieveUpdateDestroyAPIView

将多个使用组合在一起,镌汰代码重复。
  1. # myapp/api_views.py
  2. from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
  3. class PostListCreateAPIView(ListCreateAPIView):
  4.     queryset = Post.objects.all()
  5.     serializer_class = PostSerializer
  6. class PostRetrieveUpdateDestroyAPIView(RetrieveUpdateDestroyAPIView):
  7.     queryset = Post.objects.all()
  8.     serializer_class = PostSerializer
复制代码
4.3 视图集(ViewSets)

视图集将多个相干的视图使用组合在一个类中,进一步简化代码。DRF 提供了 ModelViewSet、ReadOnlyModelViewSet 等。
  1. # myapp/api_views.py
  2. from rest_framework import viewsets
  3. from .models import Post
  4. from .serializers import PostSerializer
  5. class PostViewSet(viewsets.ModelViewSet):
  6.     queryset = Post.objects.all()
  7.     serializer_class = PostSerializer
复制代码
  1. # myapp/urls.py
  2. from django.urls import path, include
  3. from rest_framework.routers import DefaultRouter
  4. from .api_views import PostViewSet
  5. router = DefaultRouter()
  6. router.register(r'posts', PostViewSet)
  7. urlpatterns = [
  8.     path('api/', include(router.urls)),
  9. ]
复制代码
4.4 自界说类视图

在 DRF 中,也可以根据须要自界说类视图,实现特定的逻辑。
示例:自界说权限和过滤

  1. # myapp/api_views.py
  2. from rest_framework import viewsets, permissions, filters
  3. from django_filters.rest_framework import DjangoFilterBackend
  4. from .models import Post
  5. from .serializers import PostSerializer
  6. class CustomPostViewSet(viewsets.ModelViewSet):
  7.     queryset = Post.objects.all()
  8.     serializer_class = PostSerializer
  9.     permission_classes = [permissions.IsAuthenticatedOrReadOnly]
  10.     filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
  11.     filterset_fields = ['title', 'created_at']
  12.     search_fields = ['title', 'content']
  13.     ordering_fields = ['created_at', 'title']
  14.     ordering = ['-created_at']
  15.     def perform_create(self, serializer):
  16.         serializer.save(author=self.request.user)
复制代码
5. 类视图的最佳实践

为了确保类视图的优雅和高效,遵照以下最佳实践好坏常紧张的。
5.1 遵照单一职责原则

每个视图类应专注于一个特定的使命,克制在一个视图中处理惩罚过多的逻辑。这有助于进步代码的可维护性和可读性。
5.2 使用通用类视图和 Mixins

尽大概使用 Django 或 DRF 提供的通用类视图和 Mixins,克制重复造轮子。这不光镌汰了代码量,还使用了框架的优化和最佳实践。
  1. # 示例:使用 DRF 的 ListModelMixin 和 CreateModelMixin
  2. from rest_framework import viewsets, mixins
  3. class PostViewSet(mixins.ListModelMixin,
  4.                  mixins.CreateModelMixin,
  5.                  viewsets.GenericViewSet):
  6.     queryset = Post.objects.all()
  7.     serializer_class = PostSerializer
复制代码
5.3 公道构造代码布局

将视图类按照功能或模块构造在差别的文件中,克制单个文件过于巨大。比方,可以将 API 视图和前端视图分开存放。
  1. myapp/
  2. ├── views/
  3. │   ├── __init__.py
  4. │   ├── frontend_views.py
  5. │   └── api_views.py
  6. ├── models.py
  7. ├── serializers.py
  8. ├── urls.py
  9. └── ...
复制代码
5.4 使用装饰器和 Mixins 添加额外功能

如权限控制、缓存、速率限定等,可以通过装饰器或 Mixins 添加到类视图中,而不须要修改视图的焦点逻辑。
  1. # 示例:添加速率限制
  2. from rest_framework.throttling import UserRateThrottle
  3. from rest_framework import viewsets
  4. class PostViewSet(viewsets.ModelViewSet):
  5.     queryset = Post.objects.all()
  6.     serializer_class = PostSerializer
  7.     throttle_classes = [UserRateThrottle]
复制代码
5.5 优化 get_queryset 和 get_serializer_class

根据哀求的差别,动态调解查询集和序列化器类,提拔性能和机动性。
  1. # 示例:根据用户角色使用不同的序列化器
  2. class PostViewSet(viewsets.ModelViewSet):
  3.     queryset = Post.objects.all()
  4.     def get_serializer_class(self):
  5.         if self.request.user.is_staff:
  6.             return PostAdminSerializer
  7.         return PostSerializer
复制代码
5.6 处理惩罚非常和错误

在类视图中得当处理惩罚大概出现的非常,确保 API 的稳固性和用户体验。
  1. # 示例:处理对象不存在的异常
  2. from rest_framework.exceptions import NotFound
  3. class PostDetailAPIView(APIView):
  4.     def get_object(self, pk):
  5.         try:
  6.             return Post.objects.get(pk=pk)
  7.         except Post.DoesNotExist:
  8.             raise NotFound(detail="Post not found", code=404)
  9.     def get(self, request, pk):
  10.         post = self.get_object(pk)
  11.         serializer = PostSerializer(post)
  12.         return Response(serializer.data)
复制代码
6. 实战示例:构建一个完备的 CRUD API

通过一个完备的示例,展示怎样使用类视图构建一个 CRUD(创建、读取、更新、删除)API。
6.1 界说模子

  1. # myapp/models.py
  2. from django.db import models
  3. from django.contrib.auth.models import User
  4. class Post(models.Model):
  5.     author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
  6.     title = models.CharField(max_length=200)
  7.     content = models.TextField()
  8.     created_at = models.DateTimeField(auto_now_add=True)
  9.     def __str__(self):
  10.         return self.title
复制代码
6.2 创建序列化器

  1. # myapp/serializers.py
  2. from rest_framework import serializers
  3. from .models import Post
  4. class PostSerializer(serializers.ModelSerializer):
  5.     author = serializers.ReadOnlyField(source='author.username')
  6.     class Meta:
  7.         model = Post
  8.         fields = ['id', 'author', 'title', 'content', 'created_at']
复制代码
6.3 实现视图集

  1. # myapp/api_views.py
  2. from rest_framework import viewsets, permissions
  3. from .models import Post
  4. from .serializers import PostSerializer
  5. class PostViewSet(viewsets.ModelViewSet):
  6.     """
  7.     一个完整的 Post CRUD API
  8.     """
  9.     queryset = Post.objects.all().order_by('-created_at')
  10.     serializer_class = PostSerializer
  11.     permission_classes = [permissions.IsAuthenticatedOrReadOnly]
  12.     def perform_create(self, serializer):
  13.         serializer.save(author=self.request.user)
复制代码
6.4 设置路由

  1. # myapp/urls.py
  2. from django.urls import path, include
  3. from rest_framework.routers import DefaultRouter
  4. from .api_views import PostViewSet
  5. router = DefaultRouter()
  6. router.register(r'posts', PostViewSet, basename='post')
  7. urlpatterns = [
  8.     path('api/', include(router.urls)),
  9. ]
复制代码
6.5 设置权限和认证

在 settings.py 中设置 DRF 的权限和认证机制。
  1. # myproject/settings.py
  2. REST_FRAMEWORK = {
  3.     'DEFAULT_PERMISSION_CLASSES': [
  4.         'rest_framework.permissions.IsAuthenticatedOrReadOnly',
  5.     ],
  6.     'DEFAULT_AUTHENTICATION_CLASSES': [
  7.         'rest_framework.authentication.SessionAuthentication',
  8.         'rest_framework.authentication.BasicAuthentication',
  9.     ],
  10.     'DEFAULT_FILTER_BACKENDS': [
  11.         'django_filters.rest_framework.DjangoFilterBackend',
  12.         'rest_framework.filters.SearchFilter',
  13.         'rest_framework.filters.OrderingFilter',
  14.     ],
  15.     'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
  16.     'PAGE_SIZE': 10,
  17. }
复制代码
确保安装并添加 django-filter:
  1. pip install django-filter
复制代码
在 INSTALLED_APPS 中添加 'django_filters':
  1. # myproject/settings.py
  2. INSTALLED_APPS = [
  3.     # 其他应用...
  4.     'rest_framework',
  5.     'django_filters',
  6.     'myapp',
  7. ]
复制代码
6.6 运行和测试 API

启动开发服务器:
  1. python manage.py runserver
复制代码
访问 /api/posts/ 可以查察全部帖子,支持 GET、POST 等方法。通过欣赏器或工具(如 Postman)测试 API 的各项功能。
7. 总结

类视图(CBV)在 Django 和 Django REST framework 中提供了强盛且机动的方式来构建视图和 API。通过继承内置类视图、使用 Mixins 以及自界说视图类,可以大大进步代码的可复用性和可维护性。以下是关键点总结:


  • 选择符合的基类:根据需求选择 View、TemplateView、ListView 等内置类视图。
  • 使用通用类视图:使用 Django 和 DRF 提供的通用类视图和 Mixins,镌汰代码重复。
  • 遵照单一职责原则:确保每个视图类只负责一个明白的使命。
  • 构造精良的代码布局:将视图类按功能模块化,便于管理和维护。
  • 处理惩罚权限和认证:公道设置权限和认证,确保应用的安全性。
  • 编写测试:为类视图编写测试,确保其举动符合预期。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表