django DRF 视图

 

 

 

 

 

 

 

 

 

视图

Django REST framwork 提供的视图的主要作用:

  • 控制序列化器的执行(检验、保存、转换数据)

  • 控制数据库模型的操作

 

1.2 普通视图

REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。

 

1.2.1 2个视图基类

1.2.1.1 APIView基本视图类

rest_framework.views.APIView

APIView是REST framework提供的所有视图类的基类,继承自Django的View父类。

APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;

  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(renderer)符合前端期望要求的格式;

  • 任何APIException异常都会被捕获到,并且处理成合适格式的响应信息返回给客户端;

    django 的View中所有异常全部以HTML格式显示 不会返回json格式

    drf的APIVIew或者APIView的子类会自动根据客户端的Accept进行错误信息的格式转换。

  • 重新声明了一个新的as_view方法并在dispatch()进行路由分发前,会对请求的客户端进行身份认证、权限检查、流量控制。

APIView除了继承了View原有的属性方法意外,还新增了类属性:

  • authentication_classes 列表或元组,身份认证类

  • permissoin_classes 列表或元组,权限检查类

  • throttle_classes 列表或元祖,流量控制类

APIView中仍以常规的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。

 

为了方便演示,所以drf提供的视图里面的内容知识,我们另外创建一个子应用来展示

python manage.py startapp demo

注册子应用

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'students',
    'sers',    # 序列化器
    "school",  # 序列化器嵌套
    'req',     # 请求与响应
    'demo',    # 视图
]

总路由,代码:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('students/', include("students.urls")),
    path('sers/', include("sers.urls")),
    path('school/', include("school.urls")),
    path("req/", include("req.urls")),
    path("demo/", include("demo.urls")),
]

子应用路由,代码:

from django.urls import path
from . import views

urlpatterns = [

]

 

序列化器,demo/serializers.py,代码:

 

# --- coding: utf-8 --
# @Author: lichaoming
# @Date  : 2024/12/03

from rest_framework import serializers
from stuapi.models import Student


class StudentModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Student
        fields = "__all__"

 

 

视图代码:

 

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import StudentModelSerializer
from stuapi.models import Student
"""
GET  /demo/students/   获取所有学生信息    
POST /demo/students/   添加一个学生信息    

GET  /demo/students/<pk>   获取一个学生信息    
PUT  /demo/students/<pk>   更新一个学生信息    
DELETE  /demo/students/<pk>   删除一个学生信息    
"""

class StudentAPIView(APIView):
    def get(self, request):
        """获取所有学生信息"""
        # 1. 从数据库中读取学生列表信息
        student_list = Student.objects.all()
        # 2. 实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(instance=student_list, many=True)
        # 3. 转换数据并返回给客户端
        return Response(serializer.data)

    def post(self,request):
        """添加学生信息"""
        # 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(data=request.data)
        # 2. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 3. 返回新增的模型数据给客户端
        return Response(serializer.data, status=status.HTTP_201_CREATED)

class StudentInfoAPIView(APIView):
    def get(self, request,pk):
        """获取一条数据"""
        # 1. 使用pk作为条件获取模型对象
        student = Student.objects.get(pk=pk)

        # 2. 序列化
        serializer = StudentModelSerializer(instance=student)
        # 3.返回结果
        return Response(serializer.data)

    def put(self, request,pk):
        """更新数据"""
        # 1. 使用pk作为条件获取模型对象
        student = Student.objects.get(pk=pk)

        # 2. 获取客户端提交的数据
        serializer = StudentModelSerializer(instance=student,data=request.data)
        # 3. 反序列化[验证数据和数据保存]
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4. 返回结果
        return Response(serializer.data)

    def delete(self,request,pk):
        """删除数据"""
        # 1. 根据PK值获取要删除的数据并删除
        Student.objects.get(pk=pk).delete()
        # 2. 返回结果
        return Response(status=status.HTTP_204_NO_CONTENT)

 

 

路由代码:

from django.urls import path, re_path
from . import views

urlpatterns = [
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),
]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

GenericAPIView[通用视图类]

