本flask源码分析不间断更新

而且我分析的源码全是我个人觉得是很漂亮的

1 flask-login

1.1 flask.ext.login.login_required(func),下面是它的文档的官方源码

 def login_required(func):
'''
If you decorate a view with this, it will ensure that the current user is
logged in and authenticated before calling the actual view. (If they are
not, it calls the :attr:`LoginManager.unauthorized` callback.) For
example:: @app.route('/post')
@login_required
def post():
pass If there are only certain times you need to require that your user is
logged in, you can do so with:: if not current_user.is_authenticated:
return current_app.login_manager.unauthorized() ...which is essentially the code that this function adds to your views. It can be convenient to globally turn off authentication when unit testing.
To enable this, if the application configuration variable `LOGIN_DISABLED`
is set to `True`, this decorator will be ignored. :param func: The view function to decorate.
:type func: function
'''
@wraps(func)
def decorated_view(*args, **kwargs):
if current_app.login_manager._login_disabled:
return func(*args, **kwargs)
elif not current_user.is_authenticated:
return current_app.login_manager.unauthorized()
return func(*args, **kwargs)
return decorated_view

其实这个login_required方法和我最开始认为的一样,就是用一个装饰器包裹着func,里面有一个对用户是否login有个判断,最后返回func。

1.1.1 根据官方文档可以看出,这个方法有两种使用方式

  第一种是对装饰的func,也就是最常用的方式。

  第二种是仅仅使用一次,用一次判断是否已authorize,要没有进行authorize。

1.1.2 下面具体分析

  首先这个login_required的方法的基本方式就是:用装饰器包裹func,里面进行一次authorize,current_app.login_manager.unauthorized()。

  然后说一下主要逻辑:如果用户login了,但没authorize,就进行authorize,如果没有login就返回原func。

  其中current_app.login_manager._login_disabled这个函数的目的是:判断全局变量中LOGIN_DISABLE是否为真,而这个函数的目的是控制这个装饰器是否生效。

2 flask的route方法,基于flask0.1最初版本

到目前还没有看过werkzeug的源码,所以有些不足以后补充

首先是route方法的源码:

    def route(self, rule, **options):
"""A decorator that is used to register a view function for a
given URL rule. Example:: @app.route('/')
def index():
return 'Hello World' Variables parts in the route can be specified with angular
brackets (``/user/<username>``). By default a variable part
in the URL accepts any string without a slash however a different
converter can be specified as well by using ``<converter:name>``. Variable parts are passed to the view function as keyword
arguments. The following converters are possible: =========== ===========================================
`int` accepts integers
`float` like `int` but for floating point values
`path` like the default but also accepts slashes
=========== =========================================== Here some examples:: @app.route('/')
def index():
pass @app.route('/<username>')
def show_user(username):
pass @app.route('/post/<int:post_id>')
def show_post(post_id):
pass An important detail to keep in mind is how Flask deals with trailing
slashes. The idea is to keep each URL unique so the following rules
apply: 1. If a rule ends with a slash and is requested without a slash
by the user, the user is automatically redirected to the same
page with a trailing slash attached.
2. If a rule does not end with a trailing slash and the user request
the page with a trailing slash, a 404 not found is raised. This is consistent with how web servers deal with static files. This
also makes it possible to use relative link targets safely. The :meth:`route` decorator accepts a couple of other arguments
as well: :param rule: the URL rule as string
:param methods: a list of methods this rule should be limited
to (``GET``, ``POST`` etc.). By default a rule
just listens for ``GET`` (and implicitly ``HEAD``).
:param subdomain: specifies the rule for the subdoain in case
subdomain matching is in use.
:param strict_slashes: can be used to disable the strict slashes
setting for this rule. See above.
:param options: other options to be forwarded to the underlying
:class:`~werkzeug.routing.Rule` object.
"""
def decorator(f):
self.add_url_rule(rule, f.__name__, **options)
self.view_functions[f.__name__] = f
return f
return decorator

