flask多app和栈的应用
一、简介
flask的蓝图可以实现url的分发,当有多个app时也可以利用app进行url分发,这里介绍下使用方式和内部原理以及栈的应用。
二、多app使用
使用示例
from werkzeug.wsgi import DispatcherMiddleware
from werkzeug.serving import run_simple
from flask import Flask app01 = Flask('app01')
app02 = Flask('app02') @app01.route('/index')
def index():
return "app01" @app02.route('/index')
def index2():
return "app02" app = DispatcherMiddleware(app01, {
'/app01': app01,
'/app02': app02,
})
#默认使用app01的路由,也就是访问 http://127.0.0.1:5000/index 返回app01
#当以app01开头时候使用app01的路由,也就是http://127.0.0.1:5000/app01/index 返回app01
#当以app02开头时候使用app02的路由,也就是http://127.0.0.1:5000/app02/index 返回app02 if __name__ == "__main__":
run_simple('127.0.0.1', 5000, app)
实现原理
多app使用借助于DispatcherMiddleware,让我们看看其源码类的定义:
class DispatcherMiddleware(object):
    """Allows one to mount middlewares or applications in a WSGI application.
    This is useful if you want to combine multiple WSGI applications::
        app = DispatcherMiddleware(app, {
            '/app2':        app2,
            '/app3':        app3
        })
    """
    def __init__(self, app, mounts=None):
        self.app = app
        self.mounts = mounts or {}
    def __call__(self, environ, start_response):
        script = environ.get('PATH_INFO', '')
        path_info = ''
        while '/' in script:
            if script in self.mounts:
                app = self.mounts[script]
                break
            script, last_item = script.rsplit('/', 1)
            path_info = '/%s%s' % (last_item, path_info)
        else:
            app = self.mounts.get(script, self.app)
        original_script_name = environ.get('SCRIPT_NAME', '')
        environ['SCRIPT_NAME'] = original_script_name + script
        environ['PATH_INFO'] = path_info
        return app(environ, start_response)
def __call__(self, environ, start_response):
script = environ.get('PATH_INFO', '')
path_info = ''
while '/' in script:
if script in self.mounts:
app = self.mounts[script]
break
script, last_item = script.rsplit('/', 1)
path_info = '/%s%s' % (last_item, path_info)
else:
app = self.mounts.get(script, self.app)
original_script_name = environ.get('SCRIPT_NAME', '')
environ['SCRIPT_NAME'] = original_script_name + script
environ['PATH_INFO'] = path_info
return app(environ, start_response)
当script = /index是,while条件成立,同时对判断 /index是否在self.mounts,显然此时不在,分割/index,修改script为空,此时while不成立,执行app = self.mounts.get(script, self.app),返回self.app也就是app01,接着运行app01(),这也就是和在上下文中流程一样了。究其本质,就是通过url匹配出是哪个app,在运行该app的__call__方法。
三、栈是使用
flask中的请求数据存放实际利用列表构造的栈来存储的,每次pop都从最后pop出栈。当我们在进行测试或者写flask离线脚本时候可能会使用到上下文嵌套,例如:
from flask import Flask, current_app, _app_ctx_stack
app1 = Flask('app01')
app1.debug = False
app2 = Flask('app02')
app2.debug = True
with app1.app_context():
    print(_app_ctx_stack._local.__storage__)
    #{<greenlet.greenlet object at 0x10dc79e88>: {'stack': [<flask.ctx.AppContext object at 0x10dda7b00>]}}
    print(current_app.config['DEBUG']) # False
    with app2.app_context():
        print(_app_ctx_stack._local.__storage__)
        #{<greenlet.greenlet object at 0x10dc79e88>: {'stack': [<flask.ctx.AppContext object at 0x10dda7b00>, <flask.ctx.AppContext object at 0x10dda7c18>]}}
        print(current_app.config['DEBUG']) # True
    print(current_app.config['DEBUG'])  # False
在以上示例中在app01的上下文中嵌套了app02的上下文,所以在栈中会有两个app_ctx,但是在各自取上下文的时候都不会冲突,因为app02的上下文在最后,也就是第二个with中top是app02的app_ctx。
四、关于with
class Foo(object):
def __init__(self,name):
self.name=name
def __enter__(self):
print('run __enter__')
return self.name def __exit__(self, exc_type, exc_val, exc_tb):
print('run __exit__') with Foo('wd') as myname:
print("vars:",myname) 结果:
run __enter__
vars: wd
run __exit__
可能你会注意在到,在以上的demo中__exit__方法中多了三个参数,即exc_type、exc_val、exc_tb这是对应着在with语句中代码出现异常时也会执行__exit__并接受异常,分别对应着:异常类型、异常值、以及异常的traceback。示例:
class Foo(object):
def __init__(self,name):
self.name=name
def __enter__(self):
print('run __enter__')
return self.name def __exit__(self, exc_type, exc_val, exc_tb):
print('run __exit__')
print('exc_type:',exc_type)
print('exc_val:',exc_val)
print('exc_tb:',exc_tb) with Foo('wd') as myname:
print("vars:", myname)
a=[]
v=a[1]
print(v) 结果:
run __enter__
vars: wd
run __exit__
exc_type: <class 'IndexError'>
exc_val: list index out of range
exc_tb: <traceback object at 0x10ec98508>
Traceback (most recent call last):
File "dbapi.py", line 21, in <module>
v=a[1]
IndexError: list index out of range
最后我们回过头来看看app_context()对象中的__enter__方法和__exit__方法:
def __enter__(self):
self.push()
return self def __exit__(self, exc_type, exc_value, tb):
self.pop(exc_value) if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
reraise(exc_type, exc_value, tb)
实际上非常简单,执行__enter__时候调用push压栈,执行__exit__时pop出栈,这样就使得每个with里面都是当前app的上下文,而不会冲突。
flask多app和栈的应用的更多相关文章
- python 全栈开发,Day142(flask标准目录结构, flask使用SQLAlchemy,flask离线脚本,flask多app应用,flask-script,flask-migrate,pipreqs)
		
