Web Flask学习
flask 基于 wsgi, 依赖 Werkzurg 和模板(Jinja).
innoDB ORM 更像是第三方插件,并不是 flask 需要关心的,当然也是 web 开发少不了的.
wsgi
wsgi wsgi 是 web server 与 web 开发框架之间的协议
Nginx <-----(U)WSGI protocol-----> Gunicorn(WSGI Server) ----(U)WSGI protocol --- > Flask(WSGI Application)
大道至简:
import time
class Server():
def __init__(self):
self.application = None
self.http_stuff = None
self.environ_and_requests = [1, 2 ,'requests' ]
def set_app(self,app):
self.application = app
def construct_response(self,code,header):
self.response_code = code
self.response_header = header
def run_loop(self):
count = 100
some_connection_coming = False
while(count):
some_connection_coming = False
## 异步回调什么的
time.sleep(1)
some_connection_coming = True
#
preprpcess_request()
if some_connection_coming:
# 把environ 和request给application,同时让application回调response
response_body = self.application(self.environ_and_requests,self.construct_response)
print('Server got response stuff %s %s %s ' % (self.response_code,self.response_header,response_body))
preprpcess_response()
send_response()
count -=1
class App():
def application(self,environ, start_response):
print('App got environ got requests. %s' % environ)
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello World!']
server = Server()
server.set_app(App().application)
server.run_loop()
App 就是 wsgi 的开发框架,Server 是实现了 wsgi 的 server:
App got environ got requests. [1, 2, 'requests']
Server got response stuff 200 OK [('Content-Type', 'text/plain')] ['Hello World!']
werkzeug
1 个 wsgi 工具包,wsig 实现的底层库 werkzeug
Template
Jinja2:
Mako 也不错?值得了解一下,跟 python 结合的比较好,更灵活。
orm
Object relational model.
将 ORUD (open read update delete)的 innoDB 的操作,用对象来实现,通过对象来表现,描述,修改数据库。比直接用 sql 语言,来的更方便。
flask-sqlalchemy
有的查询/插入特别慢,通过简单的配置,就可以专门的记录这些查询到转门的 log 里面.cool!
peewee
更轻量
flask
轻量的 wsgi web 开发框架
route
路由就是灵活性,不同的 url 处理不同的功能,越能应付复杂的 url 路由,web 功能越强大。如何更好的路由?
# basic
@app.add_route('/static/v/')
def v():
print('hi')
# v替换成其他?
@app.add_route('/static/<id>/')
def v1(id):
print('hi' +id)
# 多个变量?
@app.add_route('/static/<id1>/<id2>')
def v1(id1,id2):
print(id1+id2)
# 正则?需要用到flask Converter
# @app.route('/api/(.*?)')
from flask import Flask
from werkzeug.routing import BaseConverter
class RegexConverter(BaseConverter):
def __init__(self, map, *args):
self.map = map
self.regex = args[0]
app = Flask(__name__)
app.url_map.converters['regex'] = RegexConverter
@app.route('/docs/model_utils/<regex(".*"):url>')
def hello(url=None):
print(url)
context
flask context->线程局部变量-->werkzurg的LocalProxy LocalStack
flask 比较重要的知识点了
LocalStack 用 Local 来存各个线程的局部变量,用线程 id 来区分
class Local(object):
def __init__(self):
object.__setattr__(self, '__storage__', {})
object.__setattr__(self, '__ident_func__', get_ident)
def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}
Local 大概是这么个结构:
{
'thread_id1':{'stack':[_RequestContext(),_RequestContext(),_RequestContext(),..]},
'thread_id2':{'stack':[_RequestContext(),_RequestContext(),...]}
}
LocalStack 的操作,无非是把各个线程可能产生的局部变量(name-value) push/pop,或者直接取栈顶元素.
而整个 flask,运行了一个_request_ctx_stack,保存所有的线程的 request,url 等, 全局共享.
_request_ctx_stack = LocalStack();
还有几个关键的关键变量,自然就是拿到当前 top 线程上的各种数据了.
current_app = LocalProxy(lambda: _request_ctx_stack.top.app)
request = LocalProxy(lambda: _request_ctx_stack.top.request)
session = LocalProxy(lambda: _request_ctx_stack.top.session)
g = LocalProxy(lambda: _request_ctx_stack.top.g)
通过 LocalStack 和 LocalProxy 这样的 Python 魔法,每个线程访问当前请求中的数据(request, session)时, 都好像都在访问一个全局变量,但是,互相之间又互不影响。
反过来再思考,如果不用这个机制又会有什么?那肯定视图函数里,肯定要带参数,就像 falcon 做的那样!好像也没啥不方便的.关键都是用什么样的数据结构
,维护不同 url 不同请求的数据.
# flask
@add_route('/')
def index(request,environ):
print('hello index)
# falcon
class IndexHander(object);
"""
falcon
"""
def on_get(self,req,response)
print('hello get')
def on_post(self,req,response)
print('hello post')
app.add_route('/',IndexHander())
上面说的主要是 request context,再 flask 0.9 后还引入了新的 application context:
application 机制是为了处理多应用
场景的,这个比较少见.
app1 = Flask('app1')
app2 = Flask('app2')
signal
基于 Blinker,封装 signal 的事件分发的库,很多人推荐的 python 初学级别的源码库.
基于 blinker signal,在一些时机可以注册回调
, 如模板渲染完成,请求上下文 ready,发送 response 前,等等.
配合 werkzurg
很强的 wsgi 底层库,很多有用的 tools 函数