DRF 视图(View) 和 集合(Set) 讲解

DRF 视图

from django.shortcuts import render

# Create your views here.
from rest_framework.response import Response # DRF 中的响应
from students.serializers import StudentModelSerializer # 序列化器
from students.models import Student  # 模型
from rest_framework.views import APIView # 基础视图类
from rest_framework.generics import GenericAPIView # 通用视图类
from rest_framework import status # 响应状态码code

'''APIView 视图类'''
'''
    作用:
        1. 传入Rest_Framework中的Request对象 不是Django中的HttpRequest对象
        2. 传入Rest_Framework中的Response对象 不是Django中的HttpResponse对象
        3. APIException 异常会被捕获到,处理成适合响应的信息
        4. 在dispatch() 路由分发前,会对请求进行身份验证,权限检查,流量控制
    属性
        authentication_classes : 列表/元组,身份认证
        permissoin_classes : 列表/元组,权限检查类
        throttle_classes : 列表/元组, 流量控制类
'''

class StudentAPIView(APIView):

    def get(self, request):
        student_list = Student.objects.all()
        serializer = StudentModelSerializer(instance=student_list, many=True)

        return Response(serializer.data)

    def post(self, request):
        data = request.data
        serializer = StudentModelSerializer(data=data, )
        serializer.is_valid(raise_exception=True)  # 不强制校验错误!
        ret = serializer.save()
        if ret:
            st = status.HTTP_201_CREATED
        else:
            st = status.HTTP_400_BAD_REQUEST

        return Response(serializer.data, status=st)


'''GenericAPIView 通用视图类 '''
'''
    属性:
        queryset : 指定列表视图的查询数据集合
        serializer_class :  指定视图使用的序列化器
        pagination_class :  分页控制类
        filter_backends : 过滤 
        lookup_field  :  查询单一数据对象 时使用的条件字段,默认值是'pk'
        loop_url_kwarg : 查询单一数据时URL中的参数关键名称,默认与lookup_field一致
    
    方法: 
        get_queryset(self)  : 获取所有数据
        get_serializer_class(self)  : 调整序列化器类
        get_serializer(self,args,*kwargs) : 获取序列化器对象
        get_object(self) : 获取一条数据
'''

class StudentGenericAPIView(GenericAPIView):
    '''
        # 必须指定两个参数
            1. 序列化器
            2. 数据集
        # 备注:  对视图类并没有简写 , 需要结合视图扩展类
    '''
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()

    def get(self, request):
        serializer = self.serializer_class(instance=self.get_queryset(), many=True)
        return Response(serializer.data)

    def post(self, request):
        data = request.data
        serializer = self.serializer_class(data=data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data)


'''
# 通用视图类 + 视图混合类 
# 衍生出 四种:
Createmodelmixin  添加一条数据
Listmodelmixin   获取所有数据
Retrievemodelmixin 获取一条数据
Destorymodelmixin   删除一条数据
Updatemodelmixin    更新一条数据
'''
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin

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

    def get(self, request):
        '''
            # 获取所有数据
        :param request:
        :return:
        '''
        return self.list(request)

    def post(self, request):
        '''
            # 保存数据
        :param request:
        :return:
        '''
        return self.create(request)

    def delete(self, request, pk):
        '''
            # 删除一条数据
        :param request:
        :param pk:
        :return:
        '''
        return self.destroy(request, pk)

'''
    ### 基于 通用视图类和 视图混合类衍生
    CreateAPIView    创建一套数据
    ListAPIView      获取所有数据
    RetrieveAPIView  获取一条数据
    DestoryAPIView   删除一条数据
    UpdateAPIView    更新一条数据
    RetrieveUpdateAPIView 更新一条数据 
    RetrieveUpdateDestoryAPIView  更新或删除一条数据
'''

路由

