Flask基础


1.什么是wsgi

wsgi

wsgi是一种规范.全称Python Web Server Gateway Interface,指定了web服务器和Python web应用或web框架之间的标准接口.WSGI规定,Web程序必须有一个可调用对象,且该可调用对象接收两个参数,返回一个可迭代对象:

environ:字典,包含请求的所有信息

start_response:在可调用对象中调用的函数,用来发起响应,参数包括状态码,headers等

uwsgi

uwsgi是uWSGI服务器的独占协议.

uWSGI

uWSGI:是一个web服务器,实现了WSGI协议、uwsgi协议、http协议等.

符合wsgi的application

1 def application(environ,srart_response):
2     start_response('200 OK', [('Content-Type', 'text/plain')])
3     return ['This is a python application!']
1 class ApplicationClass(object):
2     def __init__(self, environ, start_response):
3         self.environ = environ
4         self.start_response = start_response
5  
6     def __iter__(self):
7         self.start_response('200 OK', [('Content-type', 'text/plain')])
8         yield "Hello world!n"

2.什么是werkzug

werkzeug

werkzeug是一个WSGI工具包,提供了Request和Response.

flask中的werkzeug

Flask中的程序实例app就是一个可调用对象,我们创建app实例时所调用的Flask类实现了__call方法,__call方法调用了wsgi_app()方法,该方法完成了请求和响应的处理,WSGI服务器通过调用该方法传入请求数据,获取返回数据

 1 def wsgi_app(self, environ, start_response):
 2     ctx = self.request_context(environ)
 3     error = None
 4     try:
 5         try:
 6             ctx.push()
 7             response = self.full_dispatch_request()
 8         except Exception as e:
 9             error = e
10             response = self.handle_exception(e)
11         except:  # noqa: B001
12             error = sys.exc_info()[1]
13             raise
14         return response(environ, start_response)
15     finally:
16         if self.should_ignore_error(error):
17             error = None
18         ctx.auto_pop(error)
19 
20 def __call__(self, environ, start_response):
21     return self.wsgi_app(environ, start_response)

 

本质

 1 from werkzeug.serving import run_simple
 2 from werkzeug.wrappers import BaseResponse
 3 
 4 def func(environ,start_response):
 5     print('请求来了')
 6     response = BaseResponse('你好')
 7     return response(environ,start_response)
 8 
 9 if __name__ == '__main__':
10     run_simple('127.0.0.1',5000,func)

 

3.flask的快速使用

from flask import Flask, render_template, jsonify, request, redirect, url_for, session

# template_folder模板目录 static_folder 静态目录 static_url_path 改变url的path
app = Flask(__name__, template_folder='templates', static_folder='static', static_url_path='/static')

# app密钥
app.secret_key = 's56h5h45h54s5sfs545agd6'

# 登录认证
def auth(func):
    @functools.wraps(func)
    def inner(*args, **kwargs):
        username = session.get('xxx')
        if not username:
            # redirect 重定向跳转 url_for 反向生成 等价于redirect('/login')
            return redirect(url_for('login'))
        return func(*args, **kwargs)
    return inner

# 请求之前中间件
@app.before_request
def f_before():
    pass

# 请求之后中间件
@app.after_request
def f_after(response):
    return response

# 在对应用程序实例的第一个请求之前注册要运行的函数, 只会执行一次
@app.before_first_request
def bfr():
    pass

# 主页 endpoint起别名
@app.route('/', methods=['GET'], endpoint='index')
@auth
def index():
    DATA_DICT = {}
    return render_template('index.html', data_dict=DATA_DICT)

# 登录 endpoint默认等于'/login'
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        # return 'hello'  # 返回HttpResponse响应
        # return jsonify({'code':1000,'data':[1,2,3]}) # 返回json数据
        return render_template('login.html')
    user = request.form.get('user', '0')
    if user == '1':
        session['xxx'] = 'yyy'
        return redirect('/index')
    return render_template('login.html', error='error')

