flask 信号

Posted jackchengcc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了flask 信号相关的知识,希望对你有一定的参考价值。

  Flask中的信号基于blinker模块,可以用于在flask请求的整个生命周期中添加一些特定的行为(pip3 install blinker)

  blinker中的信号有: 

    

技术分享图片
 1 template_rendered = _signals.signal(template-rendered)#模板渲染之后执行
 2 before_render_template = _signals.signal(before-render-template)#模板渲染之前执行
 3 request_started = _signals.signal(request-started)#请求开始前执行
 4 request_finished = _signals.signal(request-finished)#请求结束后执行
 5 request_tearing_down = _signals.signal(request-tearing-down)#请求执行完毕后自动执行(无论成功与否)
 6 got_request_exception = _signals.signal(got-request-exception)#请求执行出现异常时执行
 7 appcontext_tearing_down = _signals.signal(appcontext-tearing-down)#请求上下文执行完毕后执行(无论成功与否)
 8 appcontext_pushed = _signals.signal(appcontext-pushed)#请求上下文push时执行
 9 appcontext_popped = _signals.signal(appcontext-popped)#请求上下文pop时执行
10 message_flashed = _signals.signal(message-flashed)#调用flask(闪现)在其中添加数据时自动触发
Flask信号

 

  信号的执行流程:

    1.定义信号函数

    2.往信号中注册函数(connect方法)

    3.触发信号(send方法)

 

  源码:

  

技术分享图片
 1 class Flask(_PackageBoundObject):
 2 
 3     def full_dispatch_request(self):
 4        
 5         self.try_trigger_before_first_request_functions()
 6         try:
 7             # ############### 触发request_started 信号 ###############
 8             request_started.send(self)       
 9             rv = self.preprocess_request()
10             if rv is None:
11                 rv = self.dispatch_request()
12         except Exception as e:
13             rv = self.handle_user_exception(e)
14         response = self.make_response(rv)
15         response = self.process_response(response)
16 
17         # ############### request_finished 信号 ###############
18         request_finished.send(self, response=response)
19         return response
20 
21     def wsgi_app(self, environ, start_response):
22         
23         ctx = self.request_context(environ)
24         ctx.push()
25         error = None
26         try:
27             try:
28                 response = self.full_dispatch_request()
29             except Exception as e:
30                 error = e
31                 response = self.make_response(self.handle_exception(e))
32             return response(environ, start_response)
33         finally:
34             if self.should_ignore_error(error):
35                 error = None
36             ctx.auto_pop(error)
request_started
技术分享图片
1 同上
request_finished
技术分享图片
 1 def render_template(template_name_or_list, **context):
 2     """Renders a template from the template folder with the given
 3     context.
 4 
 5     :param template_name_or_list: the name of the template to be
 6                                   rendered, or an iterable with template names
 7                                   the first one existing will be rendered
 8     :param context: the variables that should be available in the
 9                     context of the template.
10     """
11     ctx = _app_ctx_stack.top
12     ctx.app.update_template_context(context)
13     return _render(ctx.app.jinja_env.get_or_select_template(template_name_or_list),
14                    context, ctx.app)
15 
16 def _render(template, context, app):
17     """Renders the template and fires the signal"""
18 
19     # ############### before_render_template 信号 ###############
20     before_render_template.send(app, template=template, context=context)
21     rv = template.render(context)
22     
23     # ############### template_rendered 信号 ###############
24     template_rendered.send(app, template=template, context=context)
25     return rv
before_render_template
技术分享图片
1 同上
template_rendered
技术分享图片
 1 class Flask(_PackageBoundObject):
 2 
 3     def handle_exception(self, e):
 4        
 5         exc_type, exc_value, tb = sys.exc_info()
 6 
 7         # ############### got_request_exception 信号 ###############
 8         got_request_exception.send(self, exception=e)
 9         handler = self._find_error_handler(InternalServerError())