"""DrfDemo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, re_path
from . import views
urlpatterns = [
    path('stu_api_view/',views.StudentAPIView.as_view()),
    path('stu_generic_api_view/',views.StudentGenericAPIView.as_view()),
    re_path('^stu_generic_model_mixin_api_view/$',views.StudentGeneralModelMixinAPIView.as_view()),
    re_path('^stu_generic_model_mixin_api_view/(?P<pk>\d+)/$',views.StudentGeneralModelMixinAPIView.as_view()),
]

DRF集合

from django.shortcuts import render

# Create your views here.
from rest_framework.response import Response

from students.models import Student
from students.serializers import StudentModelSerializer
from rest_framework.viewsets import ViewSet

''' 
    # 基类视图集 : ViewSet
        特点: 
            1. 需要手动指定执行方法 ,如:获取一条数据/获取多条数据
            2. 不同的路由需要在as_view() 方法中指定:http请求方法 反射到 不同的函数 
'''


class StudentAPIViewSet(ViewSet):
    def get_one_data(self, request, pk):
        '''
            # 查询一条数据
        :param request:
        :param pk:
        :return:
        '''
        student_list = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_list)
        return Response(serializer.data)

    def get_all_data(self, request):
        '''
            # 查询所有数据
        :param request:
        :return:
        '''
        student_list = Student.objects.all()
        serializer = StudentModelSerializer(instance=student_list, many=True)

        return Response(serializer.data)


'''
    # 通用视图集合 GenericViewSet
        特点:
            1. 提供了 序列化器 和 模型  , 为了 模型视图集 做铺垫
            2. 需要 手动维护 处理的函数
            2. 需要手动在as_view路由分发函数, 指定 http请求方法 对应的处理视图函数
            
'''

from rest_framework.viewsets import GenericViewSet


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

    def retrieve(self, request, pk):
        '''
            查询一条
        :param request:
        :param pk:
        :return:
        '''
        student = self.get_object()
        serializer = self.get_serializer(instance=student)

        return Response(serializer.data)

    def list(self, request):
        student_list = self.get_queryset()
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)


from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin

'''
    # 通用视图集 和 视图混合类使用
        特点: 
            1. 不需要手动维护 http请求方法对应的 视图处理函数
            2. 需要哪个混合类的功能,需要手动继承
            
'''


class StudentGenericViewSetMixin(GenericViewSet, ListModelMixin, RetrieveModelMixin):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()

    def get_top_2(self, request):
        student_list = self.get_queryset()[:2]
        serializer = self.get_serializer(instance=student_list, many=True)
        return Response(serializer.data)


''' 只读视图集 :ReadOnlyModelViewSet
    特点:
        1. 只提供了 list 和retrieve 2个函数
'''
from rest_framework.viewsets import ReadOnlyModelViewSet


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


'''
    # 模型视图集 StudentModelViewSetMixin
        特点: 
            1. 提供了5个处理函数
'''
from rest_framework.viewsets import ModelViewSet


class StudentModelViewSetMixin(ModelViewSet):
    queryset = Student.objects.all()
    serializer_class = StudentModelSerializer


### Action  : 解决  一个路由和多个处理函数的映射
'''
    # 在 视图集中,因为自定义视图方法的名字会各种各样,需要视图获得客户端请求的视图方法名
      request.action属性来查看      
'''

from rest_framework.decorators import action  # 装饰


class StudentAPIViewSetAction(ViewSet):

    # 为什么: 用到action,是因为视图集中 存在自定义的方法名, 如果自定义函数较多,则路由会越写越多
        #   使用action 通过路由注册的方式,按照drf默认的规则生成 新的路由地址
    # action装饰器 使用:
        # 1. methods 指定 访问的HTTP请求方法,与flask类似
        # 2. detail 表示设置router路由类在生成路由的时候是否要加上 ,主键pk到URL地址栏中
    @action(methods=['get'], detail=True)
    def get_one_data(self, request, pk):
        '''
            # 查询一条数据
        :param request:
        :param pk:
        :return:
        '''
        # print(self.action)  # 获取Action:get_one_data  ,客户端调用通过HTTP调用到的处理视图函数
        student_list = Student.objects.get(pk=pk)
        serializer = StudentModelSerializer(instance=student_list)
        return Response(serializer.data)

    @action(methods=['get'], detail=False)
    def get_all_data(self, request):
        '''
            # 查询所有数据
        :param request:
        :return:
        '''
        student_list = Student.objects.all()
        serializer = StudentModelSerializer(instance=student_list, many=True)

        return Response(serializer.data)

路由

"""DrfDemo URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, re_path
from . import views

