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

###################################################认证实现
    自定义认证的类
     """
     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)**
序列化 ****
分页 ***
路由系统 **
视图 **
渲染器 *

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容