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删除windows垃圾文件的方法
Jul 14 Python
python中print的不换行即时输出的快速解决方法
Jul 20 Python
Python基于回溯法子集树模板解决找零问题示例
Sep 11 Python
python分析作业提交情况
Nov 22 Python
浅谈用Python实现一个大数据搜索引擎
Nov 28 Python
Python实现KNN邻近算法
Jan 28 Python
Python基于socket实现简单的即时通讯功能示例
Jan 16 Python
python实现决策树分类
Aug 30 Python
python调用自定义函数的实例操作
Jun 26 Python
解决python 执行sql语句时所传参数含有单引号的问题
Jun 06 Python
PyCharm2020.1.1与Python3.7.7的安装教程图文详解
Aug 07 Python
使用pycharm运行flask应用程序的详细教程
Jun 07 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发电子邮件
2006/10/09 PHP
php数组函数序列之array_push() 数组尾部添加一个或多个元素(入栈),返回新长度。
2011/11/07 PHP
php下载文件的代码示例
2012/06/29 PHP
Laravel5.1自定义500错误页面示例
2016/10/09 PHP
基于jquery的弹出提示框始终处于窗口的居中位置(类似于alert弹出框的效果)
2011/09/28 Javascript
js下拉菜单语言选项简单实现
2013/09/23 Javascript
制作jquery遮罩层效果导航菜单代码分享
2013/12/25 Javascript
jQuery插件jFade实现鼠标经过的图片高亮其它变暗
2015/03/14 Javascript
javascript运动详解
2015/07/06 Javascript
基于jQuery和CSS3制作响应式水平时间轴附源码下载
2015/12/20 Javascript
jQuery实现的自适应焦点图效果完整实例
2016/08/24 Javascript
js实现横向拖拽导航条功能
2017/02/17 Javascript
从零开始学习Node.js系列教程之SQLite3和MongoDB用法分析
2017/04/13 Javascript
nodejs调取微信收货地址的方法
2017/12/20 NodeJs
Angular 项目实现国际化的方法
2018/01/08 Javascript
详解Node使用Puppeteer完成一次复杂的爬虫
2018/04/18 Javascript
浅谈微信JS-SDK 微信分享接口开发(介绍版)
2018/08/15 Javascript
js设置默认时间跨度过程详解
2019/07/17 Javascript
微信小程序webview组件交互,内联h5页面并网页实现微信支付实现解析
2019/08/16 Javascript
在nodejs中创建child process的方法
2021/01/26 NodeJs
[36:19]2018DOTA2亚洲邀请赛 小组赛 A组加赛 Newbee vs LGD
2018/04/03 DOTA
python实现树形打印目录结构
2018/03/29 Python
pycharm修改界面主题颜色的方法
2019/01/17 Python
Python实现的银行系统模拟程序完整案例
2019/04/12 Python
python Django中models进行模糊查询的示例
2019/07/18 Python
matplotlib quiver箭图绘制案例
2020/04/17 Python
解决import tensorflow导致jupyter内核死亡的问题
2021/02/06 Python
结构工程个人自荐信范文
2013/11/30 职场文书
销售心得体会
2014/01/02 职场文书
秦兵马俑教学反思
2014/02/07 职场文书
书香校园活动方案
2014/02/28 职场文书
党员教师工作决心书
2014/03/13 职场文书
2014年商场国庆节活动策划方案
2014/09/16 职场文书
2014年社区党建工作总结
2014/11/11 职场文书
街道社区活动报告
2015/02/05 职场文书
高中诗歌鉴赏教学反思
2016/02/16 职场文书