通用视图类在继承了APIView的所有功能以外,还提供了几个属性和方法让我们可以把视图中独特的代码抽取出来作为类属性,让视图方法中的代码变得更加通用,方便把通用代码进行简写。

rest_framework.generics.GenericAPIView

继承自APIView主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类(混入类)的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。

提供的关于序列化器使用的1个属性与2个方法

  • 属性:

    • serializer_class=A序列化器 指明视图使用的序列化器类

  • 方法:

    • get_serializer_class(self)

      当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。

      返回序列化器类,默认返回serializer_class,可以重写,例如:

 

 

class Student2GenericAPIView(GenericAPIView):
    # 整个视图类只使用一个序列化器的情况
    # serializer_class = StudentModelSerializert
    # 整个视图类中使用多个序列化器的情况
    def get_serializer_class(self):
      if self.request.method.lower() == "put":
            return StudentModelSerializer
      else:
            return Student2ModelSerializer

    queryset = Student.objects

    def get(self, request, pk):
        """获取一个模型信息"""
        serializer = self.get_serializer(instance=self.get_object())
        return Response(serializer.data)

    def put(self, request, pk):
        """更新一个模型信息"""
        serializer = self.get_serializer(instance=self.get_object(), data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)

 

 

    • get_serializer(self, args, *kwargs)

      返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。

      注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。

      • request 当前视图的请求对象

      • view 当前请求的类视图对象

      • format 当前请求期望返回的数据格式

提供的关于数据库查询的属性与方法

  • 属性:

    • queryset 指明使用的数据查询集

  • 方法:

    • get_queryset(self)

      返回视图使用的查询集QuerySet,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写,当获取数据时需要设置一些查询条件,则可以重写如下,例如:

def get_queryset(self):
    user = self.request.user
    return user.accounts.all()

 

get_object(self)

返回详情视图所需的1个模型类数据对象,主要用来提供给Mixin扩展类使用。

在试图中可以调用该方法获取详情信息的模型类对象。

若详情访问的模型类对象不存在,会返回404异常。

该方法会默认使用APIView提供的check_object_permissions方法检查当前客户端是否有权限访问当前模型对象。

举例:

 

