rest_framework之组件大长今

功能导入快捷查询:
from rest_framework import serializers   # 序列化
from rest_framework.routers import SimpleRouter,DefaultRouter # 路由
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer # 限制返回页面数据还是json数据
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination # 分页
from rest_framework.versioning import URLPathVersioning, # 版本控制,还有放在请求头中的AcceptHeaderVersioning
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser # 解析器
from rest_framework.permissions import BasePermission # 权限
from rest_framework.views import APIView # 视图
from rest_framework.viewsets import ModelViewSet # 高级封装视图
from rest_framework.response import Response
from rest_framework.status import HTTP_404_NOT_FOUND # 错误码
from app01 import serializer
from rest_framework.request import Request
from rest_framework.exceptions import ValidationError # 序列化错误返回前端




drf   
#  APIView的流程分析 # -APIView:dispatch---》包装了request,执行了认证,权限,频率 # -原生request对象 # -里面有个GET(以get形式提交的数据),以get形式提交的数据,都拆到environ内部,django把数据取出来转成了QueryDict的对象 # -session不是原生request对象的属性,在中间件中放进去的(django.contrib.sessions.middleware.SessionMiddleware) # -drf的Request类 # -data(post提交的数据,json格式,urlencoded,fromdata编码方式的数据) # -data的类型并不是固定的,可能是QueryDict,也可能是字典 # -query_params--->原生的GET # -重写了__getattr__ 对象.属性 当属性不存在就会执行该方法 return getattr(self._requset,'属性') FILES # 上传的文件 # -序列化 # -序列号使用: # -写一个类继承:Serializer或者ModelSerializer # -类内写字段 name=serialzier.CharField(source='字段,方法,对象.字段') # -如果是ModelSerializer: class Meta: model=表 fields=(字段,字段,) # -如果想重写字段 -在Meta上面或者下面:name=serialzier.CharField(source='字段,方法,对象.字段') # -SerializerMethodField -对应着一个方法:get_字段名(self,obj),方法返回值是什么,这个字段就是什么 # -在视图中使用 -实例化产生一个序列化类的对象(instance=要序列化的对象,data=json格式,many=True) # -对象.data 是个字典格式 # -反序列化的使用 # -json格式转成对象,保存到数据库 # -在保存之前一定要先调用对象.is_valid() # -Serializer的子类,需要重写create方法,自己写保存逻辑 # -ModelSerializer 直接save # -校验(局部和全局) # -validate_字段名字 局部校验 # -validate 全局校验 # -源码分析 # -序列化类实例化的时候: # -many=True的时候,生成的是列表中放了一个个的序列号化对象 # -many=False 的时候,生成的是一个序列化对象 # -__new__控制的 # -校验的源码部分 -调用了bookser.is_valid方法才走校验----》内部走了self.run_validation方法(找该方法一定要从根上找)---》Serializer类中找到了run_validation方法---》 重点的地方:self.to_internal_value(局部钩子)/self.validate(全局钩子) Serializer类中找到了to_internal_value,去对象内部反射validate_字段名的方法,如果不为None,直接执行,于是就执行了咱们自己写的局部校验的函数 # -序列化对象.data 的时候做了什么事 -执行Serializer内的data方法---》又执行了父类(BaseSerializer)的data方法---》执行self.to_representation(其实执行的是Serializer内的to_representation方法) 最终执行的是每个字段对象的get_attribute方法---》找字段对象的该方法--》在Field中找到了该方法 ---》执行了get_attribute(instance, self.source_attrs)---》self.source_attrs:每个字段source后面指定的根据.切分后的列表(publish.name:就会被分成[publish,name]) 如果是方法会执行方法,如果是字段,通过反射取出值 # -认证 # -使用(所有人都必须会)、 # -写一个认证类(继承BaseAuthentication) # -重写authenticate方法,把request对象传入 # -能从request对象中取出用户携带的token,根据token判断是否登录过 # -如果登录过,返回两个值 user对象,token对象 # -如果没有登录过抛异常 # -全局使用 # -在settings中配置 REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.MyAuths.MyAuth",] } # -局部使用 # -在视图类中配置: authentication_classes=[MyAuth,] # -局部禁用: # -在视图类中配置: authentication_classes=[] -update_or_create() 有就更新,没有就创建 参数:key=value,default={'token':token} # -uuid的使用:生成一个唯一的随机字符串 # -源码分析(大部分人会) # -APIView中的dispatch---》self.initial(认证,频率,权限)---》self.perform_authentication(认证)---》本质又调用了新的request对象的user方法 --》request.user内部执行了:self._authenticate(注意self是新的request对象)-----》循环拿到一个个认证类的对象,执行对象的authenticate方法,传入request对象 ---》一个个认证类的对象是在reuqest对象实例化的时候传入的---》APIView中的get_authenticators,通过列表推导式生成一个个的认证类对象,然后传入request对象中 # -权限 # -使用(所有人都必须会) # -写一个权限类 class MyPermision(BasePermission): message = '不是超级用户,查看不了' def has_permission(self,request,view): if request.user.user_type==1: return True else: return False # -局部使用 # -在视图类中配置: permission_classes=[MyPermision,] # -全局使用 # -在setting中配置 'DEFAULT_PERMISSION_CLASSES':['自定义的权限类'] # -局部禁用: permission_classes=[] # -返回的提示是中文: message=中文 # -源码分析 def check_permissions(self, request): #我猜 一个个对象的列表 for permission in self.get_permissions(): if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None) ) # -视图 # -基本写法(略) # -第二中写法 class PublishView(CreateModelMixin,ListModelMixin,GenericAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializers -写get和post,在其中调用父类的create或者list方法 # -第三种写法: class PublishView(ListCreateAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializers class PublishDetailView(RetrieveUpdateDestroyAPIView): queryset = models.Publish.objects.all() serializer_class = PublishSerializers # -第四种写法(两个视图类合成一个) class PublishView(ModelViewSet): queryset=models.Publish.objects.all() serializer_class=PublishSerializers # -ViewSetMixin重写了as_view方法,路由配置就改了,可以写成映射的形式{get:get_one} # -as_view方法内部执行效果 # 通过反射的取值跟赋值,完成映射,根据请求方式执行对应的方法(比如:get请求执行get_one方法,在路由中配置{get:getone}) # 3 __new__方法的使用 class Test(): def __init__(self,name): print('xxxxxxx') self.name=name def __new__(cls, *args, **kwargs): #返回一个空对象 #现在返回一个字符串对象,内部会去调用字符串对象的__init__方法 # return 'justin' return object.__new__(cls) t=Test('lqz') # print(t.name) ####频率组件##### # -使用: # -第一步,写一个频率类,继承SimpleRateThrottle from rest_framework.throttling import SimpleRateThrottle #重写get_cache_key,返回self.get_ident(request) #一定要记住配置一个scop=字符串 class Throttle(SimpleRateThrottle): scope = 'lxx' def get_cache_key(self, request, view): return self.get_ident(request) # -第二步:在setting中配置 REST_FRAMEWORK = { 'DEFAULT_THROTTLE_RATES':{ 'lxx':'3/m' } } # -局部使用 # -在视图类中配置: throttle_classes=[Throttle,] # -全局使用 # -在setting中配置 'DEFAULT_THROTTLE_CLASSES':['自己定义的频率类'], # -局部禁用 throttle_classes=[] # 频率组件分析: # -核心源代码: def check_throttles(self, request): for throttle in self.get_throttles(): if not throttle.allow_request(request, self): self.throttled(request, throttle.wait()) # -自定义的频率类:详解代码views.py 25行开始 # -SimpleRateThrottle源码 # -url控制 # -基本路由写法:咱们一直写的 # -第二种写法(必须继承只要继承了ViewSetMixin): # url(r'^publish/$', views.PublishView.as_view({'get':'list','post':'create'})), # url(r'^publish\.(?P<format>\w+)$', views.PublishView.as_view({'get':'list','post':'create'})), # url(r'^publish/(?P<pk>\d+)$', views.PublishView.as_view({'get':'retrieve','delete':'destroy','put':'update'})), # -第三种(自动生成路由,必须继承ModelViewSet): -SimpleRouter 自动生成两条路由 from rest_framework.routers import SimpleRouter,DefaultRouter router=SimpleRouter() router.register('publish',views.PublishView) # 路由 url(r'', include(router.urls)), -DefaultRouter自动生成四条路由 from rest_framework.routers import SimpleRouter,DefaultRouter router=DefaultRouter() router.register('publish',views.PublishView) # 路由 url(r'', include(router.urls)), # -解析器(一般不需要动,项目最开始全局配置一下就可以了) # -作用是控制我的视图类能够解析前端传过来的格式是什么样的 # -全局使用: # 在setting中配置: REST_FRAMEWORK = { "DEFAULT_PARSER_CLASSES":[ 'rest_framework.parsers.JSONParser', ] } # -全局使用: # -在视图类中: parser_classes=[JSONParser,] # -源码流程: # -当调用request.data的时候去执行解析方法----》根据传过来的编码方式选择一个解析器对象,调用解析器对象的parser方法完成解析 # -响应器 from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer # -不用动,就用全局配置即可 # -全局使用: # -在setting中配置 'DEFAULT_RENDERER_CLASSES':[JSONRenderer,BrowsableAPIRenderer] # -局部使用: # -在视图类中配置: renderer_classes = [JSONRenderer, BrowsableAPIRenderer] # -版本控制 # -作用用于控制版本 # -全局使用: # -在setting中配置: 'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning', 'DEFAULT_VERSION': 'v1', # 默认版本(从request对象里取不到,显示的默认值) 'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本 'VERSION_PARAM': 'version' # URL中获取值的key # -路由需要修改 -url(r'^(?P<version>[v1|v2]+)/test/', views.Test.as_view()), # -在视图类中就可以通过:request.version取出当前访问哪个版本,相应的取执行相应版本的代码 # -分页   from rest_framework.pagination import CursorPagination,LimitOffsetPagination,PageNumberPagination # 1 常规分页 # -基本使用: -page=PageNumberPagination # 实例化产生对象 # -返回值=page.paginate_queryset(ret,request,self):ret是要分页的所有数据,自动调用Response # -再序列化,序列化该返回值 # -四个参数 #每页显示多少条 page.page_size=3 #查询指定查询哪一页的key值 page.page_query_param='xxx' #前端控制每页显示多少条的查询key值比如size=9,表示一页显示9条 page.page_size_query_param='size' #控制每页最大显示多少,size如果传100,最多也是显示10 page.max_page_size=10 # 2 偏移分页 # -基本使用: page=LimitOffsetPagination实例化产生对象 # -返回值=page.paginate_queryset(ret,request,self):ret是要分页的所有数据, # -再序列化,序列化该返回值 # -四个参数: #从标杆位置往后取几个,默认取3个,我可以指定 page.default_limit=3 #每次取得条数 page.limit_query_param='limit' #标杆值,现在偏移到哪个位置,如果offset=6 表示当前在第6条位置上,往后取 page.offset_query_param='offset' #最大取10条 page.max_limit=10 # 3 cursor游标方式 # -基本使用: -page=CursorPagination实例化产生对象 # -返回值=page.paginate_queryset(ret,request,self):ret是要分页的所有数据, # -再序列化,序列化该返回值 # -三个参数: #每页显示的大小 page.page_size=3 #查询的key值 page.cursor_query_param='cursor' # 按什么排序 page.ordering='id' #-注意:get_paginated_response:调用这个方法返回的数据中会有总条数,上一页地址,下一页地址

 

posted @ 2019-07-08 16:17  希希大队长  阅读(255)  评论(0编辑  收藏  举报