接上一篇views.py视图内容整理的最终使用方法,包括自定义action,在api请求时的不同点以及注意事项


from rest_framework.generics import GenericAPIView
from rest_framework.request import Request
from rest_framework import filters
from rest_framework import mixins
from rest_framework import generics
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import status

from .models import Project
from . import serializers
# from .filters import ProjectFilter
from utils.pagination import PageNumberPagination

# from utils import mixins
"""  来自views3.py文件中的内容,针对GenericAPIView类视图
class ProjectView(GenericAPIView):
 可以继承DRF中的APIView视图
 1.APIView为View的子类
 2.每一个实例方法的第二个参数为Request对象
 3.Request在Django的HttpRequest之上做了拓展
     》与HttpRequest中解析参数的方法完全兼容
     》解析查询字符串参数:GET   ->  query_params
     》解析application/x-www-form-urlencoded参数:POST   ->  data
     》解析application/json参数:body   ->  data
     》解析multipart/form-data参数:POST、FILES   ->  data
 4.提供了认证、授权、限流功能
 5.返回DRF中的Response
     》为HttpResponse子类
     》可以自动根据请求头中的Accept字段,返回相应格式的数据
     》data接受序列化输出的数据(字典、嵌套字典的列表)
     》status指定响应状态码
     》headers修改响应头信息(字典)
 6.解析器类
     》提供针对请求头中Content-Type参数,自动解析请求参数
     》默认的解析器有三种:JSONParser(application/json)、FormParser(application/x-www-form-urlencoded)、
         MultiPartParser(multipart/form-data)
     》有两种方式可以修改使用的解析器类:
         方式一:全局settings.py中REST_FRAMEWORK -> DEFAULT_PARSER_CLASSES中指定需要使用的解析器类
         方式二:在具体某个类视图中指定parser_classes类属性(列表),优先级高于方式一

 7.渲染器类
     》提供针对请求头中Accept参数,自动选择需要的渲染器,将数据以特定的格式返回
     》默认的渲染器类有二种:JSONRenderer(application/json)、BrowsableAPIRenderer(text/html)
         如果未指定Accept或者指定的Accept不为text/html,默认返回json数据
     》有两种方式可以修改使用的解析器类:
         方式一:全局settings.py中REST_FRAMEWORK -> DEFAULT_RENDERER_CLASSES中指定需要使用的渲染器类
         方式二:在具体某个类视图中指定renderer_classes类属性(列表),优先级高于方式一

 8.GenericAPIView类视图
     》是APIView的子类,继承了APIView所有功能(认证、授权、限流、Request、Response、解析器、渲染器)
     》提供了获取列表数据的相关功能(过滤、排序、分页)
     》往往需要指定queryset类属性(定义当前类视图操作的查询集对象)
     》往往需要指定serializer_class类属性(定义了当前类视图使用的公共序列化器类)
     》使用get_queryset()方法获取queryset类属性、使用get_serializer()方法获取serializer_class类属性
     》提供了get_object()方法,获取某一个模型对象
     》在定义url路由时,指定接收主键值的关键字参数名称,默认为pk,如果不为pk的话,必须重写lookup_url_kwarg
     》一般lookup_field类属性不需要修改(默认为pk),指定的是过滤模型对象时,使用的关键词参数名称

 9.实现搜索过滤功能
     》指定过滤引擎,有两种方式
         方式一:在全局settings.py中指定DEFAULT_FILTER_BACKENDS(列表,指定过滤引擎的绝对路径字符串)
         方式二:在类视图中filter_backends类属性(列表,指定过滤引擎的引用),优先级高于全局
     》必须指定search_fields类属性,定义待校验的字段(模型类中的字段名字符串),默认忽略大小写的包含过滤
         '^': 'istartswith',
         '=': 'iexact',
         '@': 'search',
         '$': 'iregex',
     》如果不指定search_fields类属性,不会进行搜索过滤
     》调用视图的filter_queryset()方法,对查询集进行过滤,需要接收queryset查询集参数
     》在全局settings.py中使用SEARCH_PARAM参数指定前端过滤查询参数(默认为search)

 10.实现排序过滤功能
     》指定过滤引擎,有两种方式
         方式一:在全局settings.py中指定DEFAULT_FILTER_BACKENDS(列表,指定过滤引擎的绝对路径字符串)
         方式二:在类视图中filter_backends类属性(列表,指定过滤引擎的引用),优先级高于全局
     》必须指定ordering_fields类属性,定义支持排序的字段(模型类中的字段名字符串)
     》如果不指定ordering_fields类属性,那么支持由 serializer_class 属性指定的序列化器上的任何可读字段进行排序
     》指定ordering_fields = '__all__',指定视图应允许对模型的所有字段进行排序
     》指定ordering类属性,定义默认的排序字段;也可以 Projects.objects.all().order_by('name')
     》调用视图的filter_queryset()方法,对查询集进行过滤,需要接收queryset查询集参数
     》在全局settings.py中使用ORDERING_PARAM参数指定前端过滤查询参数(默认为ordering)

 11.实现分页功能
     》指定分页引擎类,有两种方式
         方式一:在全局settings.py中指定DEFAULT_PAGINATION_CLASS(指定分页引擎的绝对路径字符串)
         方式二:在类视图中pagination_class类属性(指定分页引擎的引用),优先级高于全局
     》必须在settings.py中DEFAULT_PAGINATION_CLASS指定PAGE_SIZE参数(指定默认每一页显示的数据条数)或者
         在自定义分页引擎类指定page_size参数,如果未指定,那么分页功能不会开启
     》在获取列表数据实例方法中调用paginate_queryset方法,需要接收queryset查询集对象,会返回嵌套page对象的列表
     》调用get_paginated_response方法将分页数据返回,需要接收serializer.data参数
     》如果需要开启前端能够指定获取每一页的数据条数,往往需要重写分页引擎类PageNumberPagination
         》page_size指定默认每一页数据条数
         》page_query_param设置前端指定页码的查询字符串参数名称
         》page_query_description,对前端指定页码的查询字符串参数的中文描述
         》必须重写page_size_query_param类属性,才能开启前端能够指定获取每一页的数据条数的功能
         》page_size_query_description是page_size_query_param类属性的中文描述
         》max_page_size指定前端每一页数据最大条数的最大值
     》如果需要定制分页数据的返回,那么就需要重写get_paginated_response方法
"""


