zoukankan      html  css  js  c++  java
  • response下的Response的二次封装和视图家族

    自己总结

    继承APIView流程

    APIView类
    as_view(): 就干了一件事:禁用了csrf中间件的安全认证
    dispatch():

    1. 二次封装request对象,将原wsgi的request对象保留至 _request 中
    2. 将数据包中的数据解析到request.data,将url链接?后的数据解析到request.query_params
    3. drf的三大认证
    4. 二次处理响应对象response在返回

    封装Response

    from rest_framework.response import Response
    class APIResponse(Response):
        def __init__(self, data_status, msg, results=None, headers=None, status=None, **kwargs):
            data = {
                'status': data_status,
                'msg': msg,
            }
            if results:
                data['results'] = results
            data.update(kwargs)
            super().__init__(data=data, headers=headers, status=status)
    

    使用:APIResponse(0, 'ok', {}, headers, status)

    允许局部修改

    partial=Ture
    context可以完成视图类给序列化类传参,需要在视图里面写,在序列化类中通过钩子函数中的validate_名字中的self.context.get('名字来捕获')

    局部钩子

    全局钩子

    设置群体资源校验类ListSerializer

    1、在序列化中
    class Meta:
    # 设置群体资源校验类
    list_serializer_class = BooksListSerializer
    2、在群体资源类中
    class BooksListSerializer(serializers.ListSerializer):
    # ListSerializer已提供create的实现体,有特殊需求可以重写
    def create(self, validated_data):
    # print('>>>', validated_data)
    return super().create(validated_data)

    # ListSerializer未提供update的实现体,必须重写
    def update(self, instance, validated_data):
        # print('***', instance, validated_data)
        for index, book_obj in enumerate(instance):
            book_dic = validated_data[index]  # type: dict
            for k, v in book_dic.items():
                if hasattr(book_obj, k):
                    setattr(book_obj, k, v)
            # 同步到数据库
            book_obj.save()
        # print("+++", instance)
        return instance
    

    GenericeAPIView视图

    from rest_framework.generics import GenericAPIView
    继承:GenericAPIView
    1、需要提供queryset和serializer类属性
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BooksModelSerializer
    2、在请求方法中通过self.get_queryset和self.get_serializerl来获取

    主要作用是简化了queryset和serializer_class,将这两个变量提取到了类属性中,但是get、post、put、等方法还是得自己写

    mixins视图工具类

    封装了增删改查5大接口
    from rest_framework import mixins
    继承:mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericAPIView
    CreateModelMixin单增 DestoryModelMixin单删,listModelMIxin群查,RetrieveModelMixin单查,UpdateModelMixin单更
    1、需要提供queryset和serializer类属性
    queryset = models.Book.objects.filter(is_delete=False)
    serializer_class = serializers.BooksModelSerializer
    2、方法都被封装好了,使用只需要调用和继承相应的方法即可,两行

    整合mixins 到 generics 中(ListCreateAPIView)

    不需要自己写功能,只需要提供queryset和serializer类属性即可,单需要继承相应的方法

    viewsets:视图集(重要)

    整合了mixins和viewsets.GenericViewSet
    rom rest_framework import viewsets
    继承:mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet
    1、ViewSetMixin重写了as_view方法,路由层掉用as_view方法就是掉用此方法
    2、能够实现5大接口并且自定义5大接口,即能够实现10大接口
    3、路由层需要传参,传入不同的请求对应部同的方法,来实现分发

    4、通过路由插拔式的方法来根据需求,需要自己写的自己来写方法,不需要的就用系统的方法

    老师笔记

    ListSerializer类:群增 群改

    数据层:还是采用Book、Publish、Author、AuthorDetail四个Model类

    序列化层:

    from rest_framework import serializers
    from . import models
    
    # 利用 ListSerializer 类完成群增群改
    class BooksListSerializer(serializers.ListSerializer):
        # ListSerializer已提供create的实现体,有特殊需求可以重写
        def create(self, validated_data):
            # print('>>>', validated_data)
            return super().create(validated_data)
    
        # ListSerializer未提供update的实现体,必须重写
        def update(self, instance, validated_data):
            # print('***', instance, validated_data)
            for index, book_obj in enumerate(instance):
                book_dic = validated_data[index]  # type: dict
                for k, v in book_dic.items():
                    if hasattr(book_obj, k):
                        setattr(book_obj, k, v)
                # 同步到数据库
                book_obj.save()
            # print("+++", instance)
            return instance
    
    class BooksModelSerializer(serializers.ModelSerializer):
        class Meta:
            # 设置群体资源校验类
            list_serializer_class = BooksListSerializer
    
            # 关联的Model类
            model = models.Book
            fields = ('name', 'price', 'publish', 'authors')
            extra_kwargs = {
                'publish': {
                    'write_only': True
                },
                'authors': {
                    'write_only': True
                },
                'price': {
                    # 数据库字段设置了默认值,也需要 反序列化 时必须提供该字段
                    'required': True,
                    'error_messages': {
                        'required': '价格不能为空',
                    }
                },
                'name': {
                    'min_length': 3,
                    'error_messages': {
                        'min_length': '太短',
                    }
                },
            }
    
        def validate_name(self, value: str):
            # 拿视图类传递过来的参数
            # print(self.context.get('owner'))
            if not value.isidentifier():
                raise serializers.ValidationError('名字非法')
            return value
    
        def validate(self, attrs):
            # 同一出版社书面相同,代表书是同一本,不存入数据库
            name = attrs.get('name')
            publish = attrs.get('publish')
            # print(name, type(name))
            # print(publish, type(publish))
            if models.Book.objects.filter(name=name, publish=publish):
                raise serializers.ValidationError({'%s' % name: '已存在'})
            return attrs
    

    视图层

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import status
    from . import models, serializers
    from utils.response import APIResponse
    class BooksAPIView(APIView):
        # 获取所有 | 一个
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                books_query = models.Book.objects.filter(is_delete=False, pk=pk)
            else:
                books_query = models.Book.objects.filter(is_delete=False).order_by('id')
            books_data = serializers.BooksModelSerializer(books_query, many=True).data
            return APIResponse(0, 'ok', books_data)
    
        # 新增多个 | 一个
        def post(self, request, *args, **kwargs):
            request_data = request.data
            # if isinstance(request_data, list): # 群增
            #     many = True
            # else: # 单增
            #     many = False
            many = True if isinstance(request_data, list) else False
            book_ser = serializers.BooksModelSerializer(data=request_data, many=many)
            if book_ser.is_valid():
                book_obj_list = book_ser.save()
                return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=many).data)
            else:
                return APIResponse(1, 'failed', book_ser.errors)
    
        # 修改一个
        def put(self, request, *args, **kwargs):
            pk = kwargs.get('pk', 1)
            book_obj = models.Book.objects.filter(pk=pk, is_delete=False).first()
            book_ser = serializers.BooksModelSerializer(instance=book_obj, data=request.data)
            if book_ser.is_valid():
                book_obj = book_ser.save()
                return Response({
                    'status': 0,
                    'msg': 'ok',
                    'results': serializers.BooksModelSerializer(book_obj).data
                })
            else:
                return Response({
                    'status': 1,
                    'msg': 'failed',
                    'results': book_ser.errors
                })
    
        # 局部修改多个 | 一个
        """
        def patch(self, request, *args, **kwargs):
            request_data = request.data
            many = True if isinstance(request_data, list) else False
            if many:  # 群改
                pks = [book_dic.pop('pk') for book_dic in request_data]
                # print(pks, request_data)
                book_query = models.Book.objects.filter(pk__in=pks, is_delete=False)
                book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=request_data)
                if book_ser.is_valid():
                    book_obj_list = book_ser.save()
                    return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=True).data)
                else:
                    return APIResponse(1, 'failed', book_ser.errors)
            else:  # 单改
                pk = kwargs.get('pk')
                book_query = models.Book.objects.filter(pk=pk, is_delete=False)
                # partial=True允许操作 局部的反序列化字段
                book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=[request_data])
                # context可以完成视图类给序列化类传递参数
                # book_ser = serializers.BooksModelSerializer(partial=True,instance=book_obj, data=request.data,context={'owner': 'Owen'})
    
                if book_ser.is_valid():
                    book_obj = book_ser.save()
                    return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj, many=True).data)
                else:
                    return APIResponse(1, 'failed', book_ser.errors)
        """
    
        def patch(self, request, *args, **kwargs):
            request_data = request.data
            # 群改:往 /Books/ 发送 [{"pk":1,"name":"西游记"},{"pk":2,"price":"1.00"}]  pk是必须字段
            if isinstance(request_data, list):
                pks = [book_dic.pop('pk') for book_dic in request_data]
            else:  # 单改:往 /Books/(pk)/ 发送 {"name":"西游记"}
                pks = [kwargs.get('pk')]
                request_data = [request_data]
            book_query = models.Book.objects.filter(pk__in=pks, is_delete=False)
            book_ser = serializers.BooksModelSerializer(partial=True, many=True, instance=book_query, data=request_data)
            if book_ser.is_valid():
                book_obj_list = book_ser.save()
                return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=True).data)
            else:
                return APIResponse(1, 'failed', book_ser.errors)
    
    
        # 删除一个 /books/1/ | 删除多个 /books/  数据[1, 2]
        def delete(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:
                pks = [pk]
            else:
                pks = request.data
            delete_rows = models.Book.objects.filter(pk__in=pks, is_delete=False).update(is_delete=True)
            if delete_rows != 0:
                return APIResponse(0, 'ok')
            return APIResponse(1, '删除失败')
    

    视图家族:

    数据层、序列化层:不变

    视图层:

    """
    generics:视图类
    重点:将 queryset对象 与 serializer对象 封装成类属性
    
    mixins:视图工具集
    重点:通过list、create、update、destroy、retrieve五大功能(依赖generics类)
    
    viewsets:视图集
    重点:通过ViewSetMixin完成请求方法的自定义映射(整合mixins、 generics、ViewSetMixin)
    """
    
    from rest_framework.generics import GenericAPIView
    from . import models, serializers
    from utils.response import APIResponse
    
    # generics:视图类
    class BooksGenericAPIView(GenericAPIView):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BooksModelSerializer
        # lookup_field = 'pk'  # 与urls中的有名分组,有名分组为pk可以省略
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if not pk:
                book_query = self.get_queryset()
                book_ser = self.get_serializer(book_query, many=True)
                return APIResponse(0, 'ok', book_ser.data)
            else:
                book_obj = self.get_object()
                book_ser = self.get_serializer(book_obj)
                return APIResponse(0, 'ok', book_ser.data)
    
    
    # mixins:视图工具集
    from rest_framework import mixins
    class BooksMixinsGenericAPIView(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericAPIView):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BooksModelSerializer
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if not pk:
                return self.list(request, *args, **kwargs)
            else:
                return self.retrieve(request, *args, **kwargs)
    
    
    # 整合mixins 到 generics 中:不需要自己写功能
    from rest_framework.generics import ListCreateAPIView, RetrieveAPIView
    class BooksListAPIView(ListCreateAPIView):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BooksModelSerializer
    
    
    # 重点
    # viewsets:视图集(整合mixins 到 generics)、
    from rest_framework import viewsets
    class BooksGenericViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
        queryset = models.Book.objects.filter(is_delete=False)
        serializer_class = serializers.BooksModelSerializer
    
        def create_many_or_one(self, request, *args, **kwargs):
            request_data = request.data
            many = True if isinstance(request_data, list) else False
            book_ser = serializers.BooksModelSerializer(data=request_data, many=many)
            if book_ser.is_valid():
                book_obj_list = book_ser.save()
                return APIResponse(0, 'ok', serializers.BooksModelSerializer(book_obj_list, many=many).data)
            else:
                return APIResponse(1, 'failed', book_ser.errors)
    

    路由层

    from django.conf.urls import url, include
    from . import views
    urlpatterns = [
        url(r'^v1/books/$', views.BooksGenericAPIView.as_view()),
        url(r'^v1/books/(?P<pk>d+)/', views.BooksGenericAPIView.as_view()),
        url(r'^v2/books/$', views.BooksMixinsGenericAPIView.as_view()),
        url(r'^v2/books/(?P<pk>d+)/', views.BooksMixinsGenericAPIView.as_view()),
        url(r'^v3/books/$', views.BooksListAPIView.as_view()),
        url(r'^v3/books/(?P<pk>d+)/', views.BooksListAPIView.as_view()),
        # 重点:
        url(r'^v4/books/$', views.BooksGenericViewSet.as_view({'get': 'list', 'post': 'create_many_or_one'})),
        url(r'^v4/books/(?P<pk>d+)/', views.BooksGenericViewSet.as_view({'get': 'retrieve'})),
    ]
    

    路由组件:了解

    from django.conf.urls import url, include
    from . import views
    
    from rest_framework.routers import SimpleRouter
    router = SimpleRouter()
    router.register('books', views.BooksGenericViewSet, base_name='book')
    
    # url(r'^v1/books/$', views.BooksGenericAPIView.as_view()),
    # url(r'^v1/books/(?P<pk>d+)/', views.BooksGenericAPIView.as_view()),
    # 第一种方式
    urlpatterns = []
    urlpatterns.extend(router.urls)
    
    # 第二种方式
    urlpatterns = [
        url(r'^', include(router.urls)),
    ]
    
  • 相关阅读:
    第二周学习总结
    第一周学习进度总结
    淘宝网质量属性分析
    软件架构师如何工作
    寒假学习记录第十六天
    寒假学习记录第十五天
    寒假学习记录第十四天
    寒假学习记录第十三天
    三.NFS存储服务
    二.Rsync备份服务
  • 原文地址:https://www.cnblogs.com/huanghongzheng/p/11369574.html
Copyright © 2011-2022 走看看