• DRF


    大V

    一版本  

     自定义版本基于URL获取版本

     

    定义版本类

    class ParamVersion():
        def determine_version(self, request, *args, **kwargs):
            version = request.query_params.get('version') #等于request._request.GET.get('version)
            print(request.query_params)
            return version
    

    URL

    from django.conf.urls import url, include
    from app01.views import TestView
    
    urlpatterns = [
        url(r'^test/', TestView.as_view(),name='test'),
    ]  

    views

    class TestView(APIView):
        versioning_class = URLPathVersioning   # 基于URL正则获取版本获取版本
        def get(self, request, *args, **kwargs):
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
    

      

    框架QueryParameterVersioning模块基于URL获取版本

    settings配置

    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',            # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }
    

      

    URL

    from django.conf.urls import url, include
    from app01.views import TestView
    
    urlpatterns = [
        url(r'^test/', TestView.as_view(),name='test'),
    ]
    

      

    views

    class TestView(APIView):
        versioning_class = QueryParameterVersioning   # 基于URL获取版本
        def get(self, request, *args, **kwargs):
    
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
    

      

    框架URLPathVersioning模块基于URL正则获取版本

    url

    from django.conf.urls import url, include
    from app01.views import TestView
    
    urlpatterns = [
        url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
    ]  

    view

    class TestView(APIView):
        versioning_class = URLPathVersioning   # 基于URL正则获取版本获取版本
        def get(self, request, *args, **kwargs):
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
    

      

    其他版本控制类用from rest_framework import versioning查看源码

    全局设置版本控制

    REST_FRAMEWORK = {
      "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
    }

    二 认证

     自定义认证类,用户url传入token

    url

    urlpatterns = [
       url(r'^auth/',views.AuthView.as_view(),name='auth'),
        url(r'^order/',views.OrderView.as_view(),name='order'),
    ]

    认证类 

    class Authenticate(BaseAuthentication): #继承所有认证类父类
        def authenticate(self,request):
            token = request._request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if not token_obj:
                raise exceptions.AuthenticationFailed('用户认证失败')
            # 在rest framework内部会将整个两个字段赋值给request,以供后续操作使用
            return (token_obj.user, token_obj)
    
        def authenticate_header(self, request):  #验证失败时候的弹窗,一般不用不关注
            return 'Basic realm="api"'
    

    md5生成token

    1 def md5(user):
    2     import hashlib
    3     import time
    4     ctime = str(time.time())
    5     m=hashlib.md5(bytes(user,encoding='utf-8'))
    6     m.update(bytes(ctime,encoding='utf-8'))
    7     return m.hexdigest()


    view

    
    
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import QueryParameterVersioning,URLPathVersioning
    from rest_framework import versioning
    from rest_framework.response import Response
    
    
     1 # 登录
     2 class AuthView(APIView):
     3     def post(self,request,*args,**kwargs):
     4         ret = {'code':1000,'msg':None}
     5         try:
     6             user = request._request.POST.get('username')
     7             pwd = request._request.POST.get('password')
     8             obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
     9             if not obj:
    10                 ret['code'] = 1001
    11                 ret['msg'] = "用户名或密码错误"
    12             # 为登录用户创建token
    13             token = md5(user)
    14             # 存在就更新,不存在就创建
    15             models.UserToken.objects.update_or_create(user=obj,defaults={'token':token})
    16             ret['token'] = token
    17         except Exception as e:
    18             ret['code'] = 1002
    19             ret['msg'] = '请求异常'
    21         return JsonResponse(ret)
    22 
    23 class OrderView(APIView):
    24     """
    25     订单相关业务
    26     """
    27     authentication_classes = [Authenticate,]   #需要认证的业务
    28     def get(self,request,*args,**kwargs):
    29         print(request.user)
    30         print(request.auth)
    31         ret = {'code':1000,'msg':None,'data':None}
    32         try:
    33             ret['data'] = ORDER_DICT
    34         except Exception as e:
    35             pass
    36         return JsonResponse(ret)

     框架自带认证类

    from rest_framework.authentication import BaseAuthentication

    全局配置认证

    1 REST_FRAMEWORK = {
    2     'UNAUTHENTICATED_USER': None,
    3     'UNAUTHENTICATED_TOKEN': None,
    4     "DEFAULT_AUTHENTICATION_CLASSES": [
    5         "web.utils.TestAuthentication",  #认证类路径
    6     ],
    7  
    8 }
    9 settings.py
    View Code

    全局认证时碰上不需要认证的类,只需要在类配置认证类为空列表就行,

    1 class OrderView(APIView):
    2     authentication_classes = []
    3     def get(self,request,*args,**kwargs):
    4         print(request.user)
    5         print(request.auth)
    View Code

    认证源码执行顺序

    三  权限

    权限控制类

    1 class SVIPPermission(BasePermission):
    2     message = "必须是SVIP才能访问"
    3     def has_permission(self,request,view):
    4         if request.user.user_type != 3:
    5             return False 
    6         return True
    View Code

    返回False没有权限,True有权限

    view

     1 class OrderView(APIView):
     2     """
     3     订单相关业务(只有SVIP用户有权限)
     4     """
     5     authentication_classes = [Authenticate,]
     6     permission_classes = [SVIPPermission,]
     7     def get(self,request,*args,**kwargs):
     8         print(request.user)
     9         print(request.auth)
    10         ret = {'code':1000,'msg':None,'data':None}
    11         try:
    12             ret['data'] = ORDER_DICT
    13         except Exception as e:
    14             pass
    15         return JsonResponse(ret)
    View Code

    全局配置权限

    REST_FRAMEWORK = {
    "DEFAULT_PERMISSION_CLASSES:['api.utils.permission.SVIPPermission'],
    }  

    源码流程图 

     

     四 用户访问次数/频率限制

    简单所有权限类父类实现

     1 from rest_framework.throttling import BaseThrottle
     2 import time
     3 VISIT_RECORD = {}
     4 class VisitThrottle(BaseThrottle):
     5 
     6     def __init__(self):
     7         self.history = None
     8 
     9     def allow_request(self,request,view):
    10         # 1. 获取用户IP
    11         remote_addr = self.get_ident(request)
    12 
    13         ctime = time.time()
    14         if remote_addr not in VISIT_RECORD:
    15             VISIT_RECORD[remote_addr] = [ctime,]
    16             return True
    17         history = VISIT_RECORD.get(remote_addr)
    18         self.history = history
    19 
    20         while history and history[-1] < ctime - 60:
    21             history.pop()
    22 
    23         if len(history) < 3:
    24             history.insert(0,ctime)
    25             return True
    26 
    27         # return True    # 表示可以继续访问
    28         # return False # 表示访问频率太高,被限制
    29 
    30     def wait(self):
    31         # 还需要等多少秒才能访问
    32         ctime = time.time()
    33         return 60 - (ctime - self.history[-1])
    View Code

    view

    1 class ThrottView(APIView):
    2     throttle_classes = [VisitThrottle]
    3     def get(self,request, *args, **kwargs):
    4 
    5         return HttpResponse("限流时间之内访问页面")
    View Code

    系统频率限制类

    基于用户IP显示访问频率(利于Django缓存) 实现

     view

    from rest_framework.throttling import BaseThrottle,SimpleRateThrottle
    class VisitThrottle(SimpleRateThrottle):
        scope = "Luffy"
          # 数据属性对应settings 的key,value是单位时间访问次数
        def get_cache_key(self, request, view):
            return self.get_ident(request)
    

     settings配置

    REST_FRAMEWORK = {
        "DEFAULT_THROTTLE_RATES":{
            "Luffy":'3/m',
        }
    }
    

     更多其他方式查看 >>>  from rest_framework.throttling import BaseThrottle

     

     五 解析器

    根据请求头 content-type 选择对应的解析器就请求体内容进行处理

    url

    1 from django.conf.urls import url, include
    2 from app01.views import TestView
    3 from app01 import views
    4 
    5 urlpatterns = [
    6     url(r'^paser/',views.PaserView.as_view(),name='paser'),
    7 ]
    View Code

    view

     1 from rest_framework.parsers import JSONParser,FormParser
     2 class PaserView(APIView):
     3     parser_classes = [FormParser,JSONParser]
     4     def get(self,request, *args, **kwargs):
     5         print(request.data)
     6         return HttpResponse("解析器")
     7 
     8     def post(self,request, *args, **kwargs):
     9         print(request.data)
    10         return HttpResponse("解析器")
    View Code

    更多内置解析器查看

    from rest_framework.parsers import JSONParser

    解析Content-type头和对应解析类型

    a. 仅处理请求头content-type为application/json的请求体
    b. 仅处理请求头content-type为application/x-www-form-urlencoded 的请求体

    c. 仅处理请求头content-type为multipart/form-data的请求体 

    d. 仅上传文件FileUploadParser

    全局使用

    1 REST_FRAMEWORK = {
    2     'DEFAULT_PARSER_CLASSES':[
    3         'rest_framework.parsers.JSONParser'
    4         'rest_framework.parsers.FormParser'
    5         'rest_framework.parsers.MultiPartParser'
    6     ]
    7 
    8 }
    View Code

     六 序列化

    Serializer

     序列化类

    class StuSerializers(serializers.Serializer):
        id = serializers.IntegerField()
        name = serializers.CharField()
        # 一对一和一对多正向查询  source ='字段名.跨表的字段名'
        stu_grade = serializers.CharField(source='stu_grade.title')
        addr = serializers.CharField(source='stu_addr.addr')  
    

      

    models

     1 class Student(models.Model):
     2     name = models.CharField(max_length=16)
     3     stu_grade = models.ForeignKey(to="Grade",on_delete=models.CASCADE)
     4     stu_addr = models.OneToOneField(to='Addr',on_delete=models.CASCADE)
     5 
     6 class Grade(models.Model):
     7     title = models.CharField(max_length=16)
     8 
     9 
    10 class Addr(models.Model):
    11     addr = models.CharField(max_length=100)
    View Code

    url

    1 url(r'^student/',views.StudentView.as_view(),name='student'),
    View Code

    views

    1 class StudentView(APIView):
    2     def get(self,request,*args,**kwargs):
    3         stu_list = models.Student.objects.all().first()
    4         ser = StuSerializers(instance=stu_list)
    5         return Response(ser.data)
    View Code
    from rest_framework.response import Response自动将序列化好的类转为json格式发给前端

     序列化对个对象 添加many=True

    ser = StuSerializers(instance=stu_list,many=True) 

     自定义显示字段

     1 class UserinfoSerializes(serializers.Serializer):
     2     username = serializers.CharField()
     3     password = serializers.CharField()
     4     user_type = serializers.CharField(source='get_user_type_display')  #显示choices字段名称get_字段名_display
     5     gp = serializers.CharField(source='group.title')  # onetoone foreignkey 跨表
     6     rls = serializers.SerializerMethodField()  #自定义显示字段manttomany
     7     def get_rls(self,row):
     8         role_obj_list = row.roles.all()
     9         ret = []
    10         for item in role_obj_list:
    11             ret.append({"id":item.id,"title":item.title})
    12         return ret
    View Code

    自定义显示字段用于ManytoMany 或者 多对一反向查询时 

    显示choices字段名称get_字段名_display

      

    ModelSerializer

    定义序列化类

    1 class GradeSerializers(serializers.ModelSerializer):
    2     stu_grade_id = serializers.IntegerField(write_only=True)
    3     stu_addr_id = serializers.IntegerField(write_only=True)
    4     class Meta:
    5         model = models.Student
    6         fields = '__all__'
    7         depth = 1  #层数
    View Code
    write_only=True,只做反序列化,保存
    read_only=True,只做序列化,读取
     1 class GradeView(APIView):
     2     def get(self,request,*args,**kwargs):
     3         grade_list = models.Student.objects.all()
     4         ser = GradeSerializers(instance=grade_list,many=True)
     5         print(ser)
     6         return Response(ser.data)
     7 
     8     def post(self,request,*args,**kwargs):
     9         ser = GradeSerializers(data=request.data)
    10         if ser.is_valid():  #客户端提交数据校验
    11             print('validated_data',ser.validated_data)  #提交成功字段
    12             # ser.save() # 没有外键字段使用 ,提交到数据库方式一,需要指定保存字段write_only=True 
    13             models.Student.objects.create(
    14                 name = ser.validated_data['name'],
    15                 stu_grade_id = ser.validated_data['stu_grade_id'],
    16                 stu_addr_id = ser.validated_data['stu_addr_id'],
    17             )
    18             return HttpResponse('增加成功')
    19 
    20         else:
    21             print('errors',ser.errors)  #验证失败字段
    22         return HttpResponse('ok')
    View Code

    七 分页

    url

    1 urlpatterns = [
    2     url('page_ud/', views.PageView.as_view()),
    3 ]
    View Code
    根据页码进行分页
    1 #a. 根据页码进行分页  http://127.0.0.1:8000/page_ud/?page=1&size=3
    2 class MyPagePagination(PageNumberPagination):
    3     page_size = 2  #每页显示多少条
    4     page_size_query_param = 'size' #url传递参数size,一页显示多少条数据
    5     page_query_param = 'page'      #URL传递页数,第几页
    6     max_page_size = 5
    View Code
    位置和个数进行分页
    1 class MyPagePagination(LimitOffsetPagination):
    2     default_limit = 3
    3     limit_query_param = 'limit'  # 查几条数据
    4     offset_query_param = 'offset' #从第几条开始
    5     max_limit = 5
    View Code

    游标分页

     1 # c. 游标分页 http://127.0.0.1:8000/page_ud/
     2     # 将页码加密 必须返回return pg.get_paginated_response(ser.data)这个
     3 class MyPagePagination(CursorPagination):
     4     # URL传入的游标参数
     5     cursor_query_param = 'cursor'
     6     # 默认每页显示的数据条数
     7     page_size = 2
     8     # URL传入的每页显示条数的参数
     9     page_size_query_param = 'page_size'
    10     # 每页显示数据最大条数
    11     max_page_size = 1000
    12     # 根据ID从大到小排列
    13     ordering = "id"
    View Code

    view

     1 class PageView(APIView):
     2     def get(self,request,*args,**kwargs):
     3         page_list = models.Student.objects.all()
     4         pg = MyPagePagination()
     5         # 实例化分页器
     6         page_ser = pg.paginate_queryset(queryset=page_list, request=request, view=self)
     7 
     8         ser = GradeSerializers(instance=page_ser,many=True)
     9 
    10         return Response(ser.data)
    11         # return pg.get_paginated_response(ser.data)  
    View Code

    八 视图

    GenericAPIView

    源码  继承了APIView

    url

    1 urlpatterns = [
    2     url('stu/', views.StuView.as_view())
    3 ]
    View Code

    view

     1 # 继承GenericAPIView 继承APIView
     2 # 继承GenericAPIView 从自定义的分页器和序列化类中实现一系列序列化
     3 from rest_framework.generics import GenericAPIView
     4 class StuView(GenericAPIView):
     5     queryset = models.Student.objects.all()
     6     serializer_class = GradeSerializers  #自己定义序列化类
     7     pagination_class = MyPagePagination  #自已定义分页类
     8 
     9     def get(self,request,*args,**kwargs):
    10         page_list = models.Student.objects.all()
    11         pg = MyPagePagination()
    12         # 实例化分页器
    13         page_ser = pg.paginate_queryset(queryset=page_list, request=request, view=self)
    14         ser = GradeSerializers(instance=page_ser,many=True)
    15         return Response(ser.data)
    View Code

    GenericViewSet

    1 urlpatterns = [
    2     url('stu/', views.StuView1.as_view({'get':'list'})),
    3 ]
    View Code

    view

    1 # GenericViewSet 需要在路由配置url('stu/', views.StuView1.as_view({'get':'list'})),
    2     # 将get请求印射到list方法
    3     # 相当于起别名一样的视图 也可以post put请求
    4 from rest_framework.viewsets import GenericViewSet
    5 class StuView1(GenericViewSet):
    6 
    7     def list(self,request,*args,**kwargs):
    8         return HttpResponse('...')
    View Code

    ModelViewSet

    url

    1 urlpatterns = [   
    2      url(r'^studd/(?P<pk>d+)$', views.StuView3.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
    3 
    4 ]
    View Code

    view

     1 class ModelViewSet(mixins.CreateModelMixin,
     2                    mixins.RetrieveModelMixin,
     3                    mixins.UpdateModelMixin,
     4                    mixins.DestroyModelMixin,
     5                    mixins.ListModelMixin,
     6                    GenericViewSet):继承了增删改查所有的方法
     7 from rest_framework.viewsets import ModelViewSet
     8 class StuView3(ModelViewSet):
     9     queryset = models.Student.objects.all()
    10     serializer_class = GradeSerializers  #定义序列化类
    11     pagination_class = MyPagePagination  #定义分页类
    View Code

    九 渲染器

    视图配置

    1 from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
    2 class page_udView(ModelViewSet):
    3     # renderer_classes = [JSONRenderer,]  #数据渲染成json格式
    4     renderer_classes = [JSONRenderer,BrowsableAPIRenderer]  #数据渲染成json格式,浏览器渲染
    5 
    6 
    7     queryset = Page.objects.all()
    8     serializer_class = PagePagination
    9     pagination_class = MyPagePagination
    View Code
    查看各种渲染器
    from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
    JSONRenderer  #media_type = 'application/json'
    TemplateHTMLRenderer  #media_type = 'text/html'







  • 相关阅读:
    函数的存储 堆和栈
    函数的容错处理 函数的返回值
    Linux启动故障排查和修复技巧
    干货 | 亿级Web系统负载均衡几种实现方式
    利用expect批量修改Linux服务器密码
    干货 | LVM快照学习
    实战 | Linux根分区扩容
    LVM 逻辑卷学习
    Shell脚本实战:日志关键字监控+自动告警
    手把手教你在Linux中快速检测端口的 3 个小技巧
  • 原文地址:https://www.cnblogs.com/sunny666/p/13501727.html
Copyright © 2020-2023  润新知