1. 程式人生 > 實用技巧 >drf十大元件

drf十大元件

認證

  • 作用,檢測使用者是否登入
  • 在檢視類中配置 authentication_classes = [] 這是一個列表
  • 需要實現 authenticate() 方法
自定義認證類
 #自定義認證類(繼承自object)
    class MyBaseAuthentication(Object):
    
        def authenticate(self, request):
            #完成認證邏輯
            
        def authenticate_header(self, request):
            pass

    #自定義認證類(繼承自BaseAuthentication)
    from rest_framework.authentication import BaseAuthentication
    from rest_framework.exceptions import AuthenticationFailed
    class MyBaseAuthentication(BaseAuthentication):
        
        def authenticate(self, request):
            #完成認證邏輯
區域性配置
 #區域性配置配置(在檢視中配置)
    # 登入使用者才能訪問所有註冊使用者列表(區域性使用設定)
    authentication_classes = [MyBaseAuthentication,]

    #設定為空列表,就不走認證流程了(全域性設定後,要想單個檢視不走認證)
    authentication_classes = []
全域性配置
#全域性設定
    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES':['util.authentication.MyBaseAuthentication',],
    }

    #匿名使用者(使用者未登入的情況下,可以設定匿名使用者資訊( user、auth))
    # 必要條件:不管是全域性還是檢視中都沒有設定認證類
    REST_FRAMEWORK = {
        'UNAUTHENTICATED_USER':lambda :'匿名使用者',
        'UNAUTHENTICATED_TOKEN':lambda :'1234',
    }

許可權

  • 作用:某些介面只能是特定的使用者才能訪問
  • 在檢視類中配置permission_classes = [] 這是一個列表
  • 需要實現 has_permission() 方法,表示全部物件對資源的許可權問題
  • 還有一個 has_object_permission() 表示某個物件是否對資源有許可權
  • 返回 True 或 False,True 表示有許可權,False 表示 無
  • 全域性配置 DEFAULT_PERMISSION_CLASSES,認證類中屬性 message,表示無許可權時返回的內容
  • 許可權自定義類最好繼承 BasePermission
自定義許可權類
#自定義許可權類(Object)
     class MyPermission(object):
         message = 'vip使用者才能訪問'
         def has_permission(self,request,view):
             #完成許可權邏輯
             #返回True,表示有許可權訪問
             #返回Flase,表示沒有許可權訪問

    #自定義許可權類(BasePermission)
    from rest_framework.permissions import BasePermission
    class MyPermission(BasePermission):
            message = 'vip使用者才能訪問'
            def has_permission(self,request,view):
                #完成許可權邏輯
                #返回True,表示有許可權訪問
                #返回Flase,表示沒有許可權訪問
區域性設定
 #設定許可權類(區域性使用設定)
    # permission_classes = [MyPermission,]

    #設定為空列表,就不走許可權流程了(全域性設定後,要想單個檢視不走許可權設定了)
    # permission_classes = []
全域性設定
#全域性設定
   REST_FRAMEWORK = {
       'DEFAULT_PERMISSION_CLASSES':['util.permission.MyPermission',],
   }

節流

  • 作用:根據使用者的ip地址使用者的唯一標示限制使用者的訪問頻率
  • 在檢視類中配置 throttle_classes= [] 這是一個列表
  • 實現 allow_request 方法 wait 是一個提示方法
  • 返回 True/False。True 可以繼續訪問,False 表示限制
  • 全域性配置 DEFAULT_THROTTLE_CLASSE,DEFAULT_THROTTLE_RATES 表示 頻率限制,比如 10/m 表示 每分鐘 10 次
自定義(Object)
RECORD_VISITS = {}
    class VisitThrottle(object):
        def __init__(self):
            #獲取使用者的訪問歷史
            self.history = []
        
        def allow_request(self, request, view):
            #allow_request是否允許方法
            #True 允許訪問
            #False 不允許訪問
            #獲取使用者的IP地址
            # ip_adress = request._request.META.get('REMOTE_ADDR')
            # key = ip_adress
            
            #基於使用者
            token = request.auth
            key = token
            
            currenttime = time.time()
            if key not in RECORD_VISITS:
                #當前的IP地址沒有訪問過伺服器
                RECORD_VISITS[key] = [currenttime]
                return True
            #獲取訪問歷史記錄
            visit_history = RECORD_VISITS[key]
            self.history = visit_history
        
            while visit_history and visit_history[-1] < currenttime - 60:
                visit_history.pop()

        if len(visit_history) < 10:
            #每分鐘訪問10次
            visit_history.insert(0,currenttime)
            return True
                
        return False  # False表示訪問頻率太高被限制
        
        def wait(self):
            first_time = self.history[-1]
            return 60 - (time.time() - first_time)
