【Django学习】(十三)Mixins_各种具体通用类&APIView_ViewSet_GenericViewSet_ModelViewSet类视图继承的父类区别(上)

简介: 【Django学习】(十三)Mixins_各种具体通用类&APIView_ViewSet_GenericViewSet_ModelViewSet类视图继承的父类区别

上一章我们已经学习了如何使用genericapiview实现过滤、排序、分页功能;

这次学习的是如何使用Mixins的各种具体通用类简化代码量

一、自己定义mixins通用类

1、在视图类里,感觉有很多代码都是重复的,是不是可以把公用逻辑提取出来单独封装呢?

答案是可以的!

我们在utils目录下单独创建一个文件mixins.py提取公共部分

#!/usr/bin/python3
# -*- coding: utf-8 -*-
from rest_framework import status
from rest_framework.response import Response
class ListModelMixin:
    def list(self, request, *args, **kwargs):
        qs = self.get_queryset()
        qs = self.filter_queryset(qs)
        page_queryset = self.paginate_queryset(qs)
        if page_queryset is not None:
            serializer_obj = self.get_serializer(instance=page_queryset, many=True)
            return self.get_paginated_response(serializer_obj.data)
        serializer_obj = self.get_serializer(instance=page_queryset, many=True)
        return Response(serializer_obj.data, status=status.HTTP_200_OK)
class CreateModelMixin:
    def create(self, request, *args, **kwargs):
        serializer_obj = self.get_serializer(data=request.data)
        serializer_obj.is_valid(raise_exception=True)
        serializer_obj.save()
        return Response(serializer_obj.data, status=status.HTTP_201_CREATED)
class RetrieveModelMixin:
    def retrieve(self, request, *args, **kwargs):
        pro = self.get_object()
        serializer_obj = self.serializer_class(instance=pro)
        return Response(serializer_obj.data, status=status.HTTP_200_OK)
class UpdateModelMixin:
    def update(self, request, *args, **kwargs):
        # 查出对应id的数据
        query_data = self.get_object()
        serializer_obj = self.serializer_class(instance=query_data, data=request.data)
        serializer_obj.is_valid()
        # 保存更新的数据
        serializer_obj.save()
        return Response(serializer_obj.data, status=status.HTTP_201_CREATED)
class DestroyModelMixin:
    def destroy(self, request, *args, **kwargs):
        ret = {
            "msg": "删除成功!"
        }
        # 根据id查出对应数据
        query_data = self.get_object()
        # 删除指定数据
        query_data.delete()
        # 一般删除数据的输出为None
        return Response(ret, status=status.HTTP_204_NO_CONTENT)

2、然后在视图文件中导入

from utils import mixins
class ProjectsDetailViews(mixins.RetrieveModelMixin,
                          mixins.UpdateModelMixin,
                          mixins.DestroyModelMixin,
                          GenericAPIView):
    queryset = ProjectsModel.objects.all()
    serializer_class = ProjectModelSerializer
    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)
    # 更新数据
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    # 删除数据
    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
# class ProjectsViews(APIView):
class ProjectsViews(mixins.ListModelMixin,
                    mixins.CreateModelMixin,
                    GenericAPIView):
    # 指定当前类视图需要使用的查询集
    queryset = ProjectsModel.objects.all()
    # 指定当前类视图需要使用的序列化器类
    serializer_class = ProjectModelSerializer
    # lookup_field = 'Id'
    # 声明需要使用的引擎类
    filter_backends = [filters.SearchFilter,
                       filters.OrderingFilter
                       ]
    # 定义需要过滤的字段
    search_fields = ['name', 'id']
    # 定义需要排序的字段
    ordering_fields = ['id', 'name']
    # 声明需要使用的分页引擎
    pagination_class = PageNumberPagination
    # 查询全部数据
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    # 创建数据
    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

如图所示,视图类中继承的父类中的顺序要注意:

  • GenericAPIView只能放在最后位置,因为mixins.py公共逻辑文件中很多方法都是需要继承GenericAPIView的,这里面涉及到mro算法
  • 比如获取列表方法中的get_queryset,我们并没有在misins文件中导入对应的包,当在当前文件中找不到这个方法时,就会依次去其他父类中查找,最后在GenericAPIView这个父类中找到
  • 如果GenericAPIView放在最前面,那么可能会导致有些方法找不到

二、使用rest_framework中的mixins通用类

首先我们可以进入到GenericAPIView视图类里去看下,发现里面已经定义好了很多通用接口类