# 路径传参
@app.route('/delete/<nid>', methods=['GET'])
@auth
def delete(nid):
    print(nid)
    return redirect(url_for('idx'))

# 启动flask
if __name__ == '__main__':
    app.run()

 

4.蓝图及其他

 1 from flask import Blueprint, render_template, request, redirect, session, url_for
 2 
 3 loginroute = Blueprint('loginroute', __name__)
 4 
 5 @loginroute.route('/login', methods=['GET', 'POST'], endpoint='login')
 6 def login():
 7     return render_template('login.html', error=error)
 8 
 9 # 主app中注册蓝图
10 def create_app():
11     app = Flask(__name__, template_folder='templates', static_folder='static', static_url_path='/static')
12     app.secret_key = 'df2hfdghjdf5gj'
13     app.register_blueprint(login.loginroute, url_prefix='/blog')
14     return app
15 class UserView(views.MethodView):
16     methods = ['GET', 'POST']
17     decorators = [test, ]
18 
19     def get(self):
20         return 'get'
21 
22     def post(self):
23         return 'POST'
24 app.add_url_rule('/user',view_func=UserView.as_view('user'))
25 # 如果不用方法视图实现需要在普通视图内部调用request.method判断是否为GET,POST进行判断

 

5.threading.local

 1 # 自定义threading_local()
 2 # storage = {
 3 #   1001:{'x1':1},
 4 #   1002:{'x1':2},
 5 #   1003:{'x1':3},
 6 #   1004:{'x1':4},
 7 # }
 8 class Local(object):
 9     def __init__(self):
10         # storage = {}
11         object.__setattr__(self, 'storage', {})
12 
13     def __setattr__(self, key, value):
14         ident = threading.get_ident()
15         if ident in self.storage:
16             self.storage[ident][key] = value
17         else:
18             self.storage[ident] = {key: value}
19 
20     def __getattr__(self, item):
21         ident = threading.get_ident()
22         if ident not in self.storage:
23             return
24         return self.storage[ident].get(item)
25 # 自定义高级threading_local()
26 # storage = {
27 #   1001:{'x1':[1,2]},
28 #   1002:{'x1':[]},
29 #   1003:{'x1':[3,]},
30 #   1004:{'x1':[4,5,6]},
31 # }
32 class Local(object):
33     def __init__(self):
34         # storage = {}
35         object.__setattr__(self, 'storage', {})
36 
37     def __setattr__(self, key, value):
38         ident = threading.get_ident()
39         if ident in self.storage:
40             self.storage[ident][key].append(value)
41         else:
42             self.storage[ident] = {key: [value,]}
43 
44     def __getattr__(self, item):
45         ident = threading.get_ident()
46         if ident not in self.storage:
47             return
48         return self.storage[ident][item][-1]

 

6.LocalStack和Local对象实现栈

 1 """
 2 __storage__={
 3     1111:{"stack":[xx,yy]}
 4 }
 5 """
 6 
 7 
 8 class LocalStack(object):
 9     def __iter__(self):
10         self._local = Local()
11 
12     def push(self, obj):
13         rv = getattr(self._local, 'stack', None)
14         if rv is None:
15             self._local.stack = rv = []
16         rv.append(obj)
17         return rv
18 
19     def pop(self):
20         stack = getattr(self._local, 'stack', None)
21         if stack is None:
22             return None
23         elif len(stack) == 1:
24             return stack[-1]
25         else:
26             return stack.pop()
27 
28     def top(self):
29         try:
30             return self._local.stack[-1]
31         except (AttributeError,IndexError):
32             return None

 