昨日内容回顾 1. 简述flask上下文管理 - threading.local - 偏函数 - 栈 2. 原生SQL和ORM有什么优缺点? 开发效率: ORM > 原生SQL 执行效率: 原生 ...
 - Flask之app实例的参数配置
		
说是app实例的配置, 实际也就是flask程序的配置 Flask 是一个非常灵活且短小精干的web框架 , 那么灵活性从什么地方体现呢? 有一个神奇的东西叫 Flask配置 , 这个东西怎么用呢? ...
 - Flask Vue.js全栈开发
		
Flask Vue.js全栈开发的 最新完整代码 及使用方式 本系列的最新代码及使用方式将持续更新到: http://www.madmalls.com/blog/post/latest-code/ 1 ...
 - python框架之Flask(5)-@app.before_request原理
		
示例 from flask import Flask app = Flask(__name__) @app.before_request def xx(): pass @app.route('/') ...
 - 【问题记录】uwsgi部署并启动俩个几乎一样的python flask web app,发现有一个app响应时间非常长
		
uwsgi在同一台linux上启动python flask web app(俩个), 发现第一个和第二个的简单性能测试差距非常大,差了将近一倍: 第一个结果: Concurrency Level: 1 ...
 - Flask 框架app = Flask(__name__) 解析
		
#!/usr/local/bin/python # coding=utf-8 from flask import Flask app = Flask(__name__) @app.route('/') ...
 - Flask - 运行APP
		
from flask import Flask app = Flask(__name__) @app.route("/") def hello(): return 'Hello, ...
 - flask 学习app代码备份
		
#!/usr/bin/python # -*- coding: UTF-8 -*- from flask import Flask, url_for from flask import request ...
 - Flask - 多APP应用(不太重要)
		
1. 多APP应用 请求进来时,可以根据URL的不同,交给不同的APP处理.一般用蓝图也可以实现.一般不写多app应用. from werkzeug.wsgi import DispatcherMid ...
 
随机推荐
- Android Studio_更新Gradle
			
一.Gradle更新问题 Android Studio每次更新版本都会更新Gradle这个插件,而且有时候提示更新,却一直更新不了,那是因为中国伟大的长城问题.就是下图,我刚刚更新了,提示更新grad ...
 - vmare连接远程服务器的问题
			
测试环境:两端都是VMware Workstation 12 Pro 1.需要共享虚拟机 在虚拟机上点击右键 -> Manage -> Share 后面按照操作设置 2.远程服务器的443 ...
 - 我的博客:C# PHP J2ee Java Android js WP Asp.net mvc Python
			
<p><A target="_blank" href="http://blog.163.com/hr_company_product/" &g ...
 - [20180316]为什么不使用INDEX FULL SCAN (MIN/MAX).txt
			
[20180316]为什么不使用INDEX FULL SCAN (MIN/MAX).txt --//链接:http://www.itpub.net/thread-2100456-1-1.html.自己 ...
 - [20171218]varchar2(4000)如何保存.txt
			
[20171218]varchar2(4000)如何保存.txt --//以前写的,不知道为什么被删除了,现在补上. 如果一行能被存储于一个数据块(data block)中,那么其行头(row hea ...
 - asp.net mvc中的后台验证
			
asp.net mvc的验证包含后台验证和前端验证.后台验证主要通过数据注解的形式实现对model中属性的验证,其验证过程发生在model绑定的过程中.前端验证是通过结合jquery.validate ...
 - SMP多核启动
			
在 Linux系统中,对于多核的ARM芯片而言,在Biotron代码中,每个CPU都会识别自身ID,如果ID是0,则引导Bootloader和 Linux内核执行,如果ID不是0,则Biotron一般 ...
 - Git的gc功能
			
http://blog.csdn.net/lihuanshuai/article/details/37345565 Git的底层并没有采用 CVS.SVN 底层所采用的那套增量式文件系统,而是采用一套 ...
 - MySQL面试题之如何优化一条有问题的SQL语句?
			
如何优化一条有问题的sql语句? 针对sql语句的优化.我们可以从如下几个角度去分析 回归到表的设计层面,数据类型选择是否合理 大表碎片的整理是否完善 表的统计信息,是不是准确的 审查表的执行计划,判 ...
 - 1.1开篇一:C语言编译器的选择---Dev C++
			
返回总目录 目录: 1.Dev C++的下载&安装: 2.Dev C++的使用: 前言: 那么多编译器,为什么选择Dev C++?理由有下 理由一:Dev C++ 体积比较小,不占用太多的内存 ...