再去看具体的接口请求类里面看,发现继承的是GenericAPIView和rest_framework中mixins.py里的ListModelMixin等一些类(如下图例子)

class ListAPIView(mixins.ListModelMixin,
                  GenericAPIView):
    """
    Concrete view for listing a queryset.
    """
    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

GenericAPIView中的ListAPIView中,返回的是rest_framework中mixins.py里的ListModelMixin的list方法

class ListModelMixin:
    """
    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)

drf框架已经内部定义了一些已经封装好的通用类,而且可以看出代码逻辑和我们自己写的大体上差不多,所以我们可以放心的使用drf框架内的这些封装类以及方法

导入rest_framework中的mixins包:

# from utils import mixins
from rest_framework import mixins

因为 我们之前定义的通用类名/方法名与drf内置的通用类名/方法名一致,所以视图集内的其他代码可以不用变动

三、使用rest_framework的generics.py文件中的通用类

  • 因为通用类中也继承了GenericAPIView,所以视图类里可以不用再继承了,可以删除
  • 因为通用类CreateAPIView和ListAPIView分别继承了rest_framework中的mixins.CreateModelMixin和mixins.ListModelMixin,分别调用了create方法和list方法,所以在视图类里可以不用再自己写各种接口方法了(下面代码块注释掉的部分)

class ProjectsViews(generics.CreateAPIView,
                    generics.ListAPIView,
                    ):
    # 指定当前类视图需要使用的查询集
    queryset = ProjectsModel.objects.all()
    # 指定当前类视图需要使用的序列化器类
    serializer_class = ProjectModelSerializer
    # lookup_field = 'Id'
    # 声明需要使用的引擎类
    filter_backends = [filters.SearchFilter,
                       filters.OrderingFilter
                       ]
    # 定义需要过滤的字段
    search_fields = ['name', 'id']
    # 定义需要排序的字段
    ordering_fields = ['id', 'name']
    # 声明需要使用的分页引擎
    pagination_class = PageNumberPagination
    # 查询全部数据
    # def get(self, request, *args, **kwargs):
    #     return self.list(request, *args, **kwargs)
    #
    # # 创建数据
    # def post(self, request, *args, **kwargs):
    #     return self.create(request, *args, **kwargs)

上面的继承类也可以直接继承generics里的ListCreateAPIView类

class ProjectsViews(generics.ListCreateAPIView):


相关文章
|
2月前
|
JSON 前端开发 API
Django 后端架构开发:通用表单视图、组件对接、验证机制和组件开发
Django 后端架构开发:通用表单视图、组件对接、验证机制和组件开发
52 2
|
2月前
|
JSON 数据处理 API
Django后端架构开发:视图与模板的正确使用
Django后端架构开发:视图与模板的正确使用
15 1
|
1月前
|
数据处理 Python
Django视图:构建动态Web页面的核心技术
Django视图:构建动态Web页面的核心技术
|
2月前
|
C++ Python
Django视图函数VS类视图:如何选择最适合你的开发方式?
【8月更文挑战第31天】本文对比了Django中的函数视图和类视图。函数视图直接处理HTTP请求和响应,灵活且易于维护,适用于简单业务逻辑;类视图基于Python类,提供更丰富的功能和更高的灵活性,适合处理复杂业务逻辑。选择哪种视图取决于具体需求,合理使用两者可帮助你构建高效且易维护的Django应用。
24 0
|
2月前
|
Python
列出 Django 中的继承样式
【8月更文挑战第30天】
30 0
|
2月前
|
Linux Shell 数据库
python Django教程 之 安装、基本命令、视图与网站
python Django教程 之 安装、基本命令、视图与网站
|
2月前
|
安全 API Python
Django 如何使用视图动态输出 CSV 以及 PDF
Django 如何使用视图动态输出 CSV 以及 PDF
43 4
|
3月前
|
API 数据库 数据安全/隐私保护
Django配置api、管理系统和视图
Django配置api、管理系统和视图
80 1
|
2月前
|
测试技术 Shell 数据库
Django视图测试:构建可靠Web应用的关键步骤
Django视图测试:构建可靠Web应用的关键步骤
24 0
|
4月前
|
安全 API Python
Django 如何使用视图动态输出 CSV 以及 PDF
这一篇我们需要用到 python 的 csv 和 reportLab 库,通过django视图来定义输出我们需要的 csv 或者 pdf 文件。