"""

# 源码中mixins.py文件中的Mixin拓展类
获取列表数据:  ListModelMixin拓展类     ->  list action方法      -> get
创建数据:     CreateModelMixin拓展类   ->  create action方法    -> post
获取详情数据:  RetrieveModelMixin拓展类 ->  retrieve action方法  -> get
更新数据:     UpdateModelMixin拓展类   ->  update action(完整更新)、partial_update action方法(部分更新) -> put、patch
删除数据:     DestroyModelMixin拓展类  ->  destroy action方法   -> delete


# 源码generics.py文件中的APIView具体的通用视图
获取列表数据:  ListAPIView         -> 继承ListModelMixin、GenericAPIView
创建数据:     CreateAPIView       -> 继承CreateModelMixin、GenericAPIView
获取详情数据:  RetrieveAPIView     -> 继承RetrieveModelMixin、GenericAPIView
更新数据:     UpdateAPIView       -> 继承UpdateModelMixin、GenericAPIView
删除数据:     DestroyAPIView      -> 继承DestroyModelMixin、GenericAPIView


# 源码viewsets.py文件中的ModelViewSet视图集, GenericViewSet继承了GenericAPIView和ViewSetMixin,相当于把上面做了一个整合
class ModelViewSet(mixins.CreateModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.ListModelMixin,
                   GenericViewSet):
    A viewset that provides default `create()`, `retrieve()`, `update()`,
    `partial_update()`, `destroy()` and `list()` actions.


# 源码generics.py文件中的APIView具体的混合通用视图
获取列表数据、创建数据:ListCreateAPIView
获取数据详情、更新数据:RetrieveUpdateAPIView
获取数据详情、删除数据:RetrieveDestroyAPIView
获取数据详情、更新数据、删除数据:RetrieveUpdateDestroyAPIView


# 视图集
1.如果需要实现在定义路由条目时,请求方法与要调用的action方法进行一一对应,必须得继承ViewSetMixin
2.ViewSet继承了ViewSetMixin、APIView,具备请求方法与要调用的action方法进行一一对应功能、以及认证授权限流功能,
    但是不支持Mixin,因为没有提供get_object()、get_queryset()、geat_serializer()等方法
3.GenericViewSet继承了ViewSetMixin、GenericAPIView,具备请求方法与要调用的action方法进行一一对应功能、以及支持Mixin拓展类
4.ReadOnlyModelViewSet继承了RetrieveModelMixin、ListModelMixin、GenericViewSet,提供了读取数据的2个接口
5.ModelViewSet继承了CreateModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin、
    ListModelMixin、GenericViewSet,提供了6个接口
6.ViewSetMixin类提供了请求方法与要调用的action方法进行一一对应功能,在定义路由条目时,在as_view()方法中支持接收字典数据,
    把请求方法名称字符串作为key,把具体要调用的action方法名字符串作为值
    
"""