urlpatterns = [

    # 视图集 中的方法和地址,以及HTTP请求的绑定都是通过as_view()完成的

    # 基础视图集合  ViewSet
    path('stu_view_set/', views.StudentAPIViewSet.as_view({'get': 'get_all_data'})),
    re_path('stu_view_set/(?P<pk>\d+)/', views.StudentAPIViewSet.as_view({'get': 'get_one_data'})),

    # 通用视图集合  GenericViewSet
    path('stu_generlic_view_set/', views.StudentGenericViewSet.as_view({'get': 'list'})),
    re_path('stu_generlic_view_set/(?P<pk>\d+)/', views.StudentGenericViewSet.as_view({'get': 'retrieve'})),

    # 通用视图集  GenericViewSet 和 视图混合类 ListModelMixin, RetrieveModelMixin
    path('stu_generlic_view_set_mixin/', views.StudentGenericViewSetMixin.as_view({'get': 'list'})),
    path('stu_generlic_view_set_mixin/top/', views.StudentGenericViewSetMixin.as_view({'get': 'get_top_2'})),
    re_path('stu_generlic_view_set_mixin/(?P<pk>\d+)/', views.StudentGenericViewSetMixin.as_view({'get': 'retrieve'})),

    # 只读 视图集 ReadOnlyModelViewSet  (包含 ListModelMixin, RetrieveModelMixin 混合类)
    path('stu_readonly_view_set_mixin/', views.StudentReadOnlyModelViewSetMixin.as_view({'get': 'list'})),
    re_path('stu_readonly_view_set_mixin/(?P<pk>\d+)/',
            views.StudentReadOnlyModelViewSetMixin.as_view({'get': 'retrieve'})),

    # 模型 视图集  StudentModelViewSetMixin (包含所有混合类)
    path('stu_model_view_set_mixin/', views.StudentModelViewSetMixin.as_view({'get': 'list', 'post': 'create'})),
    re_path('stu_model_view_set_mixin/(?P<pk>\d+)/',
            views.StudentModelViewSetMixin.as_view({'get': 'retrieve', 'delete': 'destroy', 'put': 'update'})),

    # ViewSet  ====>Action的查看
    path('stu_view_set_action/', views.StudentAPIViewSet.as_view({'get': 'get_all_data'})),
    re_path('stu_view_set_action/(?P<pk>\d+)/', views.StudentAPIViewSet.as_view({'get': 'get_one_data'})),

]


#### 基于action 装饰器 和 路由类 来生成路由,达到简写的目的
# SimpleRouter    作用: 为视图 生成url路由, 不会生成根目录, <上线使用>
# DefaultRouter   作用: 为视图 生成url路由

from rest_framework.routers import SimpleRouter, DefaultRouter

router = DefaultRouter()
### 注册视图集 ->生成视图集对应的路由方法
    # 1. 格式: router.register('路由前缀','视图集类','可选参数:路由别名前缀')
    # 2. 访问:
        # 访问单一数据 : http://127.0.0.1:8000/viewset/stu_view_set_action_auto/1/get_one_data/
        # 访问多条数据 : http://127.0.0.1:8000/viewset/stu_view_set_action_auto/get_all_data/
router.register('stu_view_set_action_auto', views.StudentAPIViewSetAction,'action')

# print(router.urls)
urlpatterns += router.urls
posted @ 2021-01-16 17:39  染指未来  阅读(465)  评论(0编辑  收藏  举报