Django REST framework 源码剖析-视图类详解(Views)

devtools/2025/1/8 6:32:51/

REST_framework_0">Django REST framework视图图解

在这里插入图片描述

  • 视图类(View)

‌视图‌是DRF中处理用户请求的基本单元。它们可以是函数视图(FBV)或类视图(CBV)。函数视图使用函数来处理请求,而类视图则使用类来处理请求。类视图默认会自动dispatch特定的HTTP方法,如GET、POST等,不需要像函数视图那样通过单独的条件判断来处理不同的HTTP方法。此外,类视图可以使用面向对象的技术,如Mixin(多继承、混用),将代码拆解成可复用的组件‌,GenericAPIView可以与ListModelMixin、CreateModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin等Mixin结合使用,以实现增删改查等功能‌。

  • 视图集(ViewSet)

‌视图集‌是DRF中用于组织相关视图的集合。它们继承自APIView或GenericAPIView,并且可以定义多个方法(如list、create、retrieve、update、destroy等),这些方法对应不同的HTTP请求。视图集可以解决路由匹配和合并的问题,并且方法名可以自定义,路由匹配规则也需要相应修改。视图集还可以与Mixin结合使用,以实现更复杂的业务逻辑‌。

视图类

APIView

  • rest_framework.views.APIView
  • APIView是REST framework提供的所有视图的基类,继承自Django的View父类
APIView与View的不同之处
  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据- 设置(render)符合前端要求的格式
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
支持定义的类属性
  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类
APIViews 示例
python">from rest_framework.views import APIView
from rest_framework.response import Response# url(r'^students/$', views.StudentsAPIView.as_view()),
class StudentsAPIView(APIView):def get(self, request):data_list = Student.objects.all()serializer = StudentModelSerializer(instance=data_list, many=True)return Response(serializer.data)

GenericAPIView

  • rest_framework.generics.GenericAPIView
  • 继承自APIVIew,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持,通常在使用时,可搭配一个或多个Mixin扩展类
属性
serializer_class 指明视图使用的序列化器
queryset 指明使用的数据查询集
pagination_class 指明分页控制类
filter_backends 指明过滤控制后端
方法
get_serializer_class(self)
  • 当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了
  • 返回序列化器类,默认返回serializer_class,可以重写,例如:
python">def get_serializer_class(self):if self.request.user.is_staff:return FullAccountSerializerreturn BasicAccountSerializer
get_serializer(self, args, *kwargs)
  • 返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法
  • 该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用
  • request 当前视图的请求对象
  • view 当前请求的类视图对象
  • format 当前请求期望返回的数据格式
get_queryset(self)
  • 返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写,例如:
python">def get_queryset(self):user = self.request.userreturn user.accounts.all()
get_object(self)
  • 返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用
    在试图中可以调用该方法获取详情信息的模型类对象
  • 若详情访问的模型类对象不存在,会返回404
  • 该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问, 例如:
python"># url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
class BookDetailView(GenericAPIView):queryset = BookInfo.objects.all()serializer_class = BookInfoSerializerdef get(self, request, pk):book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象serializer = self.get_serializer(book)return Response(serializer.data)
GenericAPIView 示例
python">from rest_framework.generics import GenericAPIViewfrom students.models import Student
from .serializers import StudentModelSerializer, StudentModel2Serializer
from rest_framework.response import Responseclass StudentsGenericAPIView(GenericAPIView):# 本次视图类中要操作的数据[必填]queryset = Student.objects.all()# 本次视图类中要调用的默认序列化器[选填]serializer_class = StudentModelSerializerdef get(self, request):"""获取所有学生信息"""serializer = self.get_serializer(instance=self.get_queryset(), many=True)return Response(serializer.data)def post(self,request):data = request.dataserializer = self.get_serializer(data=data)serializer.is_valid(raise_exception=True)instance = serializer.save()serializer = self.get_serializer(instance=instance)return Response(serializer.data)class StudentGenericAPIView(GenericAPIView):queryset = Student.objects.all()serializer_class = StudentModelSerializerdef get_serializer_class(self):"""重写获取序列化器类的方法"""if self.request.method == "GET":return StudentModel2Serializerelse:return StudentModelSerializer# 在使用GenericAPIView视图获取或操作单个数据时,视图方法中的代表主键的参数最好是pkdef get(self,request,pk):"""获取一条数据"""serializer = self.get_serializer(instance=self.get_object())return Response(serializer.data)def put(self,request,pk):data = request.dataserializer = self.get_serializer(instance=self.get_object(),data=data)serializer.is_valid(raise_exception=True)serializer.save()serializer = self.get_serializer(instance=self.get_object())return Response(serializer.data)
序列化器示例
python">from rest_framework import serializersfrom students.models import Studentclass StudentModelSerializer(serializers.ModelSerializer):class Meta:model= Studentfields = "__all__"class StudentModel2Serializer(serializers.ModelSerializer):class Meta:model= Studentfields = ("name","class_null")