# url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
class BookDetailView(GenericAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

    def get(self, request, pk):
        """获取一本书的信息"""
        book = self.get_object() # get_object()方法 本质上就是 self.queryset.get(pk=pk)
        serializer = self.get_serializer(book)  # 本质上 self.serializer_class(book)
        return Response(serializer.data)

 

其他可以设置的属性

  • pagination_class 指明分页控制类

  • filter_backends 指明数据过滤控制后端,允许客户端通过地址栏传递过滤参数

视图,代码:

 

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from .serializers import StudentModelSerializer
from stuapi.models import Student
"""
GET  /demo/students/   获取所有学生信息    
POST /demo/students/   添加一个学生信息    

GET  /demo/students/<pk>   获取一个学生信息    
PUT  /demo/students/<pk>   更新一个学生信息    
DELETE  /demo/students/<pk>   删除一个学生信息    
"""

class StudentAPIView(APIView):
    def get(self, request):
        """获取所有学生信息"""
        # 1. 从数据库中读取学生列表信息
        student_list = Student.objects.all()
        # 2. 实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(instance=student_list, many=True)
        # 3. 转换数据并返回给客户端
        return Response(serializer.data)

    def post(self,request):
        """添加学生信息"""
        # 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(data=request.data)
        # 2. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 3. 返回新增的模型数据给客户端
        return Response(serializer.data, status=status.HTTP_201_CREATED)

class StudentInfoAPIView(APIView):
    def get(self, request,pk):
        """获取一条数据"""
        # 1. 使用pk作为条件获取模型对象
        student = Student.objects.get(pk=pk)

        # 2. 序列化
        serializer = StudentModelSerializer(instance=student)
        # 3.返回结果
        return Response(serializer.data)

    def put(self, request,pk):
        """更新数据"""
        # 1. 使用pk作为条件获取模型对象
        student = Student.objects.get(pk=pk)

        # 2. 获取客户端提交的数据
        serializer = StudentModelSerializer(instance=student,data=request.data)
        # 3. 反序列化[验证数据和数据保存]
        serializer.is_valid(raise_exception=True)
        serializer.save()

        # 4. 返回结果
        return Response(serializer.data)

    def delete(self,request,pk):
        """删除数据"""
        # 1. 根据PK值获取要删除的数据并删除
        Student.objects.get(pk=pk).delete()
        # 2. 返回结果
        return Response(status=status.HTTP_204_NO_CONTENT)

from rest_framework.generics import GenericAPIView

"""
APIView中的api接口代码,除了部分涉及到调用模型和序列化器的代码以外,其他代码几乎都是固定写法。
所以,当我们将来针对增删查改的通用api接口编写时,完全可以基于原有的代码进行复用,
那么,drf也考虑到了这个问题,所以提供了一个GenericAPIView(通用视图类),让我们可以把接口中独特的代码单独提取出来作为类属性存在。
rest_framework.generics.GenericAPIView是APIView的子类,在APIView的基础上进行属性扩展提供了2个属性,4个方法,方便我们针对通用接口进行编写。
"""

class StudentGenericAPIView(GenericAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self, request):
        """获取学生信息"""
        # 1. 从数据库中读取学生列表信息
        instance_list = self.get_queryset()
        # 2. 实例化序列化器,获取序列化对象
        # serializer = self.serializer_class(instance_list, many=True)
        serializer = self.get_serializer(instance_list, many=True)
        # 3. 使用serializer.data实现对数据进行序列化成字典
        return Response(serializer.data)

    def post(self,request):
        """添加学生信息"""
        # 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = self.get_serializer(data=request.data)
        # 2. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 3. 返回新增的模型数据经过序列化提供给客户端
        return Response(serializer.data, status=status.HTTP_201_CREATED)

class StudentInfoGenericAPIView(GenericAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self, request,pk):
        """获取一个学生信息"""
        # 1. 使用pk作为条件获取模型对象
        # instance = self.get_queryset().get(pk=pk)
        instance = self.get_object()
        # 2. 实例化序列化器对象
        serializer = self.get_serializer(instance)
        # 3. 序列化数据并返回结果
        return Response(serializer.data)

    def put(self, request,pk):
        """更新一个学生信息"""
        # 1. 使用pk作为条件获取模型对象
        instance = self.get_object()
        # 2.获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = self.get_serializer(instance, request.data)
        # 3. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 4. 返回更新后的模型数据经过序列化提供给客户端
        return Response(serializer.data)

    def delete(self, request, pk):
        """删除一个学生信息"""
        # 1. 根据PK值获取要删除的数据并删除
        self.get_object().delete()
        # 2. 影响删除结构
        return Response(status=status.HTTP_204_NO_CONTENT)

路由代码:

# --- coding: utf-8 --
# @Author: lichaoming
# @Date  : 2024/12/03

from django.urls import path, re_path
from . import views

urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students1/", views.StudentGenericAPIView.as_view()),
    re_path("^students1/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),
]

 

 

### 5个视图扩展类

也叫混入类,作用:提供了几种后端视图(对数据资源进行增删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。

这五个扩展类需要搭配GenericAPIView通用视图基类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

 

#### 1)ListModelMixin

列表视图扩展类,提供`list(request, *args, **kwargs)`方法快速实现列表视图,返回200状态码。

该Mixin的list方法会对数据进行过滤和分页。

源代码:

 

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)

 

举例

"""
通用视图类 + 模型扩展类 实现5个基本API接口
获取多条数据 GenericsAPIView+Mixins.ListModelMixin
"""
from rest_framework.mixins import ListModelMixin


class StudentListAPIView(GenericAPIView, ListModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self, request):
        """获取所有学生信息"""
        return self.list(request)

 

 

2)CreateModelMixin

创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。

如果序列化器对前端发送的数据验证失败,返回400错误。

源代码:

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 {}

 

视图代码:

"""
通用视图类 + 模型扩展类 实现5个基本API接口
获取多条数据 GenericsAPIView+Mixins.ListModelMixin
添加一条数据 GenericsAPIView+Mixins.CreateModelMixin
"""
from rest_framework.mixins import ListModelMixin, CreateModelMixin


class StudentListAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self, request):
        """获取所有学生信息"""
        return self.list(request)

    def post(self, request):
        """添加学生信息"""
        return self.create(request)

 

#### RetrieveModelMixin

详情视图扩展类,提供`retrieve(request, *args, **kwargs)`方法,可以快速实现返回一个存在的数据对象。

如果存在,返回200, 否则返回404。

源代码:

 

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)

视图代码:

 

"""
获取一条数据 GenericsAPIView+Mixins.RetrieveModelMixin
"""
from rest_framework.mixins import RetrieveModelMixin

class StudentRetrieveAPIView(GenericAPIView, RetrieveModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self,request, pk):
        """获取一个学生信息"""
        return self.retrieve(request, pk)

 

UpdateModelMixin

更新视图扩展类,提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。

同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。

成功返回200,序列化器校验数据失败时,返回400错误。

源代码:

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'] = True
        return self.update(request, *args, **kwargs)

 

视图代码:

from rest_framework.mixins import RetrieveModelMixin,UpdateModelMixin

"""
获取一条数据 GenericsAPIView+Mixins.RetrieveModelMixin
更新一条数据 GenericsAPIView+Mixins.UpdateModelMixin
删除一条数据 GenericsAPIView+Mixins.DestroyModelMixin
"""

class StudentRetrieveAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self,request, pk):
        """获取一个学生信息"""
        return self.retrieve(request, pk)

    def put(self,request, pk):
        """更新一个学生信息"""
        return self.update(request, pk)

 

 

DestroyModelMixin

删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。

成功返回204,不存在返回404。

源代码:

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()

视图代码:

"""
获取一条数据 GenericsAPIView+Mixins.RetrieveModelMixin
更新一条数据 GenericsAPIView+Mixins.UpdateModelMixin
删除一条数据 GenericsAPIView+Mixins.DestroyModelMixin
"""

from rest_framework.mixins import RetrieveModelMixin,  UpdateModelMixin, DestroyModelMixin


class StudentRetrieveAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def 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结合视图扩展类,实现5个基本api接口,视图代码:

 

"""
通用视图类 + 模型扩展类 实现5个基本API接口
获取多条数据 GenericsAPIView+Mixins.ListModelMixin
添加一条数据 GenericsAPIView+Mixins.CreateModelMixin
"""
from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, \
    UpdateModelMixin, DestroyModelMixin


class StudentListAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def get(self, request):
        """获取所有学生信息"""
        return self.list(request)

    def post(self, request):
        """添加学生信息"""
        return self.create(request)

"""
获取一条数据 GenericsAPIView+Mixins.RetrieveModelMixin
更新一条数据 GenericsAPIView+Mixins.UpdateModelMixin
删除一条数据 GenericsAPIView+Mixins.DestroyModelMixin
"""

class StudentRetrieveAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def 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)

 

路由代码:

from django.urls import path,re_path
from . import views
urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students1/", views.StudentGenericAPIView.as_view()),
    re_path("^students1/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),

    # GenericAPIView + Mixins
    path("students2/", views.StudentListAPIView.as_view()),
    re_path("^students2/(?P<pk>\d+)/$", views.StudentRetrieveAPIView.as_view()),
]

 

### 9个视图子类

#### 1)ListAPIView

提供了get视图方法,内部调用了模型扩展类的list方法

继承自:GenericAPIView、ListModelMixin

#### 2)CreateAPIView

提供了post视图方法,内部调用了模型扩展类的create方法

继承自: GenericAPIView、CreateModelMixin

#### 3)RetrieveAPIView

提供了get视图方法,内部调用了模型扩展类的retrieve方法

继承自: GenericAPIView、RetrieveModelMixin

#### 4)DestroyAPIView

提供了delete视图方法,内部调用了模型扩展类的destroy方法

继承自:GenericAPIView、DestoryModelMixin

#### 5)UpdateAPIView

提供了put和patch视图方法,内部调用了模型扩展类的update和partial_update方法

继承自:GenericAPIView、UpdateModelMixin

#### 6)ListCreateAPIView

提供了get和post方法,内部调用了list和create方法

