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 相关文章推荐
Python3写入文件常用方法实例分析
May 22 Python
Python实现字典按照value进行排序的方法分析
Dec 23 Python
Python生成器以及应用实例解析
Feb 08 Python
Python实现定时备份mysql数据库并把备份数据库邮件发送
Mar 08 Python
一篇文章读懂Python赋值与拷贝
Apr 19 Python
python实现flappy bird小游戏
Dec 24 Python
Python基于matplotlib画箱体图检验异常值操作示例【附xls数据文件下载】
Jan 07 Python
详解Python_shutil模块
Mar 15 Python
pyqt 多窗口之间的相互调用方法
Jun 19 Python
python爬虫解决验证码的思路及示例
Aug 01 Python
Python的bit_length函数来二进制的位数方法
Aug 27 Python
python实现加密的方式总结
Jan 19 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修改上传图片尺寸的方法
2015/04/14 PHP
laravel项目利用twemproxy部署redis集群的完整步骤
2018/05/11 PHP
详解PHP多个进程配合redis的有序集合实现大文件去重
2019/03/06 PHP
php实现的表单验证类完整示例
2019/08/13 PHP
jquery 插件 web2.0分格的分页脚本,可用于ajax无刷新分页
2008/12/25 Javascript
jQuery 入门级学习笔记及源码
2010/01/22 Javascript
基于jQuery的js分页代码
2010/06/10 Javascript
jQuery获取对象简单实现方法小结
2014/10/30 Javascript
Js和JQuery获取鼠标指针坐标的实现代码分享
2015/05/25 Javascript
分享jQuery网页元素拖拽插件
2020/12/01 Javascript
JavaScript触发onScroll事件的函数节流详解
2016/12/14 Javascript
微信小程序 解决swiper不显示图片的方法
2017/01/04 Javascript
详解webpack自动生成html页面
2017/06/29 Javascript
使用layui实现的左侧菜单栏以及动态操作tab项方法
2019/09/10 Javascript
Js跳出两级循环方法代码实例
2020/09/22 Javascript
[48:32]2018DOTA2亚洲邀请赛 3.31 小组赛 A组 LGD vs VG
2018/04/01 DOTA
Python手机号码归属地查询代码
2016/05/04 Python
python生成多个只含0,1元素的随机数组或列表的实例
2018/11/12 Python
python3中pip3安装出错,找不到SSL的解决方式
2019/12/12 Python
Python文件读写w+和r+区别解析
2020/03/26 Python
Python logging模块原理解析及应用
2020/08/13 Python
python 写一个文件分发小程序
2020/12/05 Python
纯CSS实现的大小渐变、渐远效果
2014/04/15 HTML / CSS
基于MUI框架使用HTML5实现的二维码扫描功能
2018/03/01 HTML / CSS
巴西婴儿用品商店:Bebe Store
2017/11/23 全球购物
澳大利亚领先的美容护肤品零售商之一:SkincareStore
2018/01/22 全球购物
Tomcat Mysql datasource数据源配置
2015/12/28 面试题
后勤副校长自我鉴定
2013/10/13 职场文书
编辑硕士自荐信范文
2013/11/27 职场文书
文明餐桌行动实施方案
2014/02/19 职场文书
岗位廉政承诺书
2014/03/27 职场文书
毕业生简历自我评价范文
2014/04/09 职场文书
篝火晚会策划方案
2014/05/16 职场文书
求职简历自我评价怎么写
2015/03/10 职场文书
导游词之嵊泗列岛
2019/10/30 职场文书
Python加密与解密模块hashlib与hmac
2022/06/05 Python