# class RetrieveAPIView(mixins.RetrieveModelMixin, GenericAPIView):
#     # get是请求方法名称
#     # retrieve是action名称
#     def get(self, request, *args, **kwargs):
#         return self.retrieve(request, args, kwargs)
#
#
# class UpdateAPIView(mixins.UpdateModelMixin, GenericAPIView):
#     def put(self, request, *args, **kwargs):
#         # update是一个action,完整更新
#         return self.update(request, args, kwargs)
#
#
# class DestroyAPIView(mixins.DestroyModelMixin, GenericAPIView):
#     def delete(self, request, *args, **kwargs):
#         return self.destroy(request, args, kwargs)


# class ProjectDetailView(generics.RetrieveAPIView, generics.UpdateAPIView, generics.DestroyAPIView):
class ProjectDetailView(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()

    # 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 ProjectView(generics.ListAPIView, generics.CreateAPIView):
class ProjectView(generics.ListCreateAPIView):
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()
    search_fields = ['name', 'leader', 'desc', 'interfaces__name']
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    # filterset_class = ProjectFilter
    pagination_class = PageNumberPagination
    ordering_fields = ['name', 'id', 'leader']

    # def get(self, request: Request, *args, **kwargs):
    #     return self.list(request, args, kwargs)
    #
    # def post(self, request: Request, *args, **kwargs):
    #     return self.create(request, args, kwargs)


# class ProjectAllView(generics.RetrieveUpdateDestroyAPIView, generics.ListCreateAPIView):
#     serializer_class = serializers.ProjectModelSerializer2
#     queryset = Project.objects.all()
#     search_fields = ['name', 'leader', 'desc', 'interfaces__name']
#     filter_backends = [filters.SearchFilter, filters.OrderingFilter]
#     filterset_class = ProjectFilter
#     pagination_class = PageNumberPagination
#     ordering_fields = ['name', 'id', 'leader']


# 需求:将上面5个接口全部放在同一个类视图中
# class ViewSet(ViewSetMixin, views.APIView)
# class ProjectViewSet(viewsets.ViewSet):
# class ProjectViewSet(viewsets.ViewSetMixin, generics.GenericAPIView):
# class ProjectViewSet(viewsets.GenericViewSet):
# class ProjectViewSet(
#         mixins.RetrieveModelMixin,
#         mixins.UpdateModelMixin,
#         mixins.DestroyModelMixin,
#         mixins.ListModelMixin,
#         mixins.CreateModelMixin,
#         viewsets.GenericViewSet):
class ProjectViewSet(viewsets.ModelViewSet):
    serializer_class = serializers.ProjectModelSerializer2
    queryset = Project.objects.all()
    search_fields = ['name', 'leader', 'desc', 'interfaces__name']

    """ search_fields 搜索字段模糊匹配设置
        # 给drf框架搜索引擎支持搜索的字段,见settings.py文件中的REST_FRAMEWORK全局设置
        # http://localhost/projects/?search=100
        进行模糊匹配,支持查询name字段中包含100,leader字段中包含100,desc字段中包含100,项目所关联的接口名称中包含100的内容全部搜索出来
        如果需求中有了变更,需要支持其他字段的搜索,那么就在这个search_fields列表中增加该字段即可,
        同理不需要搜索某字段,直接删除该字段即可,实现了配置的可插拔操作。
        # interfaces__name关联字段,当前项目关联的接口名称,interfaces项目的models.py文件中Interfaces模型类中,
        # projects字段设置的关联字段设置的是related_name='interfaces',所以项目表中通过interfaces__name 就能查询到所有相关的接口名称

         9.实现搜索过滤功能
             》指定过滤引擎,有两种方式
                 方式一:在全局settings.py中指定DEFAULT_FILTER_BACKENDS(列表,指定过滤引擎的绝对路径字符串)
                 方式二:在类视图中filter_backends类属性(列表,指定过滤引擎的引用),优先级高于全局
             》必须指定search_fields类属性,定义待校验的字段(模型类中的字段名字符串),默认忽略大小写的包含过滤
                 '^': 'istartswith',
                 '=': 'iexact',
                 '@': 'search',
                 '$': 'iregex',
             》如果不指定search_fields类属性,不会进行搜索过滤
             》调用视图的filter_queryset()方法,对查询集进行过滤,需要接收queryset查询集参数
             》在全局settings.py中使用SEARCH_PARAM参数指定前端过滤查询参数(默认为search)

    """
    # 过滤搜索和过滤排序设置,filter_backends 搜索过滤设置,使用drf框架中filters的SearchFilter和OrderingFilter类进行实现
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    filter_fields = ['name', 'desc', 'is_execute']
    # ordering_fields 排序字段设置
    ordering_fields = ['name', 'id', 'leader']
    # 在settings.py文件中'ORDERING_PARAM': 'ordering'是给drf框架的排序引擎设置的参数,
    # ordering_fields允许用户指定排序字段'name', 'id', 'leader'
    # 这个是相关的请求方法示例,http:/localhost/projects/?page=2&page_size=3&ordering=-id
    """ filter_fields特定字段精确匹配过滤设置,
        # 请求示例:http://localhost/projects/?name=zhangsanfeng2222
        # filter_backends 过滤搜索和过滤排序设置,使用drf框架中filters的SearchFilter和OrderingFilter类进行实现

         10.实现排序过滤功能
             》指定过滤引擎,有两种方式
                 方式一:在全局settings.py中指定DEFAULT_FILTER_BACKENDS(列表,指定过滤引擎的绝对路径字符串)
                 方式二:在类视图中filter_backends类属性(列表,指定过滤引擎的引用),优先级高于全局
             》必须指定ordering_fields类属性,定义支持排序的字段(模型类中的字段名字符串)
             》如果不指定ordering_fields类属性,那么支持由 serializer_class 属性指定的序列化器上的任何可读字段进行排序
             》指定ordering_fields = '__all__',指定视图应允许对模型的所有字段进行排序
             》指定ordering类属性,定义默认的排序字段;也可以 Projects.objects.all().order_by('name')
             》调用视图的filter_queryset()方法,对查询集进行过滤,需要接收queryset查询集参数
             》在全局settings.py中使用ORDERING_PARAM参数指定前端过滤查询参数(默认为ordering)

    """
    # filterset_class = ProjectFilter
    # filterset_class自定义的过滤器类,因django-filter和当前的python以及drf版本不一致,无法使用该插件,
    # 虽然可以实现各种各样复杂的过滤规则,但是也不太推荐了,查询出来的结果可以让前端人员进行查询渲染
    pagination_class = PageNumberPagination
    """ pagination_class分页过滤设置

         11.实现分页功能
             》指定分页引擎类,有两种方式
                 方式一:在全局settings.py中指定DEFAULT_PAGINATION_CLASS(指定分页引擎的绝对路径字符串)
                 方式二:在类视图中pagination_class类属性(指定分页引擎的引用),优先级高于全局
             》必须在settings.py中DEFAULT_PAGINATION_CLASS指定PAGE_SIZE参数(指定默认每一页显示的数据条数)或者
                 在自定义分页引擎类指定page_size参数,如果未指定,那么分页功能不会开启
             》在获取列表数据实例方法中调用paginate_queryset方法,需要接收queryset查询集对象,会返回嵌套page对象的列表
             》调用get_paginated_response方法将分页数据返回,需要接收serializer.data参数
             》如果需要开启前端能够指定获取每一页的数据条数,往往需要重写分页引擎类PageNumberPagination
                 》page_size指定默认每一页数据条数
                 》page_query_param设置前端指定页码的查询字符串参数名称
                 》page_query_description,对前端指定页码的查询字符串参数的中文描述
                 》必须重写page_size_query_param类属性,才能开启前端能够指定获取每一页的数据条数的功能
                 》page_size_query_description是page_size_query_param类属性的中文描述
                 》max_page_size指定前端每一页数据最大条数的最大值
             》如果需要定制分页数据的返回,那么就需要重写get_paginated_response方法

    """


    # def retrieve(self, request, *args, **kwargs):
    #     instance = self.get_object()
    #     serializer = self.get_serializer(instance=instance)
    #     return Response(serializer.data, status=status.HTTP_200_OK)
    #
    # def update(self, request, *args, **kwargs):
    #     serializer = self.get_serializer(data=request.data, instance=self.get_object())
    #     serializer.is_valid(raise_exception=True)
    #     serializer.save()
    #     return Response(serializer.data, status=status.HTTP_201_CREATED)
    #
    # def destory(self, request, *args, **kwargs):
    #     instance = self.get_object()
    #     instance.delete()
    #     return Response(None, status=status.HTTP_204_NO_CONTENT)
    #
    # 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(instance=page, many=True)
    #         return self.get_paginated_response(serializer.data)
    #
    #     serializer = self.get_serializer(instance=queryset, many=True)
    #     return Response(data=serializer.data, status=status.HTTP_200_OK)
    #
    # def create(self, request, *args, **kwargs):
    #     serializer = self.get_serializer(data=request.data)
    #     serializer.is_valid(raise_exception=True)
    #     serializer.save()
    #     return Response(data=serializer.data, status=status.HTTP_201_CREATED)

    def name_detail(self, request, *args, **kwargs):
        instance = self.get_object()
        return Response({
            'id': instance.id,
            'name': instance.name
        })

    def names(self, request, *args, **kwargs):
        # queryset = self.get_queryset()
        # 1.如果设置的是self.get_queryset()获取的查询集,就不支持上面的过滤和排序功能
        # http://localhost/projects/names_list/?search=11&ordering=id 进行请求时,后面的排序和过滤不起作用

        queryset = self.filter_queryset(self.get_queryset())
        # 2.如果设置的是self.filter_queryset(self.get_queryset())调用filter_queryset进行过滤,获取的查询集,
        # http://localhost/projects/names_list/?search=11&ordering=id 就支持设置的过滤和排序功能
        names = [obj.name for obj in queryset]
        return Response(names)

posted @ 2025-11-19 21:56  大海一个人听  阅读(7)  评论(0)    收藏  举报