注释部分主要是使用方法不过多说明

2.1.1 分析装饰器

  它的装饰器用的很巧妙,装饰器的wraper传入的是参数,而inner传入的是func, 所以在inner函数内部会返回func

2.1.2 内部主要方法

  add_url_rule(rule, f.__name__, **options) 这个方法主要是将route的路由和option进行注册

  view_functions[f.__name__] 就是在view_function字典中添加这个route的函数名

2.2 add_url_rule 方法

说道注册路由就不得不提这个方法了,首先展示一下源码

     def add_url_rule(self, rule, endpoint, **options):
"""Connects a URL rule. Works exactly like the :meth:`route`
decorator but does not register the view function for the endpoint. Basically this example:: @app.route('/')
def index():
pass Is equivalent to the following:: def index():
pass
app.add_url_rule('index', '/')
app.view_functions['index'] = index :param rule: the URL rule as string
:param endpoint: the endpoint for the registered URL rule. Flask
itself assumes the name of the view function as
endpoint
:param options: the options to be forwarded to the underlying
:class:`~werkzeug.routing.Rule` object
"""
options['endpoint'] = endpoint
options.setdefault('methods', ('GET',))
self.url_map.add(Rule(rule, **options))

注释也不过多解释

它的主要工作就是将route的rule和endpoint建立关系。通过 url_map.add(Rule(rule, **options)) 方法。

2.3 url_map

实际上是flask的和核心库 werkzeug 自己定义的一个存储url路径的‘仓库’,

werkzeug 最核心的路由功能:添加路由规则(也可以使用 m.add),把路由表绑定到特定的环境(m.bind),匹配url(urls.match)。正常情况下返回对应的 endpoint 名字和参数字典,可能报重定向或者 404 异常。

其实是 url 到 endpoint 的转换:通过 url 找到处理该 url 的 endpoint。至于 endpoint 和 view function 之间的匹配关系,werkzeug 是不管的。

2.4 dispatch_request

def dispatch_request(self):
"""Does the request dispatching. Matches the URL and returns the
return value of the view or error handler. This does not have to
be a response object. In order to convert the return value to a
proper response object, call :func:`make_response`.
""" req = _request_ctx_stack.top.request
if req.routing_exception is not None:
self.raise_routing_exception(req)
rule = req.url_rule # dispatch to the handler for that endpoint
return self.view_functions[rule.endpoint](**req.view_args)

这个方法做的事情就是找到请求对象 request,获取它的 endpoint,然后从 view_functions 找到对应 endpoint 的 view_func ,把请求参数传递过去,进行处理并返回。

补 flask路由规则

  • 通过 @app.route 或者 app.add_url_rule 注册应用 url 对应的处理函数
  • 每次请求过来的时候,会事先调用路由匹配的逻辑,把路由结果保存起来
  • dispatch_request 根据保存的路由结果,调用对应的视图函数

最后分享来自segementfault的_Zhao的 文章, 他的路由思想和我理解的想法差不多。

----补 2017/2/22----

介绍一个搭建RESTful API 之 实现WSGI服务的URL映射,也是类似于router源代码的介绍,说的很不错。

