flask-信号

Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为。

1 pip3 install blinker

1、内置信号

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

源码示例:

 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_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

2. 自定义信号

#!/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()

 

posted @ 2018-01-11 15:47  Justin067  阅读(126)  评论(0编辑  收藏  举报
TOP