自定義(SimpleRateThrottle)
class MySimpleRateThrottle(SimpleRateThrottle):
        scope = 'unlogin'
        def get_cache_key(self, request, view):
            #根據ip或者使用者標示獲取使用者的訪問記錄
            return self.get_ident(request)
            #  return request.user.name
區域性設定
 #設定節流的類(區域性使用設定)
        throttle_classes = [VisitThrottle,]
        throttle_classes = [MySimpleRateThrottle,]

        #設定為空列表,就不進行節流設定了
         throttle_classes = []
全域性設定
REST_FRAMEWORK = {
            'DEFAULT_THROTTLE_RATES':{
                'unlogin':'10/m',
            },
            'DEFAULT_THROTTLE_CLASSES':['util.throttle.MySimpleRateThrottle',],
        }

版本

  • 作用:判斷使用者請求的Api是否有效(公司版本迭代時做相容)
  • 在檢視類中配置 versioning_class =注意這是單數形式,只能配置一個類
  • 實現 determine_version 方法
  • 全域性配置 DEFAULT_VERSION ALLOWED_VERSIONS VERSION_PARAM
自定義版本類
自定義(object):(url地址傳參)
     class MyPathVersioning(object):
         def determine_version(self,request, *args, **kwargs):
             # 獲取使用者傳遞的版本引數(version)
             # version = request._request.GET.get('version')
             version = request.query_params.get('version')
             return version

    #設定自定義的版本類
   # versioning_class = MyPathVersioning


   # 使用DRF自帶的版本類QueryParameterVersioning
   from rest_framework.versioning import QueryParameterVersioning
    # 在檢視中
    versioning_class = QueryParameterVersioning

    #如果需要做版本的預設和限制,需要在settings中設定
    REST_FRAMEWORK = {
        'DEFAULT_VERSION':'v1',
        'ALLOWED_VERSIONS':['v1','v2','v3'],
        'VERSION_PARAM':'version',
    }

    # #設定預設的版本
    # default_version = api_settings.DEFAULT_VERSION
    # #設定允許的版本
    # allowed_versions = api_settings.ALLOWED_VERSIONS
    # #設定版本的引數
    # version_param = api_settings.VERSION_PARAM

    #使用DRF自帶的版本類URLPathVersioning

    from rest_framework.versioning import URLPathVersioning

    # 在檢視中(區域性使用)
    versioning_class = URLPathVersioning
##
#    versioning_class = None

    #如果需要做版本的預設和限制,需要在settings中設定
    REST_FRAMEWORK = {
        'DEFAULT_VERSION':'v1',
            'ALLOWED_VERSIONS':['v1','v2','v3'],
            'VERSION_PARAM':'version',
    }
全域性設定
 #全域性設定
    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
    }

解析器

  • 全域性 DEFAULT_PARSER_CLASSES= ['rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser']
  • 檢視配置 parser_classes = []
  • 使用 request.data 或 request.FILE
from rest_framework.parsers import JSONParser,FormParser

    # FormParser
    # 當前端傳送過來的資料是json資料的時候
    # content-type:application/x-www-form-urlencoded
    # post請求的資料在_request.POST拿到資料
    # 傳送到後端的資料格式productId=123&productName=宋&userId=1
    # productId = request._request.POST.get('productId')
    # productName = request._request.POST.get('productName')
    # userId = request._request.POST.get('userId')
    # print(productId,productName,userId)

    # JSONParser
    # 當前端傳送過來的資料是json資料的時候
    # content-type:application/json
    # post請求的資料在_request.POST已經獲取不到了
    # 在_request.body可以拿到
    # #傳送到後端的資料格式{'productId': 123, 'productName': '宋', 'userId': 1}
    # data = request._request.body
    # import json
    # data = json.loads(data)
    # print(data)
    ######################上面的寫法並沒有用上解析器##############

    #只有呼叫request.data的時候才使用上了解析器
    data = request.data
    print(data)

序列化

序列化不僅可以序列化資料庫中的資料,也可以驗證提交欄位
提交的欄位放在 request.validated_data中,這是一個字典,Django form是 request.cleaned_data。
自定義驗證規則,鉤子函式:
def validate_field() 欄位名
django clean_field()

