python drf各类组件的用法和作用


Posted in Python onJanuary 12, 2021

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'],
  }
  """
  
  最最重要的,理清权限认证的源代码

分页

自定义分页类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']

频率限制节流

节流:
  自定义节流类
  """
  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)
      
  """

渲染器

渲染器
  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,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
  """

以上就是python drf各类组件的用法和作用的详细内容,更多关于python drf组件的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python之import机制详解
Jul 03 Python
详解Python中dict与set的使用
Aug 10 Python
详解python中requirements.txt的一切
Mar 03 Python
django manage.py扩展自定义命令方法
May 27 Python
用Python一键搭建Http服务器的方法
Jun 01 Python
5分钟 Pipenv 上手指南
Dec 20 Python
Python中Numpy ndarray的使用详解
May 24 Python
python实现在函数中修改变量值的方法
Jul 16 Python
Python在OpenCV里实现极坐标变换功能
Sep 02 Python
django 解决扩展自带User表遇到的问题
May 14 Python
Python如何自动获取目标网站最新通知
Jun 18 Python
python中re模块知识点总结
Jan 17 Python
Python try except else使用详解
Jan 12 #Python
python 逆向爬虫正确调用 JAR 加密逻辑
Jan 12 #Python
Python调用高德API实现批量地址转经纬度并写入表格的功能
Jan 12 #Python
使用sublime text3搭建Python编辑环境的实现
Jan 12 #Python
使用Python获取爱奇艺电视剧弹幕数据的示例代码
Jan 12 #Python
将不规则的Python多维数组拉平到一维的方法实现
Jan 11 #Python
python用分数表示矩阵的方法实例
Jan 11 #Python
You might like
php的GD库imagettftext函数解决中文乱码问题
2015/01/24 PHP
php多线程实现方法及用法实例详解
2015/10/26 PHP
Yii中CGridView实现批量删除的方法
2015/12/28 PHP
CL vs ForZe BO5 第三场 2.13
2021/03/10 DOTA
JAVASCRIPT  THIS详解 面向对象
2009/03/25 Javascript
NodeJS 模块开发及发布详解分享
2012/03/07 NodeJs
jQuery中prevAll()方法用法实例
2015/01/08 Javascript
JavaScript插件化开发教程(五)
2015/02/01 Javascript
jquery.uploadify插件在chrome浏览器频繁崩溃解决方法
2015/03/01 Javascript
简单谈谈javascript中的变量、作用域和内存问题
2015/08/30 Javascript
基于jQuery中ajax的相关方法汇总(必看篇)
2017/11/08 jQuery
js实现复制功能(多种方法集合)
2018/01/06 Javascript
vue引入axios同源跨域问题
2018/09/27 Javascript
node上的redis调用优化示例详解
2018/10/30 Javascript
微信小程序实现上传多张图片、删除图片
2020/07/29 Javascript
如何使用JS console.log()技巧提高工作效率
2020/10/14 Javascript
[01:15:36]加油刀塔第二期网络版
2014/08/09 DOTA
[09:34]2018DOTA2国际邀请赛寻真——永不放弃的iG
2018/08/14 DOTA
python实现批量修改文件名代码
2017/09/10 Python
Python实现京东秒杀功能代码
2019/05/16 Python
pycharm配置git(图文教程)
2019/08/16 Python
python读取Kafka实例
2019/12/23 Python
python中@property的作用和getter setter的解释
2020/12/22 Python
德国网上药房:Apotal
2017/04/04 全球购物
MCAKE蛋糕官方网站:一直都是巴黎的味道
2018/02/06 全球购物
Lentiamo荷兰:在线订购隐形眼镜、隐形眼镜液和太阳镜
2019/10/25 全球购物
巴塞罗那观光通票:Barcelona Pass
2019/10/30 全球购物
意大利消费电子产品购物网站:SLG Store
2019/12/26 全球购物
.net笔试题
2014/03/03 面试题
新农村建设典型材料
2014/05/31 职场文书
慰问信范文
2015/02/14 职场文书
酒店辞职书范文
2015/02/26 职场文书
保密法制宣传月活动总结
2015/05/07 职场文书
SQL SERVER存储过程用法详解
2022/02/24 SQL Server
PO模式在selenium自动化测试框架的优势
2022/03/20 Python
详解SQL的窗口函数
2022/04/21 Oracle