5个视图拓展类

  • 提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量
  • 这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法
ListModelMixin
  • 列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码, 该Mixin的list方法会对数据进行过滤和分页
源码
python">class ListModelMixin(object):"""List a queryset."""def list(self, request, *args, **kwargs):# 过滤queryset = self.filter_queryset(self.get_queryset())# 分页page = self.paginate_queryset(queryset)if page is not None:serializer = self.get_serializer(page, many=True)return self.get_paginated_response(serializer.data)# 序列化serializer = self.get_serializer(queryset, many=True)return Response(serializer.data)
示例
python">from rest_framework.mixins import ListModelMixin
from rest_framework.generics import GenericAPIViewclass BookListView(ListModelMixin, GenericAPIView):queryset = BookInfo.objects.all()serializer_class = BookInfoSerializerdef get(self, request):return self.list(request)
CreateModelMixin
  • 创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码, 如果序列化器对前端发送的数据验证失败,返回400错误
源码
python">class CreateModelMixin(object):"""Create a model instance."""def create(self, request, *args, **kwargs):# 获取序列化器serializer = self.get_serializer(data=request.data)# 验证serializer.is_valid(raise_exception=True)# 保存self.perform_create(serializer)headers = self.get_success_headers(serializer.data)return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)def perform_create(self, serializer):serializer.save()def get_success_headers(self, data):try:return {'Location': str(data[api_settings.URL_FIELD_NAME])}except (TypeError, KeyError):return {}
示例
python">from rest_framework.mixins import CreateModelMixin
from rest_framework.generics import GenericAPIViewclass Book(CreateModelMixin, GenericAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializerdef post(self, request, *args, **kwargs):return self.create(request, *args, **kwargs)
RetrieveModelMixin
  • 详情视图扩展类,提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象, 如果存在,返回200, 否则返回404
源码
python">class RetrieveModelMixin(object):"""Retrieve a model instance."""def retrieve(self, request, *args, **kwargs):# 获取对象,会检查对象的权限instance = self.get_object()# 序列化serializer = self.get_serializer(instance)return Response(serializer.data)
示例
python">from rest_framework.mixins import RetrieveModelMixin
from rest_framework.generics import GenericAPIViewclass BookDetailView(RetrieveModelMixin, GenericAPIView):queryset = BookInfo.objects.all()serializer_class = BookInfoSerializerdef get(self, request, pk):return self.retrieve(request)
UpdateModelMixin

更新视图扩展类,提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象, 同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新, 成功返回200,序列化器校验数据失败时,返回400错误

源码
python">class UpdateModelMixin(object):"""Update a model instance."""def update(self, request, *args, **kwargs):partial = kwargs.pop('partial', False)instance = self.get_object()serializer = self.get_serializer(instance, data=request.data, partial=partial)serializer.is_valid(raise_exception=True)self.perform_update(serializer)if getattr(instance, '_prefetched_objects_cache', None):# If 'prefetch_related' has been applied to a queryset, we need to# forcibly invalidate the prefetch cache on the instance.instance._prefetched_objects_cache = {}return Response(serializer.data)def perform_update(self, serializer):serializer.save()def partial_update(self, request, *args, **kwargs):kwargs['partial'] = Truereturn self.update(request, *args, **kwargs)
示例
python">from rest_framework.mixins import UpdateModelMixin
from rest_framework.generics import GenericAPIViewclass BookDetail(UpdateModelMixin, GenericAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializerdef put(self, request, *args, **kwargs):return self.update(request, *args, **kwargs)
DestroyModelMixin
  • 删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象, 成功返回204,不存在返回404
源码
python">class DestroyModelMixin(object):"""Destroy a model instance."""def destroy(self, request, *args, **kwargs):instance = self.get_object()self.perform_destroy(instance)return Response(status=status.HTTP_204_NO_CONTENT)def perform_destroy(self, instance):instance.delete()
示例
python">from rest_framework.mixins import DestroyModelMixin
from rest_framework.generics import GenericAPIViewclass BookDetail(DestroyModelMixin, GenericAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializerdef delete(self, request, *args, **kwargs):return self.destroy(request, *args, **kwargs)
混合使用示例 (创建、列表)
python">"""GenericAPIView结合视图扩展类实现api接口"""
from rest_framework.mixins import ListModelMixin,CreateModelMixin
class Students2GenericAPIView(GenericAPIView,ListModelMixin,CreateModelMixin):# 本次视图类中要操作的数据[必填]queryset = Student.objects.all()# 本次视图类中要调用的默认序列化器[选填]serializer_class = StudentModelSerializerdef get(self, request):"""获取多个学生信息"""return self.list(request)def post(self,request):"""添加学生信息"""return self.create(request)
混合使用示例 (更新、删除)
python">from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student2GenericAPIView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):queryset = Student.objects.all()serializer_class = StudentModelSerializer# 在使用GenericAPIView视图获取或操作单个数据时,视图方法中的代表主键的参数最好是pkdef get(self,request,pk):"""获取一条数据"""return self.retrieve(request,pk)def put(self,request,pk):"""更新一条数据"""return self.update(request,pk)def delete(self,request,pk):"""删除一条数据"""return self.destroy(request,pk)

GenericAPIView的9个视图子类

CreateAPIView
  • 提供 post 方法
  • 继承自: GenericAPIView、CreateModelMixin
ListAPIView
  • 提供 get 方法
  • 继承自:GenericAPIView、ListModelMixin
ListCreateAPIView
  • 提供 get 和 post方法
  • 继承自:GenericAPIView、ListModelMixin、CreateModelMixin
RetrieveAPIView
  • 提供 get 方法
  • 继承自: GenericAPIView、RetrieveModelMixin
DestoryAPIView
  • 提供 delete 方法
  • 继承自:GenericAPIView、DestoryModelMixin
UpdateAPIView
  • 提供 put 和 patch 方法
  • 继承自:GenericAPIView、UpdateModelMixin
RetrieveUpdateAPIView
  • 提供 get、put、patch方法
  • 继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
RetrieveDestroyAPIView
  • 提供 get 和 delete 方法
  • 继承自:GenericAPIView、RetrieveModelMixin、DestoryModelMixin
RetrieveUpdateDestoryAPIView
  • 提供 get、put、patch、delete方法
  • 继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
CURD完整示例
python">import hashlib
from django.db import models
from django.conf import settings
from django.db import models
from django.contrib.auth.models import AbstractUsertable_prefix = "rest_"class CoreModel(models.Model):"""核心标准抽象模型模型,可直接继承使用增加审计字段, 覆盖字段时, 字段名称请勿修改, 必须统一审计字段名称"""id = models.BigAutoField(primary_key=True,help_text="Id",verbose_name="Id")description = models.CharField(max_length=255,verbose_name="描述",null=True,blank=True,help_text="描述")creator = models.ForeignKey(to=settings.AUTH_USER_MODEL,related_query_name='creator_query',null=True,verbose_name='创建人',help_text="创建人",on_delete=models.SET_NULL,db_constraint=False)modifier = models.CharField(max_length=255,null=True,blank=True,help_text="修改人",verbose_name="修改人")dept_belong_id = models.CharField(max_length=255,help_text="数据归属部门",null=True,blank=True,verbose_name="数据归属部门")update_datetime = models.DateTimeField(auto_now=True,null=True,blank=True,help_text="修改时间",verbose_name="修改时间")create_datetime = models.DateTimeField(auto_now_add=True,null=True,blank=True,help_text="创建时间",verbose_name="创建时间")class Meta:abstract = Trueverbose_name = '核心模型'verbose_name_plural = verbose_nameclass Users(CoreModel, AbstractUser):GENDER_CHOICES = ((0, "未知"),(1, "男"),(2, "女"),)USER_TYPE = ((0, "后台用户"),(1, "前台用户"),)username = models.CharField(max_length=150,unique=True,db_index=True,verbose_name="用户账号",help_text="用户账号")employee_no = models.CharField(max_length=150,unique=True,db_index=True,null=True,blank=True,verbose_name="工号",help_text="工号")email = models.EmailField(max_length=255,verbose_name="邮箱",null=True,blank=True,help_text="邮箱")mobile = models.CharField(max_length=255,verbose_name="电话",null=True,blank=True,help_text="电话")avatar = models.CharField(max_length=255,verbose_name="头像",null=True,blank=True,help_text="头像")name = models.CharField(max_length=40,verbose_name="姓名",help_text="姓名")gender = models.IntegerField(choices=GENDER_CHOICES,default=0,verbose_name="性别",null=True,blank=True,help_text="性别")user_type = models.IntegerField(choices=USER_TYPE,default=0,verbose_name="用户类型",null=True,blank=True,help_text="用户类型")last_token = models.CharField(max_length=255,null=True,blank=True,verbose_name="最后一次登录Token",help_text="最后一次登录Token")def set_password(self, raw_password, **kwargs):super().set_password(hashlib.md5(raw_password.encode(encoding="UTF-8")).hexdigest())class Meta:db_table = table_prefix + "system_users"verbose_name = "用户表"verbose_name_plural = verbose_nameordering = ("-create_datetime",)class Book(CoreModel):title = models.CharField(verbose_name="标题",max_length=1024,null=True,blank=True,help_text="标题",)author = models.CharField(verbose_name="作者",max_length=1024,null=True,blank=True,help_text="作者",)class Meta:db_table = table_prefix + "book"verbose_name = "图书表"verbose_name_plural = verbose_name
python">from myproject import models
from rest_framework.fields import empty
from rest_framework.request import Request
from rest_framework.serializers import ModelSerializerfrom rest_framework.generics import CreateAPIView, ListAPIView, ListCreateAPIView
from rest_framework.generics import RetrieveAPIView, UpdateAPIView, DestroyAPIView, RetrieveDestroyAPIView, RetrieveUpdateAPIView, RetrieveUpdateDestroyAPIViewclass CustomModelSerializer(ModelSerializer):"""增强DRF的ModelSerializer,(1)self.request能获取到rest_framework.request.Request对象"""def __init__(self, instance=None, data=empty, request=None, **kwargs):super().__init__(instance, data, **kwargs)self.request: Request = request or self.context.get("request", None)class BookSerializer(CustomModelSerializer):creator = UserSerializer(required=False)create_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)update_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False)# creator = serializers.StringRelatedField()class Meta:model = Bookfields = ["title", "author", "create_datetime", "update_datetime", "creator"]depth = 1# 此视图只可以新增、不可以查询
class Book(CreateAPIView):queryset = models.Book.objects.all()serializer_class = BookSerializer# 此视图查询一条、修改、删除都包含
class BookDetail(RetrieveUpdateDestroyAPIView):  queryset = models.Book.objects.all()serializer_class = BookSerializer

总结

两个基类

  • APIView
  • GenericAPIView: 数据库操作, queryset 和serializer_class

frameworkmixins_672">5个视图扩展类(rest_framework.mixins)

  • CreateModelMixin: create方法创建一条
  • DestroyModelMixin: destory方法删除一条
  • ListModelMixin: list方法获取所有
  • RetrieveModelMixin: retrieve获取一条
  • UpdateModelMixin: update修改一条

frameworkgenerics_678">9个子类视图(rest_framework.generics)

  • CreateAPIView: 继承CreateModelMixin,GenericAPIView,有post方法,新增数据
  • DestroyAPIView: 继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
  • ListAPIView: 继承ListModelMixin,GenericAPIView,有get方法获取所有
  • UpdateAPIView: 继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
  • RetrieveAPIView: 继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条
  • ListCreateAPIView: 继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
  • RetrieveDestroyAPIView: 继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
  • RetrieveUpdateAPIView: 继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
  • RetrieveUpdateDestroyAPIView: 继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除

http://www.ppmy.cn/devtools/147997.html

相关文章

网络安全:路由技术

概述 路由技术到底研究什么内容 研究路由器寻找最佳路径的过程 路由器根据最佳路径转发数据包 知识点&#xff0c;重要OSRF,BGP1.静态路由原理 路由技术分类 静态路由和动态路由技术 静态路由&#xff1a;是第一代路由技术&#xff0c;由网络管理员手工静态写路由/路径告知路…

docker 安装influxdb

docker pull influxdb mkdir -p /root/influxdb/data docker run -d --name influxdb -p 8086:8086 -v /root/influxdb/data:/var/lib/influxdb influxdb:latest#浏览器登录&#xff1a;http://192.168.31.135:8086&#xff0c;首次登录设置用户名密码&#xff1a;admin/admin1…

您的公司需要小型语言模型

当专用模型超越通用模型时 “越大越好”——这个原则在人工智能领域根深蒂固。每个月都有更大的模型诞生&#xff0c;参数越来越多。各家公司甚至为此建设价值100亿美元的AI数据中心。但这是唯一的方向吗&#xff1f; 在NeurIPS 2024大会上&#xff0c;OpenAI联合创始人伊利亚…

Ungoogled Chromium127编译指南 Linux篇 - 拉取仓库(七)

1. 引言 在完成了Docker环境的配置后&#xff0c;我们现在需要获取Ungoogled Chromium的源代码。本文将详细介绍如何正确拉取和管理项目代码&#xff0c;确保我们获得正确的版本用于编译。源代码的获取看似简单&#xff0c;但正确的版本选择和子模块管理对于成功编译至关重要。…

Python基于Gradio可视化部署机器学习应用

Gradio 是一个用于快速创建机器学习模型和用户界面之间交互的 Python 库。它允许你无需编写大量前端代码&#xff0c;就能将机器学习模型部署为可交互的网页应用。以下是一个基于 Gradio 可视化部署机器学习应用的基本步骤&#xff1a; 安装 Gradio&#xff1a; 首先&#xff0…

探索电商新维度:利用JAVA爬虫获取1688店铺商品接口

引言 在数字化时代&#xff0c;电商行业的迅猛发展带来了巨大的数据量和信息流。对于商家而言&#xff0c;如何高效地管理和利用这些数据成为了提升竞争力的关键。本文将深入探讨如何利用JAVA爬虫技术&#xff0c;获取1688平台的item_search_shop接口&#xff0c;以获得店铺的…

网络游戏之害

网络游戏之害&#xff1a; 网络游戏于今之世风靡四方&#xff0c;其娱人耳目、畅人心怀之效&#xff0c;固为人知&#xff0c;然所藏之害&#xff0c;若隐伏之暗潮&#xff0c;汹涌而至时&#xff0c;足以覆舟&#xff0c;尤以青年为甚&#xff0c;今且缕析其害&#xff0c;以…

Springboot日志打印、SpringBoot集成Log4j2(附源码)、异步日志

文章目录 一、Log4j2介绍1.1、常用日志框架1.2、为什么选用log4j2 二、Log4j2整合步骤2.1、引入jar包2.2、配置文件2.3、配置文件模版 三、配置参数简介3.1、日志级别3.2、日志格式&#xff08;PatternLayout&#xff09;3.3、Appenders组件列表3.3.1、Console3.3.2、File3.3.3…