Flask框架(三)—— 请求扩展、中间件、蓝图、session源码分析

请求扩展、中间件、蓝图、session源码分析

一、请求扩展

1、before_request

类比django中间件中的process_request,在请求收到之前绑定一个函数做一些事情

#基于它做用户登录认证
@app.before_request
def process_request(*args,**kwargs):
if request.path == '/login':
return None
user = session.get('user_info')
if user:
return None
return redirect('/login')

2、after_request

类比django中间件中的process_response,每一个请求之后绑定一个函数,如果请求没有异常

@app.after_request
def process_response1(response):
print('process_response1 走了')
return response

3、before_first_request

第一次请求时会走,跟浏览器无关

@app.before_first_request
def first():
pass

4、teardown_request

每次请求走,都会走它,包括视图函数出了异常

@app.teardown_request
def ter(e):
pass

5、errorhandler

路径不存在时404,服务器内部错误500

@app.errorhandler(404)
def error_404(arg):
return "404错误了"

6、template_global

标签

@app.template_global()
def sb(a1, a2):
return a1 + a2
# {{sb(1,2)}}

7、template_filter

过滤器,注意模板层中参数的位置,一个写前面,其余写后面

@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
# {{ 1|db(2,3)}}

二、中间件

from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
return 'Hello World!'
# 模拟中间件
class Md(object):
def __init__(self,old_wsgi_app):
self.old_wsgi_app = old_wsgi_app def __call__(self, environ, start_response):
print('开始之前')
ret = self.old_wsgi_app(environ, start_response)
print('结束之后')
return ret if __name__ == '__main__':
# 把原来的wsgi_app替换为自定义的
app.wsgi_app = Md(app.wsgi_app)
app.run()

三、蓝图(blueprint)

对程序进行目录结构划分

1、不使用蓝图,自己分文件

目录结构:

-templates
-views
-__init__.py
-user.py
-order.py
-app.py

app.py

from views import app
if __name__ == '__main__':
app.run()

init.py

from flask import Flask,request
app = Flask(__name__)
# 不导入这个不行,容易产生交叉导入问题
from . import order
from . import user

user.py

from . import app
@app.route('/user')
def user():
return 'user'

order.py

from . import app
@app.route('/order')
def order():
return 'order'

2、使用蓝图之中小型系统

蓝图模板下载:
链接:https://pan.baidu.com/s/1nosJD2PCtk2jQa4d3wLL4g
提取码:yhkq
  • xxx = Blueprint('account', __name__,url_prefix='/xxx',)url_prifix 表示添加在原路由中加中间路由,此时须访问127.0.0.1/xxx/index才能访问

目录结构:

-flask_pro
-flask_test
-__init__.py
-static
-templates
-views
-order.py
-user.py
-manage.py

__init__.py

from flask import  Flask
app=Flask(__name__) # 3.注册蓝图到app中
from flask_test.views import user
from flask_test.views import order
app.register_blueprint(user.us)
app.register_blueprint(order.ord)

manage.py

from flask_test import  app
if __name__ == '__main__':
app.run(port=8008)

user.py

from flask import Blueprint
# 1.创建蓝图
us=Blueprint('user',__name__,)
# 2.使用蓝图
@us.route('/login')
def login():
return 'login'

order.py

from flask import Blueprint
ord=Blueprint('order',__name__) @ord.route('/test')
def test():
return 'order test'

3、使用蓝图之大型系统

蓝图模板下载:
链接:https://pan.baidu.com/s/1Ce2npcn2PTRsvrfHjG9b2A
提取码:rnk9

4、总结

(1)xxx = Blueprint('account', name,url_prefix='/xxx') :蓝图URL前缀,表示url的前缀,在该蓝图下所有url都加前缀

(2)xxx = Blueprint('account', name,url_prefix='/xxx',template_folder='tpls'):给当前蓝图单独使用templates,向上查找,当前找不到,会找总templates

(3)蓝图的befort_request,对当前蓝图有效

(4)大型项目,可以模拟出类似于django中app的概念

四、threading.local

多个线程修改同一个数据,复制多份变量给每个线程用,为每个线程开辟一块空间进行数据存储

1、不用threading.local

# 不用local
from threading import Thread
import time
lqz = -1
def task(arg):
global lqz
lqz = arg
# time.sleep(2)
print(lqz) for i in range(10):
t = Thread(target=task,args=(i,))
t.start()

2、threading.local使用

from threading import Thread
from threading import local
import time
from threading import get_ident
# 特殊的对象
lqz = local()
def task(arg):
# 对象.val = 1/2/3/4/5
lqz.value = arg
time.sleep(2)
print(lqz.value)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()