继承自:GenericAPIView、ListModelMixin、CreateModelMixin

#### 7)RetrieveUpdateAPIView

提供 get、put、patch方法

继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin

#### 8)RetrieveDestroyAPIView

提供 get、delete方法

继承自:GenericAPIView、RetrieveModelMixin、DestroyModelMixin

#### 9)RetrieveUpdateDestroyAPIView

提供 get、put、patch、delete方法

继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin

视图代码:

"""
使用视图子类编写5个基本API接口
视图子类 = 通用视图类+模型扩展类
ListAPIView = GenericsAPIView + ListModelMixin  列表视图子类
CreateAPIView = GenericsAPIView + CreateModelMixin  创建视图子类
"""

from rest_framework.generics import ListAPIView,CreateAPIView,\
    RetrieveAPIView,UpdateAPIView,DestroyAPIView

class StuListAPIView(ListAPIView,CreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

class StuRetrieveAPIView(RetrieveAPIView,UpdateAPIView,DestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

 

路由

# --- coding: utf-8 --
# @Author: lichaoming
# @Date  : 2024/12/03

from django.urls import path, re_path
from . import views

urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students1/", views.StudentGenericAPIView.as_view()),
    re_path("^students1/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),

    # GenericAPIView + Mixins
    path("students2/", views.StudentListAPIView.as_view()),
    re_path("^students2/(?P<pk>\d+)/$", views.StudentRetrieveAPIView.as_view()),

    # 视图子类
    path("students3/", views.StuListAPIView.as_view()),
    re_path("^students3/(?P<pk>\d+)/$", views.StuRetrieveAPIView.as_view()),
]

 

简化代码

"""
使用视图子类编写5个基本API接口
视图子类 = 通用视图类+模型扩展类
ListAPIView = GenericsAPIView + ListModelMixin  列表视图子类
CreateAPIView = GenericsAPIView + CreateModelMixin  创建视图子类
"""

from rest_framework.generics import ListAPIView,CreateAPIView,\
    RetrieveAPIView,UpdateAPIView,DestroyAPIView

class StudentView(object):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

class StuListAPIView(StudentView,ListAPIView,CreateAPIView):
    pass

class StuRetrieveAPIView(StudentView,RetrieveAPIView,UpdateAPIView,DestroyAPIView):
    pass

 

 

"""
上面的接口代码还可以继续更加的精简,drf在使用GenericAPIView和Mixins进行组合以后,还提供了视图子类。
视图子类是通用视图类 和 模型扩展类 的子类,提供了各种的视图方法调用mixins操作
    ListAPIView = GenericAPIView + ListModelMixin                 获取多条数据的视图方法
    CreateAPIView = GenericAPIView + CreateModelMixin       添加一条数据的视图方法
    RetrieveAPIView = GenericAPIView + RetrieveModelMixin  获取一条数据的视图方法
    UpdateAPIView = GenericAPIView + UpdateModelMixin     更新一条数据的视图方法
    DestroyAPIView = GenericAPIView + DestroyModelMixin    删除一条数据的视图方法

组合视图子类
    ListCreateAPIView = ListAPIView + CreateAPIView
    RetrieveUpdateAPIView = RetrieveAPIView + UpdateAPIView
    RetrieveDestroyAPIView = RetrieveAPIView + DestroyAPIView
    RetrieveUpdateDestroyAPIView = RetrieveAPIView + UpdateAPIView + DestroyAPIView
"""

from rest_framework.generics import ListAPIView, CreateAPIView, \
    RetrieveAPIView, UpdateAPIView, DestroyAPIView, \
    ListCreateAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView, RetrieveUpdateDestroyAPIView


# class StuListAPIView(ListAPIView, CreateAPIView):
class StuListAPIView(ListCreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer


# class StuRetrieveAPIView(RetrieveAPIView, UpdateAPIView, DestroyAPIView):
# class StuRetrieveAPIView(RetrieveUpdateAPIView, DestroyAPIView):
# class StuRetrieveAPIView(RetrieveDestroyAPIView, UpdateAPIView):
class StuRetrieveAPIView(RetrieveUpdateDestroyAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

 

 

视图集ViewSet

使用视图集ViewSet,可以将一系列视图相关的代码逻辑和相关的http请求动作封装到一个类中:

  • list() 提供一组数据

  • retrieve() 提供单个数据

  • create() 创建数据

  • update() 保存数据

  • destory() 删除数据

ViewSet视图集类不再限制视图方法名为get/post...等这种情况了,而是实现允许开发者根据自己的需要定义自定义视图方法名,例如 list() 或get_all()、create() 等,然后经过路由中使用http请求动作和这些视图方法名action进行绑定映射调用。

视图集在使用as_view()方法时,设置字典参数允许我们将代表视图方法名与具体http请求进行绑定。

1.3.1 常用视图集父类

1) ViewSet

继承自APIViewViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典{“http请求”:“视图方法”}的映射处理工作,如{'get':'list'},

在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

 

"""
上面代码如果想要合并成一个视图类,实现一个视图类提供5个甚至更多的API接口,则需要继承视图集(ViewSet)
为什么要继承视图集(ViewSet)?
1. 上面使用的视图类都是基于APIView实现的,而APIView基于django提供的View视图基类,
   而django的视图类View在内部实现时,dispatch方法中限制了当前视图必须采用get/post/put/delete/patch等http请求动作作为方法名,但是
   如果要实现5个api接口,必然要实现2个get请求,分别是获取多条数据与获取一条数据,一个类中肯定不存在同名的方法。
   
2. 5个接口api接口中,只有删除、获取、更新一条数据时需要地址栏传递ID,而添加一条数据与获取多条数据,实际上并不需要ID。
   所以,路由有决定我们要分开写5个接口。

drf为了解决上面的2个问题,提供了视图集和路由集。
视图集就可以帮我们实现一个视图类响应多种重复的http请求
路由集就可以帮我们实现自动根据不同的视图方法来生成不同参数的路由地址。
from rest_framework.viewsets import ViewSet  # ViewSet是APIView的子类,是所有drf中的视图集的父类
"""


"""使用ViewSet基本视图集实现5个基本api接口"""
from rest_framework.viewsets import ViewSet


class StudentViewSet(ViewSet):
    def list(self,request):
        """获取多个数据"""
        # 1. 从数据库中读取模型列表信息
        instance_list = Student.objects.all()
        # 2. 实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(instance_list, many=True)
        # 3. 使用serializer.data实现对数据进行序列化成字典
        return Response(serializer.data)

    def create(self, request):
        """添加数据"""
        # 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(data=request.data)
        # 2. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 3. 返回新增的模型数据经过序列化提供给客户端
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, pk):
        """获取一个学生信息"""
        # 1. 使用pk作为条件获取模型对象
        instance = Student.objects.get(pk=pk)
        # 2. 实例化序列化器对象
        serializer = StudentModelSerializer(instance)
        # 3. 序列化数据并返回结果
        return Response(serializer.data)

    def update(self,request, pk):
        """更新一个学生信息"""
        # 1. 使用pk作为条件获取模型对象
        instance = Student.objects.get(pk=pk)
        # 2.获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = StudentModelSerializer(instance, request.data)
        # 3. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 4. 返回更新后的模型数据经过序列化提供给客户端
        return Response(serializer.data)

    def destroy(self, request, pk):
        """删除一个学生信息"""
        # 1. 根据PK值获取要删除的数据并删除
        Student.objects.filter(pk=pk).delete()
        # 2. 影响删除结构
        return Response(status=status.HTTP_204_NO_CONTENT)

 

在设置路由时,我们可以如下操作

from django.urls import path,re_path
from . import views
urlpatterns = [
    # 代码省略。。。。。。
    # 代码省略。。。。。。
    
    
    # ViewSet
    # 视图集的路由注册格式
    # path("访问路径", views.视图集类名.as_view({"http请求方法名": "视图方法名", "http请求方法名": "视图方法名", ...})),
    path("students4/", views.StudentViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students4/(?P<pk>\d+)/$", views.StudentViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),
]

 

GenericViewSet

继承自GenericAPIView和ViewSetMixin,作用让视图集的视图代码变得更加通用,抽离独特代码作为视图类的属性。

使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView

GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIViewViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

视图代码:

 

"""
使用通用视图集类GenericViewSet实现接口中独特代码的分离
"""
from rest_framework.viewsets import GenericViewSet


class StudentGenericViewSet(GenericViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

    def list(self,request):
        """获取多个数据"""
        # 1. 从数据库中读取模型列表信息
        instance_list = self.get_queryset()
        # 2. 实例化序列化器,获取序列化对象
        serializer = self.get_serializer(instance_list, many=True)
        # 3. 使用serializer.data实现对数据进行序列化成字典
        return Response(serializer.data)

    def create(self, request):
        """添加数据"""
        # 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = self.get_serializer(data=request.data)
        # 2. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 3. 返回新增的模型数据经过序列化提供给客户端
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def retrieve(self, request, pk):
        """获取一个数据"""
        # 1. 使用pk作为条件获取模型对象
        instance = self.get_object()
        # 2. 实例化序列化器对象
        serializer = self.get_serializer(instance)
        # 3. 序列化数据并返回结果
        return Response(serializer.data)

    def update(self,request, pk):
        """更新一个数据"""
        # 1. 使用pk作为条件获取模型对象
        instance = self.get_object()
        # 2.获取客户端提交的数据,实例化序列化器,获取序列化对象
        serializer = self.get_serializer(instance, request.data)
        # 3. 反序列化[验证数据、保存数据到数据库]
        serializer.is_valid(raise_exception=True)
        serializer.save()
        # 4. 返回更新后的模型数据经过序列化提供给客户端
        return Response(serializer.data)

    def destroy(self, request, pk):
        """删除一个数据"""
        # 1. 根据PK值获取要删除的数据并删除
        self.get_object().delete()
        # 2. 影响删除结构
        return Response(status=status.HTTP_204_NO_CONTENT)

 

路由代码:

from django.urls import path,re_path
from . import views
urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students1/", views.StudentGenericAPIView.as_view()),
    re_path("^students1/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),

    # GenericAPIView + Mixins
    path("students2/", views.StudentListAPIView.as_view()),
    re_path("^students2/(?P<pk>\d+)/$", views.StudentRetrieveAPIView.as_view()),

    # 视图子类
    path("students3/", views.StuListAPIView.as_view()),
    re_path("^students3/(?P<pk>\d+)/$", views.StuRetrieveAPIView.as_view()),

    # ViewSet
    # 视图集的路由注册格式
    # path("访问路径", views.视图集类名.as_view({"http请求方法名": "视图方法名", "http请求方法名": "视图方法名", ...})),
    path("students4/", views.StudentViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students4/(?P<pk>\d+)/$", views.StudentViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # GenericViewSet
    path("students5/", views.StudentGenericViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students5/(?P<pk>\d+)/$", views.StudentGenericViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),
]

 

结合我们上面学习的模型扩展类,实现简写操作,视图代码:

"""
使用通用视图集类+模型扩展类,直接达到简写api代码的目的
"""
class StudentGenViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,
                        RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

 

路由,代码:

from django.urls import path,re_path
from . import views
urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students1/", views.StudentGenericAPIView.as_view()),
    re_path("^students1/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),

    # GenericAPIView + Mixins
    path("students2/", views.StudentListAPIView.as_view()),
    re_path("^students2/(?P<pk>\d+)/$", views.StudentRetrieveAPIView.as_view()),

    # 视图子类
    path("students3/", views.StuListAPIView.as_view()),
    re_path("^students3/(?P<pk>\d+)/$", views.StuRetrieveAPIView.as_view()),

    # ViewSet
    # 视图集的路由注册格式
    # path("访问路径", views.视图集类名.as_view({"http请求方法名": "视图方法名", "http请求方法名": "视图方法名", ...})),
    path("students4/", views.StudentViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students4/(?P<pk>\d+)/$", views.StudentViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # GenericViewSet
    path("students5/", views.StudentGenericViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students5/(?P<pk>\d+)/$", views.StudentGenericViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # GenericViewSet + 模型扩展类
    path("students6/", views.StudentGenViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students6/(?P<pk>\d+)/$", views.StudentGenViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),
]

 

ModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

视图代码:

"""
ModelViewSet = GenericViewSet + ListModelMixin + CreateModelMixin+
               RetrieveModelMixin + UpdateModelMixin + DestroyModelMixin
"""
from rest_framework.viewsets import ModelViewSet
class StudentModelViewSet(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

 

路由代码:

from django.urls import path,re_path
from . import views
urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students1/", views.StudentGenericAPIView.as_view()),
    re_path("^students1/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),

    # GenericAPIView + Mixins
    path("students2/", views.StudentListAPIView.as_view()),
    re_path("^students2/(?P<pk>\d+)/$", views.StudentRetrieveAPIView.as_view()),

    # 视图子类
    path("students3/", views.StuListAPIView.as_view()),
    re_path("^students3/(?P<pk>\d+)/$", views.StuRetrieveAPIView.as_view()),

    # ViewSet
    # 视图集的路由注册格式
    # path("访问路径", views.视图集类名.as_view({"http请求方法名": "视图方法名", "http请求方法名": "视图方法名", ...})),
    path("students4/", views.StudentViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students4/(?P<pk>\d+)/$", views.StudentViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # GenericViewSet
    path("students5/", views.StudentGenericViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students5/(?P<pk>\d+)/$", views.StudentGenericViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # GenericViewSet + 模型扩展类
    path("students6/", views.StudentGenViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students6/(?P<pk>\d+)/$", views.StudentGenViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # ModelViewSet 模型视图集
    path("students7/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students7/(?P<pk>\d+)/$", views.StudentModelViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),
]

 

ReadOnlyModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin。

视图代码:

"""
ReadOnlyModelViewSet = RetrieveModelMixin + ListModelMixin + GenericViewSet
"""
from rest_framework.viewsets import ReadOnlyModelViewSet


class StudentReadOnlyModelViewSet(ReadOnlyModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer

路由代码:

from django.urls import path,re_path
from . import views
urlpatterns = [
    # APIView
    path("students/", views.StudentAPIView.as_view()),
    re_path("^students/(?P<pk>\d+)/$", views.StudentInfoAPIView.as_view()),

    # GenericAPIView
    path("students1/", views.StudentGenericAPIView.as_view()),
    re_path("^students1/(?P<pk>\d+)/$", views.StudentInfoGenericAPIView.as_view()),

    # GenericAPIView + Mixins
    path("students2/", views.StudentListAPIView.as_view()),
    re_path("^students2/(?P<pk>\d+)/$", views.StudentRetrieveAPIView.as_view()),

    # 视图子类
    path("students3/", views.StuListAPIView.as_view()),
    re_path("^students3/(?P<pk>\d+)/$", views.StuRetrieveAPIView.as_view()),

    # ViewSet
    # 视图集的路由注册格式
    # path("访问路径", views.视图集类名.as_view({"http请求方法名": "视图方法名", "http请求方法名": "视图方法名", ...})),
    path("students4/", views.StudentViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students4/(?P<pk>\d+)/$", views.StudentViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # GenericViewSet
    path("students5/", views.StudentGenericViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students5/(?P<pk>\d+)/$", views.StudentGenericViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # GenericViewSet + 模型扩展类
    path("students6/", views.StudentGenViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students6/(?P<pk>\d+)/$", views.StudentGenViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # ModelViewSet 模型视图集
    path("students7/", views.StudentModelViewSet.as_view({"get": "list", "post": "create"})),
    re_path("^students7/(?P<pk>\d+)/$", views.StudentModelViewSet.as_view({
        "get": "retrieve",
        "put": "update",
        "delete": "destroy",
    })),

    # ReadOnlyModelViewSet  只读视图集
    path("students8/", views.StudentReadOnlyModelViewSet.as_view({"get": "list"})),
    re_path("^students8/(?P<pk>\d+)/$", views.StudentReadOnlyModelViewSet.as_view({"get": "retrieve"})),
]

 

 

 

posted @ 2025-06-24 15:05  minger_lcm  阅读(12)  评论(0)    收藏  举报