7.Flask全过程

  1 app = Flask(__name__,static_url_path='/xx')
  2 
  3 # 在源码种生成如下数据
  4 url_rule_class = Rule
  5 url_map_class = Map
  6 session interface = SecureCookieSessionInterface()
  7 # Flask中的__init__
  8 self.static_url_path = static_url_path
  9 self.config = Config
 10 self.view_functions = {
 11     "index":index
 12 }
 13 self.before_request_funcs = {}
 14 self.after_request_funcs = {}
 15 self.before_first_request = []
 16 self.url_map = self.url_map_class()
 17 self.add_url_rule("static")
 18 # 从字典中读取配置信息
 19 app.config.from_object("xx.xx")
 20 @app.before_request
 21 def f_before():
 22     pass
 23 # 将f_before添加到self.before_request_funcs
 24 self.before_request_funcs['None'].append(f_before)
 25 @app.after_request
 26 def f_after(response):
 27     return response
 28 # 将f_after添加到self.after_request_funcs
 29 self.after_request_funcs['None'].append(f_after)
 30 # self.after_request_funcs中的中间件逆序执行
 31 @app.before_first_request
 32 def bfr():
 33     pass
 34 # bfr.before_first_request_funcs
 35 self.before_first_request_funcs['None'].append(bfr)
 36 @app.route('/', methods=['GET'], endpoint='index')
 37 @auth
 38 def index():
 39     DATA_DICT = {}
 40     return render_template('index.html', data_dict=DATA_DICT)
 41 # 
 42 self.add_url_rule
 43 # 将url和对应的视图函数名绑定到rule,再将rule和endpoint放到Map,通过as.view方法实现view_func函数的传入
 44 # Rule
 45 endpoint和url
 46 # Map
 47 __init__
 48     self.rules = [rule,rule]
 49 # 启动flask
 50 if __name__ == '__main__':
 51     app.run()
 52 # 请求到来之后,执行__call__方法
 53 # run_simple(*,*,self,*)
 54 # 执行第三个函数(self)
 55 def wsgi_app(self, environ, start_response):
 56     """
 57     创建ctx,包含request=Request(environ) session=None
 58     详见8.1
 59     """
 60     ctx = self.request_context(environ)
 61     error = None
 62     try:
 63         try:
 64             """
 65             app_ctx = AppContext(app,g)
 66             将app_ctx放入local中
 67             将ctx放入local
 68             session赋值
 69             路由匹配
 70             详见8.1
 71             """
 72             ctx.push()
 73             """
 74             详见8.4
 75             """
 76             response = self.full_dispatch_request()
 77         except Exception as e:
 78             error = e
 79             response = self.handle_exception(e)
 80         except:  # noqa: B001
 81             error = sys.exc_info()[1]
 82             raise
 83         return response(environ, start_response)
 84     finally:
 85         if self.should_ignore_error(error):
 86             error = None
 87         ctx.auto_pop(error)
 88 
 89 def __call__(self, environ, start_response):
 90     return self.wsgi_app(environ, start_response)
 91 
 92 def full_dispatch_request(self) -> Response:
 93     # 触发所有first_request函数
 94     self.try_trigger_before_first_request_functions()
 95     try:
 96         # 信号 暂留
 97         request_started.send(self)
 98         # 执行所有before_request
 99         rv = self.preprocess_request()
