zoukankan      html  css  js  c++  java
  • 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'







  • 相关阅读:
    1.4.2.3. SETUP(Core Data 应用程序实践指南)
    1.4.2.2. PATHS(Core Data 应用程序实践指南)
    1.4.2.1. FILES(Core Data 应用程序实践指南)
    1.4.2. 实现 Core Data Helper 类(Core Data 应用程序实践指南)
    1.4.1. Core Data Helper 简介(Core Data 应用程序实践指南)
    1.4. 为现有的应用程序添加 Core Data 支持(Core Data 应用程序实践指南)
    1.3.2. App Icon 和 Launch Image(Core Data 应用程序实践指南)
    1.3.1. 新建Xcode项目并设置故事板(Core Data 应用程序实践指南)
    php验证邮箱是否合法
    如何使js函数异步执行
  • 原文地址:https://www.cnblogs.com/sunny666/p/13501727.html
Copyright © 2011-2022 走看看