前言
最近学习了 django 的一个 restframework 框架, 对于里面的执行流程产生了兴趣, 经过昨天一晚上初步搞清楚了执行流程 (部分方法还不太清楚), 于是想详细的总结一下当来一个请求时, 在该框架里面是如何执行的?
启动项目时
昨天在调试 django 时, 发现在 APIView 中打的断点没有断下来, 而是打在 View 中的断点断下来了, 调试了很多次, 最后发现, 在 django 项目启动时, 会首先加载 urls 中的文件, 执行 views 中类的 as_view 方法, 其实是继承自 APIView 的, APIView 继承自 django 原生 View 的 as_view 方法.
里面一个参数叫 pattern_name, 对应的值是 admin:auth_group_change, 如下图所示:
目前还不清楚这里面的具体流程是什么, 但是并不妨碍阅读之后的源码, 在这只要清楚一点, 在 Django 项目启动时, 路由所对应的 CBV 里面的相关方法的内存地址已经获取到. 这样做的好处就是提高效率, 坏处可能有一点点, 会提升性能的消耗.
具体路由和逻辑代码
在这里假设来一个 GET 请求, urls 和 views 里面的代码如下:
- # urls.py
- url(r'^book/(?P<id>\d+)/', views.Book.as_view()),
- # views.py
- class Book(APIView):
- def dispatch(self, request, *args, **kwargs):
- return super().dispatch(request, *args, **kwargs)
- def get(self, request, id):
- response = {'status': 100, 'msg': None}
- book = models.Book.objects.filter(pk=id).first()
- book_ser = BookSerib(book, many=False)
- print('book_ser.data', book_ser.data)
- response['books'] = book_ser.data
- response['msg'] = '获取图书成功'
- print('response', response)
- return Response(response)
urls 里面就是一个典型的 CBV 的路由配置, 在 views 中一个是路由分发方法, 一个是获取单本图书信息 (通过 id).
as_view 具体执行流程
在项目启动时, 相应的函数内存地址已经获取到, 那么具体是怎么获取到的呢?
在上面的代码中可以看到 Book 类是继承自 APIView 类的, 所以在路由配置里面执行的 as_view 方法如果 Book 类没有重写, 那么执行的就是按照 mro 列表顺序查找到的第一个方法, 在这里执行的是 APIView 类中的 as_view 方法.
查看该源码如下:
APIView 类的父类是 View 类, 查看该类的 as_view 方法, 源码如下:
具体 as_view 就是将 view 函数的内存地址返回, 以便请求来时直接调用.
而 initkwargs 这个参数应该是由 django 内部传的一些参数, 如下所示:
请求到来时
因为经过 django 先执行了 as_view 返回 view 的内存地址, 所以会直接执行 view 函数, 如下:
在这里该 self 由于是 继承自 APIView 类的 Book 类的对象, 所以 dispatch 方法首先去自身找, 之后去父类找, 在 APIView 类中找到 dispatch 方法, 源码如下:
initialize_request 方法:
源码如下:
在实例化 Request 对象时, authenticators 参数需要在认证时使用, 所以先把这个参数的值找出来. 步骤如下:
调用 self.get_authenticators
找到 self.authentication_classes
找到 api_settings, 才能找到 DEFAULT_AUTHENTICATION_CLASSES
DEFAULT 和 IMPORT_STRINGS 参数
DEFAULT 参数
IMPORT_STRINGS 参数
实例化 APISettings 对象
通过__getattr__方法获取值
执行 perform_import 方法
执行 import_from_string
执行 import_module
执行_bootstrap._gcd_import
执行_sanity_check
_sanity_check 返回, 执行_find_and_load 方法
所以通过__getattr__的到的是一个列表, 里面是两个类, 分别是 [rest_framework_authentication_SessionAuthentication, rest_framework_authentication_BasicAuthentication]
到这里, initialize_request 方法执行结束, 得到一个经过 Request 类实例化的 request 对象, 该对象里面含有原生 request 对象, 可以通过 request._request 取到.
initial 方法:
源码如下:
这里传入的 request 参数是经过 Request 封装后的参数
执行 get_format_suffix
执行完这个方法, self_format_kwarg = None,
执行 perform_content_negotiation
执行 self.get_renders
执行 self.get_content_negotiator
执行 conneg.select_renderer 方法
未完待续......
来源: https://www.cnblogs.com/zuanzuan/p/10412165.html