100         if rv is None:
101             # 执行视图函数
102             rv = self.dispatch_request()
103         except Exception as e:
104             rv = self.handle_user_exception(e)
105             return self.finalize_request(rv)
106 
107 def try_trigger_before_first_request_functions(self) -> None:
108     if self._got_first_request:
109         return
110     with self._before_request_lock:
111         if self._got_first_request:
112             return
113         for func in self.before_first_request_funcs:
114             self.ensure_sync(func)()
115             self._got_first_request = True
116 def preprocess_request(self) -> t.Optional[ResponseReturnValue]:
117     names = (None, *reversed(request.blueprints))
118     for name in names:
119         if name in self.url_value_preprocessors:
120             for url_func in self.url_value_preprocessors[name]:
121                 url_func(request.endpoint, request.view_args)
122      for name in names:
123         if name in self.before_request_funcs:
124             for before_func in self.before_request_funcs[name]:
125                 rv = self.ensure_sync(before_func)()
126                 if rv is not None:
127                     return rv
128      return None
129 class RequestContext:
130     def __init__(
131         self,
132         app: "Flask",
133         environ: dict,
134         request: t.Optional["Request"] = None,
135         session: t.Optional["SessionMixin"] = None,
136     ) -> None:
137         self.app = app
138         if request is None:
139             request = app.request_class(environ)
140         self.request = request
141         self.url_adapter = None
142         try:
143             self.url_adapter = app.create_url_adapter(self.request)
144         except HTTPException as e:
145             self.request.routing_exception = e
146         self.flashes = None
147         self.session = session
148     def push(self) -> None:
149         """
150         调用了如下函数,返回了AppContext
151         详见8.2
152         def app_context(self) -> AppContext:
153             return AppContext(self)
154         """
155         app_ctx = self.app.app_context()
156         app_ctx.push()
157         """
158         _request_ctx_stack = LocalStack()
159         _app_ctx_stack = LocalStack()
160         详见8.3
161         """
162         _request_ctx_stack.push(self)
163     
164         if self.session is None:
165             session_interface = self.app.session_interface
166             self.session = session_interface.open_session(self.app, self.request)
167     
168             if self.session is None:
169                 self.session = session_interface.make_null_session(self.app)
170     
171         if self.url_adapter is not None:
172             self.match_request()
173 class AppContext:
174     def __init__(self, app: "Flask") -> None:
175         self.app = app
176         self.url_adapter = app.create_url_adapter(None)
177         self.g = app.app_ctx_globals_class()
178 
179         # Like request context, app contexts can be pushed multiple times
180         # but there a basic "refcount" is enough to track them.
181         self._refcnt = 0
182     def push(self) -> None:
183         """Binds the app context to the current context."""
184         self._refcnt += 1
185         """
186         _request_ctx_stack = LocalStack()
187         _app_ctx_stack = LocalStack()
188         详见8.3
189         """
190         _app_ctx_stack.push(self)
191         appcontext_pushed.send(self.app)
192 class LocalStack(object):
193     def __iter__(self):
194         self._local = Local()
195     def push(self, obj):
196         rv = getattr(self._local, 'stack', None)
197         if rv is None:
198             self._local.stack = rv = []
199         rv.append(obj)
200         return rv
201     def pop(self):
202         stack = getattr(self._local, 'stack', None)
203         if stack is None:
204             return None
205         elif len(stack) == 1:
206             return stack[-1]
207         else:
208             return stack.pop()
209     def top(self):
210         try:
211             return self._local.stack[-1]
212         except (AttributeError,IndexError):
213             return None
214 """
215 _request_ctx_stack = LocalStack()
216 request context,程序上下文,存储的是请求级别的信息,比如当前访问的url
217 _app_ctx_stack = LocalStack()
218 app context,应用上下文,存储的是应用级别的信息,比如数据库连接信息。
219 """
220 _request_ctx_stack = {111:{stack:[ctx,]}}
221 _app_ctx_stack = {111:{stack:[app_ctx,]}}

 

8.用户请求全过程

 1 """
 2 创建ctx=RequestContext对象,其内部封装了Request和session
 3 创建app_ctx=AppContext对象,其内部封装了App和g
 4 ctx.push触发ctx和app_ctx分别通过自己的LocalStack对象将其放入Local中,以线程ID为key,以{"stack":[]}为value的字典
 5 {
 6     1111:{"stack":[ctx,]}
 7 }
 8 {
 9     1111:{"stack":[app_ctx,]}
10 }
11 
12 注意:以后要获取request/session/app/g时,去local中获取
13 执行所有before_request
14 执行视图函数
15 执行所有after_request(session放到cookie,保存在浏览器中)
16 销毁ctx和app_ctx
17 """

 

原创文章,作者:,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/269097.html

(0)
上一篇 2022年6月20日 15:07
下一篇 2022年6月20日 15:08

相关推荐

发表回复

登录后才能评论