3、通过字典自定义threading.local(函数)

from threading import get_ident,Thread
import time
storage = {}
def set(k,v):
ident = get_ident()
if ident in storage:
storage[ident][k] = v
else:
storage[ident] = {k:v}
def get(k):
ident = get_ident()
return storage[ident][k]
def task(arg):
set('val',arg)
v = get('val')
print(v) for i in range(10):
t = Thread(target=task,args=(i,))
t.start()

4、面向对象版

from threading import get_ident,Thread
import time
class Local(object):
storage = {}
def set(self, k, v):
ident = get_ident()
if ident in Local.storage:
Local.storage[ident][k] = v
else:
Local.storage[ident] = {k: v}
def get(self, k):
ident = get_ident()
return Local.storage[ident][k]
obj = Local()
def task(arg):
obj.set('val',arg)
v = obj.get('val')
print(v)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()

5、通过setattr和getattr实现

from threading import get_ident,Thread
import time
class Local(object):
storage = {}
def __setattr__(self, k, v):
ident = get_ident()
if ident in Local.storage:
Local.storage[ident][k] = v
else:
Local.storage[ident] = {k: v}
def __getattr__(self, k):
ident = get_ident()
return Local.storage[ident][k]
obj = Local()
def task(arg):
obj.val = arg
print(obj.val)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()

6、每个对象有自己的存储空间(字典)

from threading import get_ident,Thread
import time
class Local(object):
def __init__(self):
object.__setattr__(self,'storage',{})
def __setattr__(self, k, v):
ident = get_ident()
if ident in self.storage:
self.storage[ident][k] = v
else:
self.storage[ident] = {k: v}
def __getattr__(self, k):
ident = get_ident()
return self.storage[ident][k]
obj = Local()
def task(arg):
obj.val = arg
obj.xxx = arg
print(obj.val)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()

7、兼容线程和协程(终极版)——flask中使用版本

try:
from greenlet import getcurrent as get_ident
except Exception as e:
from threading import get_ident from threading import Thread
import time
class Local(object):
def __init__(self):
object.__setattr__(self,'storage',{})
def __setattr__(self, k, v):
ident = get_ident()
if ident in self.storage:
self.storage[ident][k] = v
else:
self.storage[ident] = {k: v}
def __getattr__(self, k):
ident = get_ident()
return self.storage[ident][k]
obj = Local()
def task(arg):
obj.val = arg
obj.xxx = arg
print(obj.val)
for i in range(10):
t = Thread(target=task,args=(i,))
t.start()

五、session源码分析

1.请求来了,生成一个空session放到ctx中:ctx = self.request_context(environ)
2.ctx.push():
if self.session is None:
session_interface = self.app.session_interface
# 正常情况下session中有值了
# 什么情况下没有:请求中没有cookie,session仍为空
# 从cookie中取出value,(有解密过程)转成session对象 self.session = session_interface.open_session(
self.app, self.request
) if self.session is None:
# 生成一个空session
self.session = session_interface.make_null_session(self.app)
3.请求走了:
self.full_dispatch_request()
1 执行before_request
2 执行视图函数
3 把session写入
if not self.session_interface.is_null_session(ctx.session):
self.session_interface.save_session(self, ctx.session, response)

六、session修改的坑

# 1.增加值
session['user']={'name':'aaa','age':18} # 2.修改session的坑
session['user']['name']='bbb'
# 这样无法修改session,这样触发的是session['user']字典的__setitem__方法,没有modified,在save_session时没有保存,所以session并没有改变 # 解决方法一
session['user']={'name':'bbb','age':18}
# 这样是在__setitem__方法中写了modified,并设置为True,在save_session时因为是True所以保存 # 解决方法二
session['user']['name']='bbb'
session.modified=True # 修改完后,手动指定modified为True,这样再save_session时就会保存
博客内容仅供参考,部分参考他人优秀博文,仅供学习使用

