1. 程式人生 > 程式設計 >python drf各類元件的用法和作用

python drf各類元件的用法和作用

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,就不再進行許可權認證了
     permission_classes = []
  """
 
  全域性的設定
  """
  REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES':['unitls.permission.MyOrderPermission'],}
  """
  
  最最重要的,理清許可權認證的原始碼

分頁

 自定義分頁類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,*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,**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,**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)
        
        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,UpdateModelMixin
    from rest_framework.viewsets import GenericViewSet
    # ListModelMixin : 返回列表資料據( get請求)
    # CreateModelMixin : 新增一條資料 (Post請求)
    # RetrieveModelMixin,: 獲取詳情資料 (get請求)
    # DestroyModelMixin,: 刪除資料的時候 (delete)
    # UpdateModelMixin : 跟新資料的時候使用 (put)
 
    class BookView(ListModelMixin,UpdateModelMixin,GenericViewSet):
      # queryset: 設定獲取的資料
      queryset = models.BookInfo.objects.all()
      # serializer_class: 設定序列化的類
      serializer_class = BookinfoSeralizer
      # pagination_class : 設定分頁的類
      pagination_class = MyPageNumberPagination
    """
    第四個:ModelViewSet檢視的使用
    ModelViewSet繼承自istModelMixin,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,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']

頻率限制節流

節流:
  自定義節流類
  """
  VISIT_RECORD = {}
  class VisitThrottle(object):
    def __init__(self):
      self.history = None
    def allow_request(self,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,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,**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_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',}
    """
  
  全域性設定
  """
    REST_FRAMEWORK = {
      'VERSION_PARAM':'version','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,**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,**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,**kwargs):
        # 如果使用JSONParser、FormParser解析資料的話
        data = request.data
        print(data)
      
  """

渲染器

 渲染器
  INSTALLED_APPS = [
           'rest_framework',]
  from rest_framework.renderers import BrowsableAPIRenderer,JSONRenderer,AdminRenderer
  class BookView(ModelViewSet):
    # 設定渲染器型別
    renderer_classes = [JSONRenderer]

序列化

 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,**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
  """

以上就是python drf各類元件的用法和作用的詳細內容,更多關於python drf元件的資料請關注我們其它相關文章!