文章目录
  1. 1.wsgi
  2. 2.werkzeug
  3. 3.Template
  4. 4.orm
    1. 4.1.flask-sqlalchemy
    2. 4.2.peewee
  5. 5.flask
    1. 5.1.route
    2. 5.2.context
    3. 5.3.signal
    4. 5.4.配合 werkzurg

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:

Screenshot from 2019-01-02 10-13-14-30e1ea96-9c10-4e9d-99c5-326398ce586cScreenshot from 2019-01-02 10-13-14-30e1ea96-9c10-4e9d-99c5-326398ce586c

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 介绍

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:

request context

application 机制是为了处理多应用场景的,这个比较少见.

app1 = Flask('app1')
app2 = Flask('app2')

signal

基于 Blinker,封装 signal 的事件分发的库,很多人推荐的 python 初学级别的源码库.

基于 blinker signal,在一些时机可以注册回调, 如模板渲染完成,请求上下文 ready,发送 response 前,等等.

配合 werkzurg

很强的 wsgi 底层库,很多有用的 tools 函数

Related Issues not found

Please contact @anribras to initialize the comment

文章目录
  1. 1.wsgi
  2. 2.werkzeug
  3. 3.Template
  4. 4.orm
    1. 4.1.flask-sqlalchemy
    2. 4.2.peewee
  5. 5.flask
    1. 5.1.route
    2. 5.2.context
    3. 5.3.signal
    4. 5.4.配合 werkzurg