Flask框架(三)—— 请求扩展、中间件、蓝图、session源码分析的更多相关文章

  1. Flask框架(五) —— session源码分析

    Flask框架(五) —— session源码分析 目录 session源码分析 1.请求来了,执行__call__方法 2.__call__方法 3.调用__call__方法 3.1.ctx = s ...

  2. PHP扩展编写、PHP扩展调试、VLD源码分析、基于嵌入式Embed SAPI实现opcode查看

    catalogue . 编译PHP源码 . 扩展结构.优缺点 . 使用PHP原生扩展框架wizard ext_skel编写扩展 . 编译安装VLD . Debug调试VLD . VLD源码分析 . 嵌 ...

  3. 定时组件quartz系列<三>quartz调度机制调研及源码分析

    quartz2.2.1集群调度机制调研及源码分析引言quartz集群架构调度器实例化调度过程触发器的获取触发trigger:Job执行过程:总结:附: 引言 quratz是目前最为成熟,使用最广泛的j ...

  4. Django——Session源码分析

    首先我们导入django.contrib.sessions.middleware这个中间件,查看里面的Session源码 from django.contrib.sessions.middleware ...

  5. Netty之旅三:Netty服务端启动源码分析,一梭子带走!

    Netty服务端启动流程源码分析 前记 哈喽,自从上篇<Netty之旅二:口口相传的高性能Netty到底是什么?>后,迟迟两周才开启今天的Netty源码系列.源码分析的第一篇文章,下一篇我 ...

  6. 第三篇:Spark SQL Catalyst源码分析之Analyzer

    /** Spark SQL源码分析系列文章*/ 前面几篇文章讲解了Spark SQL的核心执行流程和Spark SQL的Catalyst框架的Sql Parser是怎样接受用户输入sql,经过解析生成 ...

  7. Bytom Dapp 开发笔记(三):Dapp Demo前端源码分析

    本章内容会针对比原官方提供的dapp-demo,分析里面的前端源码,分析清楚整个demo的流程,然后针对里面开发过程遇到的坑,添加一下个人的见解还有解决的方案. 储蓄分红合约简述 为了方便理解,这里简 ...

  8. Flask的闪现(message) 请求扩展 中间件 蓝图

    补充:一个编程思路 需求:做一些邮件短信微信的消息通知,比如账单告警之类的:比如数据库操作,数据库种类繁多:缓存的选择比如redis/memcache,诸如此类需要进行选择配置,如果我们单纯的用函数去 ...

  9. 服务网关zuul之二:过滤器--请求过滤执行过程(源码分析)

    Zuul的核心是一系列的过滤器,这些过滤器可以完成以下功能: 身份认证与安全:识别每个资源的验证要求,并拒绝那些与要求不符的请求. 审查与监控:在边缘位置追踪有意义的数据和统计结果,从而带来精确的生成 ...

随机推荐

  1. mac安装测试myCat

      参考博文https://www.cnblogs.com/chanshuyi/p/head_first_of_mycat.html 1.下载解压mycat的mac版(位置不限) 2.cd进bin文件 ...

  2. Flume 实时获取日志内容插入MySQL

    https://www.jianshu.com/p/22e6133649ca 采用链接的方法试了一下,好像不成功,问题出在 channel.take();   //获取出来的Event为空,不知道为啥

  3. Olympic Game

    每次奥运会期间,大家都非常关注奖牌榜排名的情况. 现在我们假设奖牌榜的排名规则,按优先级从高到低如下: 金牌 数量多的排在前面: 银牌 数量多的排在前面: 铜牌 数量多的排在前面: 若以上三个条件仍无 ...

  4. python-套接字编程之tcp

    服务端和客户端. 服务端脚本: # Auther:AlphaPanda # Description:server # Version:1 # Date:Mon Dec 2 09:02:01 EST 2 ...

  5. Android开源SlidingMenu的使用

    一.SlidingMenu简介 SlidingMenu是最常用的几个开源项目之一. GitHub上的开源项目Slidingmenu提供了最佳的实现:定制灵活.各种阴影和渐变以及动画的滑动效果都不错.不 ...

  6. 为Sublime Text 3设置优雅的字体

    本文使用的Sublime Text 3版本是3.2.1(build 3207),这个版本默认对中文的支持很糟糕,中国程序员很费眼睛,需要做一番设置. 首选需要在本机安装漂亮的字体,我们选用的是YaHe ...

  7. 第四周总结&实验报告二

    第四周总结&实验报告二 课程总结 这周我们学习了string类,以及很多string类的很多操作方法,同时string也是一个对象,在用到它时我们首字母需要大写,这周我们还加深了对函数构造的理 ...

  8. jquery自动播放音频文件

    使用jquery自动播放音频文件 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  9. React Native商城项目实战01 - 初始化设置

    1.创建项目 $ react-native init BuyDemo 2.导入图片资源 安卓:把文件夹放到/android/app/src/main/res/目录下,如图: iOS: Xcode打开工 ...

  10. 一、基础篇--1.1Java基础-int 和 Integer 有什么区别,Integer的值缓存范围

    int和Integer的区别 int是基本数据类型,Integer是int的包装类. Integer必须实例化后才能使用,int变量不需要. Integer实际是对象的引用,生成一个新对象实际上是生成 ...