REST framework (组件源码流程分析)
阅读目录
一、APIView & View
二、组件源码流程
一、APIView & View
- View
- 路径:django.views.View
- 使用:
- urls: path('xxx/', views.xxxx.as_view(), name='xxx')
- 视图:class xxxx(View):
- ApiView
- 路径:from rest_framework.views import APIView
- 使用:
- urls: path('xxx/', views.xxAPI.as_view(), name='xxx')
- 视图:class xxAPI(APIView):
- APIView继承View,重写as_view(),增加扩展配置
二、组件源码流程分析
1. APIView源码分析
1.路由:url(r'^books/$', views.BookView.as_view(),name="books") # View下的view 2.请求:books/一旦被访问 执行APIView.as_view() -> APIView: dispatch() view = super(APIView, cls).as_view(**initkwargs) 3.def dispatch(): # APIView # request加工 request = self.initialize_request(request, *args, **kwargs) def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), # 解析器 authenticators=self.get_authenticators(), # 认证组件 negotiator=self.get_content_negotiator(), parser_context=parser_context ) # 构建request对象 self.request=Request(request) class Request(object): self._request = request # 原request def query_params(self): return self._request.GET def data(self): return post.data # post请求数据 self.request._request self.request.GET # get self.request.data # POST PUT # 初始化组件信息 self.initial(request, *args, **kwargs) 分发----if get请求: if request.method.lower() in self.http_method_names: handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) # 视图: self.get(request, *args, **kwargs) return response 4.csrf_exempt(view) #排除csrf
1.1 APIView().initial() 流程
def initial(self, request, *args, **kwargs): """ Runs anything that needs to occur prior to calling the method handler. """ # 1.确定请求是否包含“.json”样式格式后缀 self.format_kwarg = self.get_format_suffix(**kwargs) # Perform content negotiation and store the accepted info on the request neg = self.perform_content_negotiation(request) def perform_content_negotiation(self, request, force=False): """ Determine which renderer and media type to use render the response. """ # 2.渲染器 renderers = self.get_renderers() # [renderer() for renderer in self.renderer_classes] # 3.协商类 conneg = self.get_content_negotiator() # if not getattr(self, '_negotiator', None): # self._negotiator = self.content_negotiation_class() # return self._negotiator try: # 选择渲染器 return conneg.select_renderer(request, renderers, self.format_kwarg) except Exception: if force: return (renderers[0], renderers[0].media_type) raise # 调用request对象__setattr__赋值 request.accepted_renderer, request.accepted_media_type = neg # Determine the API version, if versioning is in use. version, scheme = self.determine_version(request, *args, **kwargs) def determine_version(self, request, *args, **kwargs): """ If versioning is being used, then determine any API version for the incoming request. Returns a two-tuple of (version, versioning_scheme) """ if self.versioning_class is None: return (None, None) # 4.version组件 scheme = self.versioning_class() # api_settings.DEFAULT_VERSIONING_CLASS return (scheme.determine_version(request, *args, **kwargs), scheme # 调用request对象__setattr__赋值 request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted # 5.认证组件 self.perform_authentication(request) # 默认执行 def perform_authentication(self, request): request.user #执行request的user,这是的request已经是加工后的request了
@property def user(self): """ Returns the user associated with the current request, as authenticated by the authentication classes provided to the request. """ if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() # return self._user #返回user
# 执行self._authenticate() 开始用户认证,如果验证成功后返回元组: (用户,用户Token)
def _authenticate(self):
""" Attempt to authenticate the request using each authentication instance in turn. """ #循环对象列表 for authenticator in self.authenticators: try: #执行每一个对象的authenticate 方法 user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise if user_auth_tuple is not None: self._authenticator = authenticator self.user, self.auth = user_auth_tuple #返回一个元组,user,和auth,赋给了self, # 只要实例化Request,就会有一个request对象,就可以request.user,request.auth了 return self._not_authenticated()
# 如果没有认证成功
def _not_authenticated(self):
""" Set authenticator, user & authtoken representing an unauthenticated request. Defaults are None, AnonymousUser & None. """ #如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None # if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() # 默认值为:匿名用户AnonymousUser else: self.user = None # None 表示跳过该认证 if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() # 默认值为:None else: self.auth = None # (user, token) # 表示验证通过并设置用户名和Token; # AuthenticationFailed异常
# 6.权限组件
self.check_permissions(request)
def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
)
#if request.authenticators and not request.successful_authenticator:
# raise exceptions.NotAuthenticated()
# raise exceptions.PermissionDenied(detail=message)
# 7.频率组件
self.check_throttles(request)
def check_throttles(self, request):
"""
Check if request should be throttled.
Raises an appropriate exception if the request is throttled.
"""
for throttle in self.get_throttles():
if not throttle.allow_request(request, self):
self.throttled(request, throttle.wait()) # exceptions.Throttled(wait)
APIView().dispatch() 执行结束分发至视图,紧接着执行视图中的 def get(request, *args, **kwargs) ,def post(request, *args, **kwargs) 等
2. 视图执行流程
操作数据:以Book表为例 class BookView(APIView): # 查看所有书籍 def get(self,request): book_list=Book.objects.all() bs=BookModelSerializers(book_list,many=True,context={'request': request}) return Response(bs.data) # 添加一本书籍 def post(self,request): # post请求的数据 bs=BookModelSerializers(data=request.data) if bs.is_valid(): print(bs.validated_data) bs.save()# create方法 return Response(bs.data) else: return Response(bs.errors) class BookDetailView(APIView): # 查看一本书籍 def get(self,request,id): book=Book.objects.filter(pk=id).first() bs=BookModelSerializers(book,context={'request': request}) return Response(bs.data) # 更新一本书籍 def put(self,request,id): book=Book.objects.filter(pk=id).first() bs=BookModelSerializers(book,data=request.data) if bs.is_valid(): bs.save() return Response(bs.data) else: return Response(bs.errors) # 删除某一本书籍 def delete(self,request,id): Book.objects.filter(pk=id).delete() return Response()
分析:获取所有书籍,执行get方法查询数据库,返回对象/queryset交给自定制序列化类,分页后Response返回给前端,这个过程中DRF组件体现:
- 序列化组件
- 分页组件
- 渲染器
三、总结
根据上面的分析,总结DRF包含的几大组件如下:
请求进来:
- 路由(可自定制路由)
- 版本
- 认证
- 权限
- 频率
- 获取数据(解析器)请求头解析
- 序列化
- 分页
- 渲染器
- 视图 # DRF视图不只有APIView
本文基于APIView源码流程分析总结DRF几大组件,组件的使用请见 REST framework (组件使用)