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)
  37.  
  38. request_started

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. def wsgi_app(self, environ, start_response):
  60.  
  61. ctx = self.request_context(environ)
  62. ctx.push()
  63. error = None
  64. try:
  65. try:
  66. response = self.full_dispatch_request()
  67. except Exception as e:
  68. error = e
  69. response = self.make_response(self.handle_exception(e))
  70. return response(environ, start_response)
  71. finally:
  72. if self.should_ignore_error(error):
  73. error = None
  74. ctx.auto_pop(error)
  75.  
  76. def pop(self, exc=_sentinel):
  77. app_ctx = self._implicit_app_ctx_stack.pop()
  78.  
  79. try:
  80. clear_request = False
  81. if not self._implicit_app_ctx_stack:
  82. self.preserved = False
  83. self._preserved_exc = None
  84. if exc is _sentinel:
  85. exc = sys.exc_info()[1]
  86.  
  87. # ################## 触发 request_tearing_down 信号 ##################
  88. self.app.do_teardown_request(exc)
  89.  
  90. # If this interpreter supports clearing the exception information
  91. # we do that now. This will only go into effect on Python 2.x,
  92. # on 3.x it disappears automatically at the end of the exception
  93. # stack.
  94. if hasattr(sys, 'exc_clear'):
  95. sys.exc_clear()
  96.  
  97. request_close = getattr(self.request, 'close', None)
  98. if request_close is not None:
  99. request_close()
  100. clear_request = True
  101. finally:
  102. rv = _request_ctx_stack.pop()
  103.  
  104. # get rid of circular dependencies at the end of the request
  105. # so that we don't require the GC to be active.
  106. if clear_request:
  107. rv.request.environ['werkzeug.request'] = None
  108.  
  109. # Get rid of the app as well if necessary.
  110. if app_ctx is not None:
  111. # ####################################################
  112. app_ctx.pop(exc)
  113.  
  114. assert rv is self, 'Popped wrong request context. ' \
  115. '(%r instead of %r)' % (rv, self)
  116.  
  117. def auto_pop(self, exc):
  118. if self.request.environ.get('flask._preserve_context') or \
  119. (exc is not None and self.app.preserve_context_on_exception):
  120. self.preserved = True
  121. self._preserved_exc = exc
  122. else:
  123. 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)
  30.  
  31. message_flashed

message_flashed

执行的流程

  1. a. before_first_request
  2. b. 触发 request_started 信号
  3. c. before_request
  4. d. 模板渲染
  5. 渲染前的信号 before_render_template.send(app, template=template, context=context)
  6. rv = template.render(context) # 模板渲染
  7. 渲染后的信号 template_rendered.send(app, template=template, context=context)
  8. e. after_request
  9. f. session.save_session()
  10. g. 触发 request_finished信号
  11.  
  12. 如果上述过程出错:
  13. 触发错误处理信号 got_request_exception.send(self, exception=e)
  14.  
  15. h. 触发信号 request_tearing_down
  16.  
  17. 由信号引发的源码流程:找扩展点

在请求到来的时候执行信号

  1. from flask import Flask,signals,render_template
  2.  
  3. app = Flask(__name__)
  4.  
  5. # 往信号中注册函数
  6. def func(*args,**kwargs):
  7. print('触发型号',args,kwargs)
  8.  
  9. signals.request_started.connect(func)
  10.  
  11. # 触发信号: signals.request_started.send()
  12.  
  13. @app.before_first_request
  14. def before_first1(*args,**kwargs):
  15. pass
  16. @app.before_first_request
  17. def before_first2(*args,**kwargs):
  18. pass
  19.  
  20. @app.before_request
  21. def before_first3(*args,**kwargs):
  22. pass
  23.  
  24. @app.route('/',methods=['GET',"POST"])
  25. def index():
  26. print('视图')
  27. return render_template('index.html')
  28.  
  29. if __name__ == '__main__':
  30. app.wsgi_app
  31. app.run()

2. 自定义信号

  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. from flask import Flask, current_app, flash, render_template
  4. from flask.signals import _signals
  5.  
  6. app = Flask(import_name=__name__)
  7.  
  8. # 自定义信号
  9. xxxxx = _signals.signal('xxxxx')
  10.  
  11. def func(sender, *args, **kwargs):
  12. print(sender)
  13.  
  14. # 自定义信号中注册函数
  15. xxxxx.connect(func)
  16.  
  17. @app.route("/x")
  18. def index():
  19. # 触发信号
  20. xxxxx.send('123123', k1='v1')
  21. return 'Index'
  22.  
  23. if __name__ == '__main__':
  24. app.run()

  