10 
11         if self.propagate_exceptions:
12             # if we want to repropagate the exception, we can attempt to
13             # raise it with the whole traceback in case we can do that
14             # (the function was actually called from the except part)
15             # otherwise, we just raise the error again
16             if exc_value is e:
17                 reraise(exc_type, exc_value, tb)
18             else:
19                 raise e
20 
21         self.log_exception((exc_type, exc_value, tb))
22         if handler is None:
23             return InternalServerError()
24         return handler(e)
25 
26     def wsgi_app(self, environ, start_response):
27         
28         ctx = self.request_context(environ)
29         ctx.push()
30         error = None
31         try:
32             try:
33                 response = self.full_dispatch_request()
34             except Exception as e:
35                 error = e
36                 # 这里这里这里这里这里这里这里这里这里这里这里这里 #
37                 response = self.make_response(self.handle_exception(e))
38             return response(environ, start_response)
39         finally:
40             if self.should_ignore_error(error):
41                 error = None
42             ctx.auto_pop(error)
got_request_exception
技术分享图片
  1 class AppContext(object):
  2     def push(self):
  3         """Binds the app context to the current context."""
  4         self._refcnt += 1
  5         if hasattr(sys, exc_clear):
  6             sys.exc_clear()
  7         _app_ctx_stack.push(self)
  8         # ############## 触发 appcontext_pushed 信号 ##############
  9         appcontext_pushed.send(self.app)
 10 
 11     def pop(self, exc=_sentinel):
 12         """Pops the app context."""
 13         try:
 14             self._refcnt -= 1
 15             if self._refcnt <= 0:
 16                 if exc is _sentinel:
 17                     exc = sys.exc_info()[1]
 18                 # ############## 触发 appcontext_tearing_down 信号 ##############
 19                 self.app.do_teardown_appcontext(exc)
 20         finally:
 21             rv = _app_ctx_stack.pop()
 22         assert rv is self, Popped wrong app context.  (%r instead of %r)  23             % (rv, self)
 24 
 25         # ############## 触发 appcontext_popped 信号 ##############
 26         appcontext_popped.send(self.app)
 27 
 28 class RequestContext(object):
 29     def push(self):
 30         top = _request_ctx_stack.top
 31         if top is not None and top.preserved:
 32             top.pop(top._preserved_exc)
 33 
 34         app_ctx = _app_ctx_stack.top
 35         if app_ctx is None or app_ctx.app != self.app:
 36             
 37             # ####################################################
 38             app_ctx = self.app.app_context()
 39             app_ctx.push()
 40             self._implicit_app_ctx_stack.append(app_ctx)
 41         else:
 42             self._implicit_app_ctx_stack.append(None)
 43 
 44         if hasattr(sys, exc_clear):
 45             sys.exc_clear()
 46 
 47         _request_ctx_stack.push(self)
 48 
 49         # Open the session at the moment that the request context is
 50         # available. This allows a custom open_session method to use the
 51         # request context (e.g. code that access database information
 52         # stored on `g` instead of the appcontext).
 53         self.session = self.app.open_session(self.request)
 54         if self.session is None:
 55             self.session = self.app.make_null_session()
 56 
 57 class Flask(_PackageBoundObject):
 58 
 59 
 60     def wsgi_app(self, environ, start_response):
 61         
 62         ctx = self.request_context(environ)
 63         ctx.push()
 64         error = None
 65         try:
 66             try:
 67                 response = self.full_dispatch_request()
 68             except Exception as e:
 69                 error = e
 70                 response = self.make_response(self.handle_exception(e))
 71             return response(environ, start_response)
 72         finally:
 73             if self.should_ignore_error(error):
 74                 error = None
 75             ctx.auto_pop(error)
 76 
 77 
 78     def pop(self, exc=_sentinel):
 79         app_ctx = self._implicit_app_ctx_stack.pop()
 80 
 81         try:
 82             clear_request = False
 83             if not self._implicit_app_ctx_stack:
 84                 self.preserved = False
 85                 self._preserved_exc = None
 86                 if exc is _sentinel:
 87                     exc = sys.exc_info()[1]
 88 
 89                 # ################## 触发 request_tearing_down 信号 ##################
 90                 self.app.do_teardown_request(exc)
 91 
 92                 # If this interpreter supports clearing the exception information
 93                 # we do that now.  This will only go into effect on Python 2.x,
 94                 # on 3.x it disappears automatically at the end of the exception
 95                 # stack.
 96                 if hasattr(sys, exc_clear):
 97                     sys.exc_clear()
 98 
 99                 request_close = getattr(self.request, close, None)
100                 if request_close is not None:
101                     request_close()
102                 clear_request = True
103         finally:
104             rv = _request_ctx_stack.pop()
105 
106             # get rid of circular dependencies at the end of the request
107             # so that we don‘t require the GC to be active.
108             if clear_request:
109                 rv.request.environ[werkzeug.request] = None
110 
111             # Get rid of the app as well if necessary.
112             if app_ctx is not None:
113                 # ####################################################
114                 app_ctx.pop(exc)
115 
116             assert rv is self, Popped wrong request context.   117                 (%r instead of %r) % (rv, self)
118 
119     def auto_pop(self, exc):
120         if self.request.environ.get(flask._preserve_context) or 121            (exc is not None and self.app.preserve_context_on_exception):
122             self.preserved = True
123             self._preserved_exc = exc
124         else:
125             self.pop(exc)
request_tearing_down
技术分享图片
1 同上
appcontext_tearing_down
技术分享图片
1 同上
appcontext_pushed
技术分享图片
1 同上
appcontext_popped
技术分享图片
 1 def flash(message, category=message):
 2     """Flashes a message to the next request.  In order to remove the
 3     flashed message from the session and to display it to the user,
 4     the template has to call :func:`get_flashed_messages`.
 5 
 6     .. versionchanged:: 0.3
 7        `category` parameter added.
 8 
 9     :param message: the message to be flashed.
10     :param category: the category for the message.  The following values
11                      are recommended: ``‘message‘`` for any kind of message,
12                      ``‘error‘`` for errors, ``‘info‘`` for information
13                      messages and ``‘warning‘`` for warnings.  However any
14                      kind of string can be used as category.
15     """
16     # Original implementation:
17     #
18     #     session.setdefault(‘_flashes‘, []).append((category, message))
19     #
20     # This assumed that changes made to mutable structures in the session are
21     # are always in sync with the session object, which is not true for session
22     # implementations that use external storage for keeping their keys/values.
23     flashes = session.get(_flashes, [])
24     flashes.append((category, message))
25     session[_flashes] = flashes
26 
27     # ############### 触发 message_flashed 信号 ###############
28     message_flashed.send(current_app._get_current_object(),
29                          message=message, category=category)
message_flashed

自定义信号:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from flask import Flask, current_app, flash, render_template
from flask.signals import _signals
 
app = Flask(import_name=__name__)
 
# 自定义信号
xxxxx = _signals.signal(xxxxx)
  
def func(sender, *args, **kwargs):
    print(sender)
 
# 自定义信号中注册函数
xxxxx.connect(func)
 
@app.route("/x")
def index():
    # 触发信号
    xxxxx.send(123123, k1=v1)
    return Index
 
if __name__ == __main__:
    app.run()

 

流程图:

  技术分享图片

以上是关于flask 信号的主要内容,如果未能解决你的问题,请参考以下文章

python Flask - 数据库片段

Flask信号管理

Flask 信号机制 (signals)

Flask--信号

flask-信号

flask_day05:信号 Django信号 flask-script sqlalchemy 创建操作数据表