美文网首页
DRF十大组件的作用和使用方法

DRF十大组件的作用和使用方法

作者: _Clown_ | 来源:发表于2019-08-04 19:06 被阅读0次
    ###################################################认证实现
        自定义认证的类
         """
         from rest_framework.authentication import BaseAuthentication
         from rest_framework.exceptions import AuthenticationFailed
         from authapp.models import UserToken
         class MyOrderAuthentication(BaseAuthentication):
                在这里实现认证的逻辑
             def authenticate(self, request):
                 token = request._request.GET.get('token')
                 # 获取到token之后,需要在数据库中查找token
                 obj = UserToken.objects.filter(token=token).first()
                 if not obj:
                     # 没有通过认证
                     raise AuthenticationFailed('认证失败')
                 # 返回元组( user, auth )
                 return (obj.user, obj)
         """
     
        使用局部配置(在视图函数中)
         """
         class OrderView(APIView):
             # 通过authentication_classes设置认证类
             authentication_classes = [MyOrderAuthentication,]
             # 通过authentication_classes设置为空列表,就不再进行认证了
             # authentication_classes = []
         """
     
        全局配置
         """
         REST_FRAMEWORK = {
             'DEFAULT_AUTHENTICATION_CLASSES':['unitls.authentication.MyOrderAuthentication'],
         }
         """
     
        设置匿名用户
         """
         REST_FRAMEWORK = {
             'UNAUTHENTICATED_USER': lambda :"匿名用户",
             'UNAUTHENTICATED_TOKEN': lambda :'123456',
         }
         """
     
        ## 最最重要的,理清认证的源代码
     
     
    ################################################################权限
     权限
     
       自定义权限类
       """
         from rest_framework.permissions import BasePermission
         class MyOrderPermission(BasePermission):
             #自定义权限认证的类,必须要实现has_permission方法
             message = '你不是超级用户,没有权限访问'
             def has_permission(self, request, view):
             
                 #Return `True` if permission is granted, `False` otherwise.
                 #返回True表示有权限访问,返回False表示没有权限访问
                 if request.user.user_type != 3:
                     return False
                 return True
       """
     
       局部使用
       """
        class OrderView(APIView):
        
             # permission_classes设置权限类
             permission_classes = [MyOrderPermission,]
             # 通过authentication_classes设置为空列表,就不再进行权限认证了
             permission_classes = []
       """
     
       全局的设定
       """
        REST_FRAMEWORK = {
           'DEFAULT_PERMISSION_CLASSES':['unitls.permission.MyOrderPermission'],
        }
       """
       
       最最重要的,理清权限认证的源代码
     
     
    ##############################################################节流
    节流:
       自定义节流类
       """
        VISIT_RECORD = {}
        class VisitThrottle(object):
            def __init__(self):
                self.history = None
            def allow_request(self,request,view):
                #实现节流的逻辑
                #基于ip做节流
                # #获取用户访问的IP地址
                # ip_address = request._request.META.get('REMOTE_ADDR')
                ctime = time.time()
                # if ip_address not in VISIT_RECORD:
                #     #第一次访问的时候将访问的时间存储在字典中(ip地址为Key,访问的时间为value值)
                #     VISIT_RECORD[ip_address] = [ctime,]
                #
                # #第二次访问的时候取出访问的历史记录
                # history = VISIT_RECORD[ip_address]
                # 基于用户的节流
                username = request.user.username
                if username not in VISIT_RECORD:
                    VISIT_RECORD[username] = [ctime, ]
                history = VISIT_RECORD[username]
                self.history = history
                while history and history[-1] < ctime - 10:
                    #如果访问的时间记录超过60秒,就把超过60秒的时间记录移除
                    history.pop()
                if len(history) < 6:
                    history.insert(0,ctime)
                    return True
                return False
            def wait(self):
                #一旦用户访问次数到达阀值,显示用户需要等待的时间
                ctime = time.time()
                            #09:54:30    09:54:28
                return 10 - (ctime - self.history[-1])
       """
     
       局部使用
       """
           class OrderView(APIView):
               # throttle_classes设置节流类
               throttle_classes = [VisitThrottle,]
       """
               
       全局设置
       """
        REST_FRAMEWORK = {
           'DEFAULT_THROTTLE_CLASSES':['unitls.throttle.VisitThrottle'],
        }
       """
       
       使用DRF内置的限频类
        """
        from rest_framework.throttling import SimpleRateThrottle
        
        #推荐使用这种
        class VisitThrottle(SimpleRateThrottle):
            #没有登录用户,每分钟访问10次
            scope = 'logined'
            def get_cache_key(self, request, view):
            return request.user.username
        """
     
       全局设置
        """
        REST_FRAMEWORK = {
            'DEFAULT_THROTTLE_RATES':{
                'unlogin':'10/m',
                'logined':'3/m',
            },
            'DEFAULT_THROTTLE_CLASSES':['unitls.throttle.VisitThrottle'],
        }
        """
     
     
    #########################################################
    关于版本控制
        自定义版本控制类
        """
            class ParmasVersion(object):
                def determine_version(self, request, *args, **kwargs):
                    version = request.query_params.get('version')
                    return version
        """
     
        使用(局部)
        """
            class VersionView(APIView):
                #设置获取版本的类
                versioning_class = ParmasVersion
        """
     
        全局设置
        """
             'DEFAULT_VERSIONING_CLASS':'unitls.version.ParmasVersion',
        """
     
        使用 DRF内置的版本控制类QueryParameterVersioning(局部)
        """
            from rest_framework.versioning import QueryParameterVersioning
            class VersionView(APIView):
                #设置获取版本的类
                versioning_class = QueryParameterVersioning
        """
        
        设置文件中的配置信息
        """
            REST_FRAMEWORK = {
                'VERSION_PARAM':'version',
                'DEFAULT_VERSION':'v1',
                'ALLOWED_VERSIONS':['v1','v2'],
            }
        """
     
        全局设置
        """
            REST_FRAMEWORK = {
                'VERSION_PARAM':'version',
                'DEFAULT_VERSION':'v1',
                'ALLOWED_VERSIONS':['v1','v2'],
                'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.QueryParameterVersioning',
            }
        """
     
     
        使用 DRF内置的版本控制类URLPathVersioning(局部)
        """
            from rest_framework.versioning import URLPathVersioning
            class VersionView(APIView):
                #设置获取版本的类
                versioning_class = URLPathVersioning
            """
        
        设置文件中的配置信息
        """
            REST_FRAMEWORK = {
                'VERSION_PARAM':'version',
                'DEFAULT_VERSION':'v1',
                'ALLOWED_VERSIONS':['v1','v2'],
            }
            """
        
        全局设置
        """
            REST_FRAMEWORK = {
                'VERSION_PARAM':'version',
                'DEFAULT_VERSION':'v1',
                'ALLOWED_VERSIONS':['v1','v2'],
                'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
            }
        """
     
        如果使用URLPathVersioning,路由格式如下
        """
            url(r"^(?P<version>[v1|v2]+)/version/",VersionView.as_view(),name='vvvv')
        """
     
        #使用 DRF内置的版本控制类URLPathVersioning 反向生成url地址
        """
            #反向生成url地址 reverse
            obj = request.versioning_scheme
            url1 = obj.reverse(viewname='orders',request=request)
            
            #使用django的reverse方法反响生成url地址
            from django.urls import reverse
            url2 = reverse(viewname='orders',kwargs={'version':'v2'})
        """
     
    #################################################解析器
     
    因为开发人员post请求上传数据时,传递的数据类型不同,我们可能在request._request.POST中获取不到数据
     
        case1: Content-Type : application/x-www-form-urlencoded
        服务端接收到的post请求的数据格式:username=xxxxx&age=18&sex=男
        我们就可以在request._request.POST中获取到数据
        """
            class UserInfoView(APIView):
                def post(self,request,*args,**kwargs):
                    username = request._request.POST.get('username')
                    age = request._request.POST.get('age')
                    sex = request._request.POST.get('sex')
        """
     
        case2:Content-Type:application/json
        服务端接收到的post请求的数据格式就是json数据:{"username":"xxxx","age":"18","sex":"男"}
        在request._request.POST中就获取不到数据,但是在request.body中可以拿到
        """
            class UserInfoView(APIView):
                def post(self,request,*args,**kwargs):
                    import json
                    data = json.loads(request.body.decode('utf8'))
                    print(data)
        """
     
        DRF内置的解析器FormParser,JSONParser
        使用(局部):
        """
           from rest_framework.parsers import FormParser,JSONParser
           class UserInfoView(APIView):
                parser_classes = [FormParser,JSONParser]
                
                #这时DRF 内部代码会根据request.Content-Type和解析器支持的media_type比较
                从而选择对应的解析器
                
                def post(self,request,*args,**kwargs):
                    # 如果使用JSONParser、FormParser解析数据的话
                    data = request.data
                    print(data)
                
        """
     
        使用(全局配置解析器):
     
     
    #############################################################
    关于序列化
        Django的序列化
        """
        #django序例化方式一
        books = models.BookInfo.objects.all().values('id','bookname')
        books = list(books)
        print(type(books), books)
        self.ret['books'] = books
        #django序例化方式二
        books = models.BookInfo.objects.all()
        books = [model_to_dict(item) for item in books]
        self.ret['books'] = books
        """
     
        DRF 序列化
        第一种:继承自serializers.Serializer
        """
             class BookDetailSerializer(serializers.Serializer):
                     # 正常的字段序列化
                     id = serializers.IntegerField()
                     bookname = serializers.CharField()
                     author = serializers.CharField()
                     category = serializers.IntegerField()
                     bookdesc = serializers.CharField()
                     
                     
                     # 获取枚举类型的文本是 source=get_字段名_display
                     status = serializers.CharField(
                         source='get_status_display'
                     )
                     categoryname = serializers.CharField(
                         source='get_category_display'
                     )
                     
                     # 自定义方法获取字段
                     chpaters = serializers.SerializerMethodField()
                     #序列化时可以自定义方法获取字段
                     def get_chpaters(self,row):
                         """ row - > bookinfo """
                             chpaters = models.ChpaterInfo.objects.filter(book=row)
                             ser = ChpaterSerializer(instance=chpaters,many=True,
                                                     context=self.context
                                                     )
                             return ser.data
        """
         序列化时生成url
        """
            url = serializers.HyperlinkedIdentityField(
            view_name='chpaterdetail', lookup_field='id',
            lookup_url_kwarg='pk',
            )
        """
        注意:如果序列化类中使用HyperlinkedIdentityField生成url,那我们在序例化时添加context={'request': request}
        """
            ser = BookDetailSerializer(
            instance=obj,many=False,
            context={'request': request}
            )
        """
     
        如果出现关联关系时,获取model对像的某一个字段
        """
            bookname = serializers.CharField(source='book.bookname')
        """
     
        第二种继承自:serializers.ModelSerializer
        """
        class ChpaterDetailSerializer(serializers.ModelSerializer):
            #使用ModelSerializer进行章节详情的序列化
            bookname = serializers.CharField(source='book.bookname')
            class Meta:
                model = models.ChpaterInfo
                #fields = "__all__"
                fields = ['id','bookname']
        """
        
        DRF (序列化时)自定义方法获取数据
        """
            book = serializers.SerializerMethodField()
        """
        """
             def get_book(self,row):
                 """ row - > UserInfo"""
                     print('======',row.book.all())
                     ser = UsersBooksSerializer(
                         instance=row.book.all(),
                         many=True
                     )
                
                     return ser.data
        """
        
        DRF depth深度的使用
        # depth会根据关联的数据不停的深入将数据获取出来(最多不超过10层)
        # depth = 1
        """
        class UsersSerializer(serializers.ModelSerializer):
            class Meta:
                model = models.UserInfo
                fields = "__all__"
                #depth会根据关联的数据不停的深入将数据获取出来(最多不超过10层)
                depth = 1
        """
     
        DRF序列化的验证功能
        """
        class UsersSerializer(serializers.ModelSerializer):
            #自定义验证错误的信息
            username = serializers.CharField(error_messages={'required':'用户名不能为空'})
            class Meta:
                model = models.UserInfo
                fields = "__all__"
        """
     
        """
        class UsersView(APIView):
            def post(self,request,*args,**kwargs):
            """DRF 序列化自带验证功能"""
                data = request.data
                #print(data)
                ser = UsersSerializer(data=data)
                if ser.is_valid(): # ser.is_valid()y验证数据的有效性
                    print('验证后的数据',ser.validated_data)
                    #验证后的数据正确后,保存数据至数据库
                    ser.save()
                else:
                    #上传数据不符合规范时ser.errors,返回错误详细
                    print(ser.errors)
                return Response(data)
        """
     
        自定义字段验证规则
        """
            class UsersInfoSerializer(serializers.ModelSerializer):
            username = serializers.CharField(error_messages={'required':'用户名不能为空'})
                class Meta:
                    model = models.UserInfo
                    fields = "__all__"
                
                # 用户名中必须包含老王两个字,不包含则认为名字无效
                def validate_username(self,validated_value):
                    print(validated_value)
                    from rest_framework.exceptions import ValidationError
                    if '老王' not in validated_value:
                    #验证不通过,抛出异常
                        raise ValidationError('用户名不合法')
                    #验证通过,返回数据
                    return validated_value
        """
     
    #########################################分页
     
      自定义分页类PageNumberPagination
        # 自定制分页类
        class MyPageNumberPagination(PageNumberPagination):
            """http://127.0.0.1:8000/api/userpage/?page=1&pagesize=10"""
            # page_size每一返回多少条
            page_size = 5
            # 设置分页的参数名
            page_query_param = 'page'
            # 设置每页返回数据量的参数名
            page_size_query_param = 'pagesize'
            # 设置每页最大返回的条数
            max_page_size = 6
     
      使用
          class UsersPageView(APIView):
              
              def get(self,request,*args,**kwargs):
                  # 获取表中所有用户的row(记录)
                  obj = models.UserInfo.objects.all()
                  #实例化分页的类
                  #page_obj = PageNumberPagination()
                  page_obj = MyPageNumberPagination()
                  #获取分页数据
                  page_data = page_obj.paginate_queryset( queryset=obj,request=request,view=self)
                  # 序列化
                  ser = UsersSerializer(instance=page_data,many=True)
     
                  # return Response(ser.data)
                  #get_paginated_response会返回上一页下一页和总条数
                  return page_obj.get_paginated_response(ser.data)
     
        自定义分页类LimitOffsetPagination
        from  rest_framework.pagination import LimitOffsetPagination
     
        class MyLimitOffsetPagination(LimitOffsetPagination):
            """http://127.0.0.1:8000/api/userpage/?limit=10&offset=0"""
            default_limit = 5
            limit_query_param = 'limit'
            offset_query_param = 'offset'
            max_limit = 7
     
        
        自定义分页类CursorPagination(会对分页参数进行加密)
        from  rest_framework.pagination import CursorPagination
     
        class MyCursorPagination(CursorPagination):
            """http://127.0.0.1:8000/api/userpage/?cursor=cD01"""
            cursor_query_param = 'cursor'
            page_size = 4
            #返回数据市的排序的方式
            ordering = '-id'
            max_page_size = 8
     
         设置全局的分页
         """
             REST_FRAMEWORK = {
                 'DEFAULT_PAGINATION_CLASS':'unitl.pagination.MyCursorPagination',
                 'PAGE_SIZE':3
             }
         """
     
     
    ###########################
    视图
        以前 (Django的View)
        """
            class MyView(View)
                .....
        """
     
        现在(rest_framework的APIView)
        """
            class MyView(APIView)
            .....
        """
        
        其他视图的使用
        第一个:GenericAPIView 视图的使用 (跟继承自APIViewq其实一样,只是我们在外面逻辑,
            GenericAPIView在内部c定制方法帮我们实现了)
        """
        from rest_framework.generics import GenericAPIView
        class BookinfoSeralizer(serializers.ModelSerializer):
            
            class Meta:
                model = models.BookInfo
                fields = "__all__"
        class BookView(GenericAPIView):
            # queryset: 设置获取的数据
            queryset = models.BookInfo.objects.all()
            # serializer_class: 设置序列化的类
            serializer_class = BookinfoSeralizer
            # pagination_class : 设置分页的类
            pagination_class = MyPageNumberPagination
            def get(self,request,*args,**kwargs):
                obj = self.get_queryset() #=> obj = models.BookInfo.objects.all()
                # 获取当前分页的数据
                page_data = self.paginate_queryset(obj) #=>page_obj = MyPageNumberPagination() #获取分页数据page_data = page_obj.paginate_queryset()
                # 获取序列化之后的数据
                ser = self.get_serializer(instance=page_data,many=True) #->ser = BookinfoSeralizer(instance=page_data,many=True)
                return Response(ser.data)
        """
            
         第二个:GenericViewSet 视图的如下使用,注意路由会发生变化
            """
            class BookView(GenericViewSet):
                # queryset: 设置获取的数据
                queryset = models.BookInfo.objects.all()
                # serializer_class: 设置序列化的类
                serializer_class = BookinfoSeralizer
                # pagination_class : 设置分页的类
                pagination_class = MyPageNumberPagination
                
                def list(self,request,*args,**kwargs):
                    
                    obj = self.get_queryset() #=> obj = models.BookInfo.objects.all()
                    # 获取当前分页的数据
                    page_data = self.paginate_queryset(obj) #=>page_obj = MyPageNumberPagination() #获取分页数据page_data = page_obj.paginate_queryset(
                    # 获取序列化之后的数据
                    ser = self.get_serializer(instance=page_data,many=True) #->ser = BookinfoSeralizer(instance=page_data,many=True)
                    
                    return Response(ser.data)
            """
            路由会发生变化,配置如下
            """
            url(r"bookpage/$",views.BookView.as_view({'get': 'list'}),name='bookpage')
            """
            
            第三个:ListModelMixin,CreateModelMixin,RetrieveModelMixin,
            DestroyModelMixin,UpdateModelMixin 等视图的使用
            
            """
            from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin
            from rest_framework.viewsets import GenericViewSet
            # ListModelMixin : 返回列表数据据( get请求)
            # CreateModelMixin  : 新增一条数据 (Post请求)
            # RetrieveModelMixin,  : 获取详情数据 (get请求)
            # DestroyModelMixin,   : 删除数据的时候 (delete)
            # UpdateModelMixin  : 跟新数据的时候使用 (put)
     
            class BookView(ListModelMixin,RetrieveModelMixin,CreateModelMixin,DestroyModelMixin,UpdateModelMixin,GenericViewSet):
                # queryset: 设置获取的数据
                queryset = models.BookInfo.objects.all()
                # serializer_class: 设置序列化的类
                serializer_class = BookinfoSeralizer
                # pagination_class : 设置分页的类
                pagination_class = MyPageNumberPagination
            """
            第四个:ModelViewSet视图的使用
            ModelViewSet继承自istModelMixin,CreateModelMixin,
            RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin视图
            如果要实现最基本的增删改查功能,就直接继承自ModelViewSet
            """
            from rest_framework.viewsets import ModelViewSet
            class BookView(ModelViewSet):
                # queryset: 设置获取的数据
                queryset = models.BookInfo.objects.all()
                # serializer_class: 设置序列化的类
                serializer_class = BookinfoSeralizer
                # pagination_class : 设置分页的类
                pagination_class = MyPageNumberPagination
            """
            视图使用小总结
                只想实现简单的增删改查
                    ModelViewSet
                只想增
                    CreateModelMixin,GenericViewSet
                只想增删改
                    CreateModelMixin,DestroyModelMixin,UpdateModelMixin,GenericViewSet
                如果视图中的业务逻辑复杂,以上都不能满足的时候,直接使用
                    APIView
         #自动路由配置
         """
             from django.conf.urls import url,include
             from api import views
             from rest_framework import routers
             
             router = routers.DefaultRouter()
             router.register(r"bookpage",views.BookView,base_name='bookpage')
             
             
             urlpatterns = [
                url(r'v1/',include(router.urls)),
             ]
         """
             
        自动路由会生成四个接口
        ^api/ v1/ ^bookpage/$ [name='bookpage-list']
        ^api/ v1/ ^bookpage\.(?P<format>[a-z0-9]+)/?$ [name='bookpage-list']
        ^api/ v1/ ^bookpage/(?P<pk>[^/.]+)/$ [name='bookpage-detail']
        ^api/ v1/ ^bookpage/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='bookpage-detail']
    ##############################渲染器
        INSTALLED_APPS = [
                          'rest_framework',
                         ]
        from rest_framework.renderers import BrowsableAPIRenderer,JSONRenderer,AdminRenderer
        class BookView(ModelViewSet):
            # 设置渲染器类型
            renderer_classes = [JSONRenderer]
    ############################################
    认证 ***
    权限(授权) ***
    用户访问次数/频率限制 ***
    版本 ***
    解析器(parser)**
    序列化 ****
    分页 ***
    路由系统 **
    视图 **
    渲染器 *
    
    

    相关文章

      网友评论

          本文标题:DRF十大组件的作用和使用方法

          本文链接:https://www.haomeiwen.com/subject/xowydctx.html