flask源码分析的更多相关文章

  1. Flask源码分析二:路由内部实现原理

    前言 Flask是目前为止我最喜欢的一个Python Web框架了,为了更好的掌握其内部实现机制,这两天准备学习下Flask的源码,将由浅入深跟大家分享下,其中Flask版本为1.1.1. 上次了解了 ...

  2. Flask源码分析一:服务启动

    前言: Flask是目前为止我最喜欢的一个Python Web框架了,为了更好的掌握其内部实现机制,这两天准备学习下Flask的源码,将由浅入深跟大家分享下,其中Flask版本为1.1.1. Flas ...

  3. 【Flask源码分析——请求上下文与应用上下文】

    Flask中有两种上下文,请求上下文和应用上下文.两者的作用域都处于一个请求的局部中. 查看源代码,上下文类在flask.ctx模块中定义 AppContext类定义应用上下文,app是当前应用Web ...

  4. Flask源码剖析详解

    1. 前言 本文将基于flask 0.1版本(git checkout 8605cc3)来分析flask的实现,试图理清flask中的一些概念,加深读者对flask的理解,提高对flask的认识.从而 ...

  5. Flask系列10-- Flask请求上下文源码分析

    总览 一.基础准备. 1. local类 对于一个类,实例化得到它的对象后,如果开启多个线程对它的属性进行操作,会发现数据时不安全的 import time from threading import ...

  6. Flask系列之源码分析(一)

    目录: 涉及知识点 Flask框架原理 简单示例 路由系统原理源码分析 请求流程简单源码分析 响应流程简单源码分析 session简单源码分析 涉及知识点 1.装饰器 闭包思想 def wapper( ...

  7. flask框架(三)——路由系统route转换成add_url_rule及源码分析

    这节我们不用@app.route来写路由,而是通过add_url_rule 传统写法  (<int:nid>传递int类型参数,endpoint是取别名) @app.route('/det ...

  8. flask/app.py-add_url_rule源码分析

    之前分析route方法的时候,可以看到中间会调用add_url_rule方法,add_url_rule方法和route方法一样属于Flask这个类的. add_url_rule方法主要用来连接url规 ...

  9. Flask框架(三)—— 请求扩展、中间件、蓝图、session源码分析

    Flask框架(三)—— 请求扩展.中间件.蓝图.session源码分析 目录 请求扩展.中间件.蓝图.session源码分析 一.请求扩展 1.before_request 2.after_requ ...

随机推荐

  1. [LeetCode] Swap Nodes in Pairs 成对交换节点

    Given a linked list, swap every two adjacent nodes and return its head. For example,Given 1->2-&g ...

  2. swfit-学习笔记(表UITableView的简单使用)

    /*使用与Object-C基本类似,只做简单地使用,创建表及其设置数据源和代理*/ import UIKit class ViewController: UIViewController,UITabl ...

  3. 【UOJ #35】后缀排序 后缀数组模板

    http://uoj.ac/problem/35 以前做后缀数组的题直接粘模板...现在重新写一下模板 注意用来基数排序的数组一定要开到N. #include<cstdio> #inclu ...

  4. java为什么非静态内部类中不能有static修饰的属性,但却可以有常量?

    如:public class InnerClassDemo{int x;class A{static int a = 0;//这样写是不合法的.static final int b=0;//这样写是合 ...

  5. Beta版本冲刺第三天

    Aruba 408 409 410 428 429 431 完成任务: 分类界面,实现手动新增/删除分类 分类界面,设置确定和取消按钮的intent 实现图片在编辑界面导入并合理摆放 立会照片: 燃尽 ...

  6. supervisor监管进程max file descriptor配置不生效的问题

    配置了 sudo vim /etc/security/limits.conf * soft nofile * hard nofile   单独起进程没问题, 放到supervisor下监管启动,则报错 ...

  7. linux下安装不同版本的jdk

    问题: 因为需要使用jmeter的插件,发现jmeter最新版apache-jmeter-3.0可用,但是其需要jdk1.7以上版本,而公司服务器上jdk均为1.6版本,于是在测试账号下安装多个版本j ...

  8. git 命令操作

    git add .   : 将所有修改过的工作文件提交暂存区 git commit -am 'new'  : 将修改过的文件进行记录 git push origin dev : 将项目推送到dev分只 ...

  9. Comet技术

    1.Comet是什么? 维基百科: Comet是一种用于web的推送技术,能使服务器实时地将更新的信息传送到客户端,而无须客户端发出请求,目前有两种实现方式,长轮询和iframe流. 说白了就是web ...

  10. Python数据分析笔记目录

    速查笔记 使用实例 Pandas-数据导入 (未完成) Pandas-数据探索 基础属性 shape indexs columns values dtype/dtypes 汇总和计算描述统计 coun ...