第一種方式(serializers.Serializer)
        class xxxxSerializer(serializers.Serializer):
            username = serializers.CharField()
            #使用者的id
            id = serializers.IntegerField()
            # 使用者型別(普通使用者、VIP使用者)
            #type = serializers.IntegerField()
            type = serializers.CharField(source="get_type_display")
            # 1:男  2:女
            #自定義序列化方法
            gender = serializers.SerializerMethodField()
            # 出生日期
            birthday = serializers.DateTimeField(format='%Y-%m-%d')
            #自定義序列化方法的方法民命規範:def get_欄位名(self,row)
            #生成url地址
            #序列化時返回使用者詳情的url地址
            url = serializers.HyperlinkedIdentityField(
                view_name ='userdetail',lookup_field='id',lookup_url_kwarg ='pk')
#           url(r"^(?P<version>[v1|v2]+)/userdetail/(?P<pk>\d+)/",UserDetailView.as_view(),name='userdetail'),
            def get_gender(self,row):
                ##row -> User()
                if row.gender == 1:
                    return "男"
                elif row.gender == 2:
                    return "女"

#            如果使用serializers.Serializer)序列化的類儲存資料時,需要重寫create
            def create(self, validated_data):
                 instance = models.User.objects.create(**validated_data)
                 return instance
第二種方式(serializers.ModelSerializer)
    class UserListSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.User
            #fields = "__all__"
            fields = ["id","username"]


    #對請求的資料進行驗證(POST)
    class RegisterUserSerializer(serializers.ModelSerializer):
        #使用者名稱
        username = serializers.CharField(error_messages=
             {
             'required':'使用者名稱不能為空'
             },
        )
        #密碼(A a-z 0-9,不低於8位)
        password = serializers.CharField()
         
         #自定義驗證方法(validate_欄位名)
         def validate_password(self,value):
             #value -> password
             import re
             from rest_framework.exceptions import ValidationError
             if re.match(r'[A-Z]',value):
                 #首字母是大寫
                 if re.search(r'[a-z]',value) and re.search(r'[0-9]',value) and len(value) > 7:
                     return value
                 else:
                     raise ValidationError('密碼格式錯誤')
             else:
                 raise ValidationError('密碼首字母必須大寫')

        class Meta:
            model = models.User
            fields = ["username","password"]

分頁

  • DRF提供了三種方式
第一種繼承自PageNumberPagination
from rest_framework.pagination import PageNumberPagination
    # https://www.baidu.com/?kw=xxx&page=1&pagesize=5
    # 自定義分頁類
    class MyPageNumberPagination(PageNumberPagination):
        #page_size,每頁返回多少條資料
        page_size = 5
        #傳遞分頁的引數
        page_query_param = 'page'
        #傳遞每頁返回多少條資料的引數
        page_size_query_param = 'pagesize'
        #每頁返回資料的最大條數
        max_page_size = 10
        
        def get_paginated_response(self, data):
            ###可選方法,自定義分頁的返回結果
            ret = {
                'code':1,
                'count':self.page.paginator.count,
                'next':self.get_next_link(),
                'previous':self.get_previous_link(),
                'data':data
            }
            return Response(ret)
第二種分頁方式LimitOffsetPagination
from rest_framework.pagination import LimitOffsetPagination
# https://www.baidu.com/?kw=xxx&offset=5&limit=5
class MyLimitOffsetPagination(LimitOffsetPagination):
    #預設每頁返回的條數
    default_limit = 5
    #限制返回條數的引數名
    limit_query_param = 'limit'
    #設定起始的偏移量引數
    offset_query_param = 'offset'
    #每頁返回資料的最大條數
    max_limit = 10
第三種分頁方式CursorPagination(加密的方式)
from rest_framework.pagination import CursorPagination
# http://127.0.0.1:8000/v2/userlist/?cursor=cD03&pagesize=2
class MyCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 5
    #排序方式
    ordering = '-id'
    page_size_query_param = 'pagesize'
    max_page_size = 10

檢視

檢視中的區域性使用
class UserList(APIView):
    def get(self,request,*args,**kwargs):
        ret = {
            'code':1,
            'data':None
        }
        # 獲取使用者列表
        queryset = models.User.objects.all()
        #例項化分頁類
        pg = MyCursorPagination()
        #呼叫paginate_queryset進行分頁,獲取當前分頁資料
        pg_data = pg.paginate_queryset(queryset=queryset,request=request,view=self)
        ser = UserSerializer(
                             instance=pg_data,
                             context={'request': request},
                             many=True
                             )
        # return response(ser.data)
        return pg.get_paginated_response(ser.data)
最早使用的是django自帶的檢視類
    from django.views import View
    class UserView(View):
    
        def get(self,request,*args,**kwargs):
            pass
        def post(self,request,*args,**kwargs):
            pass

    後來使用rest_framework的APIView檢視類(定製性很強)
    from rest_framework.views import APIView
    class Register(APIView):
        def get(self,request,*args,**kwargs):
            pass
        def post(self,request,*args,**kwargs):
            pass