Flask —— 信号(5)的更多相关文章

  1. flask信号使用

    flask信号: 安装: flask中的信号使用的是一个第三方插件,叫做blinker.通过pip list看一下,如果没有安装,通过以下命令即可安装blinker: pip install blin ...

  2. 信号(Django信号、Flask信号、Scrapy信号)

    简介 Django.Flask.scrapy都包含了一个“信号分配器”,使得当一些动作在框架的其他地方发生的时候,解耦的应用可以得到提醒. 通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒 ...

  3. 了解Flask 信号机制

    Flask框架中的信号基于blinker,其主要就是让开发者可是在flask请求过程中定制一些用户行为. pip3 install blinker 1. 内置信号 request_started = ...

  4. flask—信号(blinker)

    Flask框架中的信号基于blinker,主要是让开发者在flask请求过程中定制一些用户行为. 安装blinker pip3 install blinker 1.内置信号 request_start ...

  5. 22、Flask实战第22天:Flask信号

    Flask中的信号使用的是一个第三方插件blinker.通过pip list看一下是否安装,如果没有,则使用如下命令安装 pip install blinker 自定义信号 自定义信号分为3步: ①定 ...

  6. flask信号

    骚师博客:信号 信号你就可以这么理解,请求比喻成赛车,请求走的流程就是赛车道,而信号坐落在赛车道上的加油站和维修站,信号注册的函数好比维修站的人,每经过维修站并且维修站里有人就进行维修 信号这里理解: ...

  7. Flask信号流程

    首先先我们来看看Flask里面的信号是什么样的,我们可以找到一个叫signals.py的文件 这里面是所有定义了的后面请求流程中会用到的信号 二.哪些地方用到了信号 1.请求app上下文时执行的,在执 ...

  8. 七十四:flask信号之flask的内置信号

    flask所有的内置信号 1.template_rendered:模板渲染完成后的信号2.before_render_template:模板渲染之前的信号3.request_started:模板开始渲 ...

  9. 七十三:flask信号之信号机制和使用场景

    若安装flask是未默认安装blinker,则pip install blinker 使用信号分为3步,第一是定义一个信号,第二是监听一个信号,第三是发送一个信号 1.定义信号:定义信号需要使用到bl ...

随机推荐

  1. .Net语言 APP开发平台——Smobiler学习日志:SmoOne新增考勤功能

    大家好!SmoOne这次新增了考勤功能,大家打开SmoOne应用便可体验,无需重新下载更新.如果没有下载SmoOne客户端,可以在apps.smobiler.com进行下载安装. 另外,SmoOne开 ...

  2. php 关于经纬度距离计算方法

    1.PHP实现通过经纬度计算距离 单位为公里 function getdistance($lng1,$lat1,$lng2,$lat2)//根据经纬度计算距离 { //将角度转为狐度  $radLat ...

  3. MySQL高级特性——绑定变量

    从MySQL 4.1 版本开始,就支持服务器端的绑定变量,这大大提高了客户端和服务器端数据传输的效率 介绍 当创建一个绑定变量 SQL 时,客户端会向服务器发送一个SQL语句的原型.服务器端收到这个S ...

  4. finereport报表--动态格间运算 一

    一.运算符:   ! 绝对值 A2[A2:!1] ;   A2 标示从列A纵向第2单元格开始,!1 表示第1个位置的单元格; [A2:!1] 代表索引,表示从A列纵向开始往下,第1个单元格的位置的索引 ...

  5. Web前端:博客美化:一、模板美化

    1.选用模板simplememory 2.写css放在 这些会覆盖掉原来的css样式 我是在网上找的css代码二次加工的 : ) /*1.针对simplememory的修改*/ #google_ad_ ...

  6. Dynamics 365的系统作业实体记录增长太快怎么回事?

    摘要: 本人微信公众号:微软动态CRM专家罗勇 ,回复294或者20190111可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me ...

  7. C#获得指定目录床架时间、更新时间和最后访问时间等信息的代码

    将做工程过程常用的内容片段备份一次,下面的内容内容是关于C#获得指定目录床架时间.更新时间和最后访问时间等信息的内容,希望能对小伙伴们也有用. using System;using System.IO ...

  8. Java新知识系列 八

    什么是死锁,死锁的原因和必要条件:       []什么是死锁,死锁的原因和必要条件: 死锁:死锁的原因在于进程在等待其它进程占有的某些资源,而自身的资源又被其它进程等待着,造成了死循环. 出现死锁的 ...

  9. matlab练习程序(水波特效)

    还记得原来写过一个对图像进行波纹扭曲操作的博文. 这次实现的是水波特效,其实就是通过正余弦函数表示波纹中心位置慢慢向外扩散,通过叠加衰减因子使振幅不断减小,进而产生水波的效果. 效果如下: 原图: 波 ...

  10. 扩展1000!(n!)的尾数零的个数

    #include <stdio.h> #include <malloc.h> //计算1000!尾数零的个数 //扩展n!的尾数零的个数 //2^a * 5^b //obvio ...