GenericAPIView檢視的使用(其實它繼承自APIView,只是在APIView的基礎上添加了屬性和方法,可以提供給我們呼叫)
 from rest_framework.generics import GenericAPIView
     class UserGenericAPIView(GenericAPIView):
         #獲取使用者的列表
         #獲取資料庫中表裡面的資料集
         queryset = models.User.objects.all()
         #設定序列化的類
         serializer_class = UserSerializer
         #設定分頁類
         pagination_class = MyPageNumberPagination

         def get(self,request,*args,**kwargs):
             #呼叫get_queryset獲取結果集
             data = self.get_queryset()
             #呼叫paginate_queryset獲取當前分頁下的資料
             pd_data = self.paginate_queryset(queryset=data)
             #呼叫get_serializer方法獲取UserSerializer序列化物件
             ser = self.get_serializer(
                 instance=pd_data,many=True,
                 context={'request':request},
             )
             # return Response(ser.data)
             return self.get_paginated_response(ser.data)
GenericViewSet檢視,路由和請求反射對應的方法就會發生變化
from rest_framework.viewsets import GenericViewSet
    class UserGenericAPIView(GenericViewSet):
        #獲取使用者的列表
        #獲取資料庫中表裡面的資料集
        queryset = models.User.objects.all()
        #設定序列化的類
        serializer_class = UserSerializer
        #設定分頁類
        pagination_class = MyPageNumberPagination
        
        def list(self,request,*args,**kwargs):
            #呼叫get_queryset獲取結果集
            data = self.get_queryset()
            #呼叫paginate_queryset獲取當前分頁下的資料
            pd_data = self.paginate_queryset(queryset=data)
            #呼叫get_serializer方法獲取UserSerializer序列化物件
            ser = self.get_serializer(
                                      instance=pd_data,many=True,
                                      context={'request':request},
                                      )
                                      # return Response(ser.data)
            return self.get_paginated_response(ser.data)
終極檢視的使用
from rest_framework.mixins import ListModelMixin,\
        CreateModelMixin,DestroyModelMixin,UpdateModelMixin,\
        RetrieveModelMixin

    # CreateModelMixin: 新增資料(POST請求)
    # DestroyModelMixin: 刪除資料(DELETE請求)
    # UpdateModelMixin: 更新資料(PUT請求)
    # ListModelMixin: 獲取列表資料 (GET請求)
    # RetrieveModelMixin: 獲取詳情資料(GET請求)
    # 使用以上檢視類的時候一定要和GenericViewSet配合使用

    class UserListView(ListModelMixin,CreateModelMixin,
                       DestroyModelMixin,UpdateModelMixin,
                       RetrieveModelMixin,GenericViewSet):
        #設定資料集
        queryset = models.User.objects.all()
        #設定序列化類
        serializer_class = UserListSerializer
        #設定分頁類
        pagination_class = MyPageNumberPagination


    檢視類使用的總結:
    1.繼承自APIVIew的檢視是萬能的,自定義性比較強
    2.GenericAPIView檢視的使用(其實它繼承自APIView,只是在APIView的基礎上
添加了屬性和方法,可以提供給我們呼叫,一般情況下不會單獨使用它)
    3.如果只是實現簡單的增、刪、改、查,下面類可以隨機配合使用
         CreateModelMixin: 新增資料(POST請求)
         DestroyModelMixin: 刪除資料(DELETE請求)
         UpdateModelMixin: 更新資料(PUT請求)
         ListModelMixin: 獲取列表資料 (GET請求)
         RetrieveModelMixin: 獲取詳情資料(GET請求)
         使用以上檢視類的時候一定要和GenericViewSet配合使用
    4.如果只是實現增、刪、改、查功能全部都要實現,可以直接繼承自ModelViewSet
    from rest_framework.viewsets import ModelViewSet

路由

#自動路由配置
"""
     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']

渲染器

 from rest_framework.renderers import JSONRenderer,\
        BrowsableAPIRenderer,AdminRenderer
    #JSONRenderer:在瀏覽器中只會返回json資料
    #BrowsableAPIRenderer:得到視覺化的模版介面
    #AdminRenderer:得到管理員視覺化的模版介面
    
    區域性使用(檢視中)
    renderer_classes = [JSONRenderer,AdminRenderer]

    全域性使用(DRF預設已經設定過了,不需要自己設定)
    'DEFAULT_RENDERER_CLASSES': (
     'rest_framework.renderers.JSONRenderer',
     'rest_framework.renderers.BrowsableAPIRenderer',
    )

作者:時光清淺_許你心安_
連結:https://www.jianshu.com/p/f7d92c95a9fb