首先,学习flask之前,先了解一下Django和Flask中是怎么渲染字符串的。在Django中使用mark_safe();在Flask中使用Markup();还可以在HTML中使用管道符{{ add | safe }}。简单介绍一下Flask,它是轻量型的,第三方组件非常丰富,可扩展性比较强,用法和Django差不多。
一、介绍Flask、Django、Tornado框架
Django:重武器,内部包含了非常多的组件(ORM、Form、ModelForm、缓存、Session、中间件、信号等)
Flask:短小精悍,内部没有太多的组件,第三方组件非常丰富。路由比较特殊,基于装饰器来实现,但是究其本质还是通过add_url_rule来实现。
Tornado:异步非阻塞框架(node.js)
bottle:第三方库比较少
web.py:比较老
二、Flask入门
安装
pip3 install flask
WSGI
werkzeug示例(flask)
wsgiref示例(wsgi)
本质的本质
flask
View Code
三、配置文件
settings.py
四、路由系统
设置URL路由使用route()装饰器,route()装饰哪个函数,那么route()中的参数就映射到哪个函数
路由路径支持变量
形式:
converter支持的类型:
示例
@app.route和@app.add_url_rule参数
View Code
五、模板语言
Flask使用的是jinja2模板,所以其语法和Django无差别
Flask中自定义模板方法的方式和Bottle相似,创建一个函数并通过参数的形式传入render_template
六、请求&响应相关
请求相关信息
响应相关信息
七、Session&Cookie
除请求对象之外,还有一个 session 对象。它允许你在不同请求间存储特定用户的信息。它是在 Cookies 的基础上实现的,并且对 Cookies 进行密钥签名要使用会话,你需要设置一个密钥。
设置:session['username'] = 'xxx'
删除:session.pop('username', None)
八、闪现(基于session实现的)
应用:对临时数据操作,如显示错误信息
代码示例
九、蓝图(blueprint)
目标:构造程序目录
优点:可以批量URL
指定模板路径/静态文件路径
请求扩展(针对pp或者针对某个蓝图)
注意:蓝图对象名称和函数名称不能重复
十、请求扩展(Django中间件)
基于before_request做用户登录认证
代码示例
执行顺序
代码示例
请求拦截后,response所有都执行,函数不再执行
代码示例
定制错误信息
代码示例
模板中定义方法
代码示例
第一次进来要执行的操作
代码示例
十一、中间件
代码示例
十二、上下文管理
请求上下文
threading.local对象,用于为每个线程开辟一块空间来保存它独有的值
代码示例
源码(request)
情况一:单进程单线程,基于全局变量做
情况二:单进程多进程,基于threading.local对象做
情况三:单进程单线程(多个协程),threading.local对象做不到
决定
以后不支持协程:threading.local对象
支持:自定义threading.local对象(支持协程)
代码示例
自定义类似threading.local对象
一、self.storage={}
object.__setattr__(self, 'storage', {}) 使用此方法时,对象.xx不会调用__setattr__()方法
二、对象.xx
触发:
def __setattr__(self, key, value):
print(key, value)
flask上下文管理机制
1.threading.local对每个线程保留它自己的值,但是flask为了支持协程,它自己定义了一个Local对象,其中创建了一个字典{greenlet做唯一标识:存数据},保证数据隔离,在Local对象中保存它的值
2.三个流程
a.请求到来时
ctx=封装RequestContext(request, session)
ctx放到local中
请求刚进来封装了一个RequestContext对象,ctx=封装RequestContext(request,session),ctx通过push()加到local对象中
具体用到的是_local.stack把信息加到local对象中
b.执行视图时
导入request
print(request) --> LocalProxy对象的__str__方法
request.method --> LocalProxy对象的__getattr__方法
request + 1 --> LocalProxy对象的__add__方法
都会调用_lookup_req_object函数:去local中将requestContext获取到,再去requestContext中获取request或session
c.请求结束
ctx.auto_pop()
ctx从local中移除
拿到之后在执行_request_ctx_stack.pop(),去local里面把原来请求相关的requestContext对象删除掉,这次请求终止
3.与Django相比是两种不同的实现方式
Django/tornado是通过传参数形式
flask是通过上下文管理,两种方式都可以实现,只不过实现方式不一样
应用上下文
请求流程:
_request_ctx_stack.local = { }
_app_ctx_stack.local = { }
1.请求到来,有人来访问
View Code
2.使用
View Code
3.终止,ctx、app_ctx全部pop
问题1:多线程是如何实现?
不管几个线程进来都是两个local对象,只不过是每个线程的唯一标识不同,而所有线程的唯一标识都放在对应的Local对象中,使用时取自己对应的不会出错
问题2:flask的local中保存数据时,使用列表创建出来的是栈
如果写web程序,web运行环境:栈中永远保存1条数据(可以不用栈)
写脚本获取app信息时,可能存在app上下文嵌套关系(要使用栈)
代码示例
多app应用
代码示例
问题3:web访问多app应用时,上下文管理是如何实现?
每个app都会调用自己的__call__方法,而且都有自己的唯一标识,并且添加到相应的local对象中,只是对应的app是不一样的,执行过程和多线程实现过程类似
补充:当用脚本写flask时,有可能会出现堆栈
View Code
十三、偏函数
代码示例
十四、面向对象
当把面向对象中的所有__函数__实现时,对象做任何操作时,都会执行其中对应的方法
代码示例
面向对象私有
代码示例
十五、拼接列表中的值
实例一
实例二
十六、数据库连接池(基于threading.local实现)
友情链接:https://www.cnblogs.com/wupeiqi/articles/8184686.html
Django和Flask使用数据库分析
Django:ORM(pymysql/MySQLdb)
Flask:原生SQL
pymysql(2/3)
MySQLdb(2)
SQLAlchemy(ORM)
原生SQL
代码示例
问题
1.来一个用户连接一次数据库(把连接数据库的操作放到全局变量中)
2.并发运行时,拿到的数据有可能是错的
3.加锁可以解决信息错误的问题,但是没有并发运行
解决思路
不能为每个用户创建一个连接
创建一定数量的连接池,如果有人来使用时有空的就拿去用,用完再还回来,没有时就等待
使用DBUtils模块
安装:如果安装到虚拟环境,需要先切换到虚拟环境
使用:
模式一:为每个线程创建一个连接
模式二:创建n个连接,多线程来时,去获取
代码示例
十七、信号(只能执行不能终止)
Django:要有请求、有信号、信号中注册函数
Flask:
before_first_request
触发request_started信号
before_request
模板渲染
渲染前的信号:before_render_template.send(app, template=template, context=context)
rv = template.render(context) # 模板渲染
渲染后的信号:template_rendered.send(app, template=template, context=context)
after_request
session.save_session()
触发request_finished信号
如果上述过程出错:
触发错误处理信号:got_request_exception.send(self, exception=e)
触发信号:request_tearing_down
十八、MetaClass
作用:用来指定当前类是由谁来创建(默认type创建)
类由type创建:class Foo(metaclass=type)
继承type:class Foo(type)
十九、Flask-session
Flask中的session处理机制(内置:将session保存在加密的cookie中实现)
请求刚进来:获取随机字符串,存在则去"数据库"中获取原来的个人数据,否则创建一个空容器。--> 内存:对象(随机字符串,{放置数据的容器})
# 到底是什么对象?
# 1.obj = 创建SecureCookieSessionInterface()
# 2.obj = open_session(self.app, self.request) = SecureCookieSession()
# self.session = SecureCookieSession()对象
# 为session创建一个特殊的字典
self.session = session_interface.open_session(self.app, self.request)
视图:操作内存中对象(随机字符串,{放置数据的容器})
响应:内存对象(随机字符串,{放置数据的容器})
将数据保存到数据库
把随机字符串写在用户cookie中
自定义
请求刚进来:
# 创建特殊的字典,并添加到Local中
# 调用关系:
# self.session_interface.open_session(self, request)
# 由于默认app中的session_interface = SecureCookieSessionInterface()
# SecureCookieSessionInterface().open_session(self, request)
# 由于默认app中的session_interface = MySessionInterFace()
# MySessionInterFace().open_session(self, request)
self.session = session_interface.open_session(self.app, self.request)
调用:
session --> LocalProxy --> 偏函数 --> LocalStack --> Local
请求终止:
# 由于默认app中的session_interface = SecureCookieSessionInterface()
# SecureCookieSessionInterface().save_session(self, app, session, response)
# 由于默认app中的session_interface = MySessionInterFace()
# MySessionInterFace().save_session(self, app, session, response)
flask-session组件
随机生成一个ID
>>> from uuid import uuid4
>>> uuid4()
UUID('81a3ae5a-991f-4eb9-9e1d-76c11d248887')
使用:
代码示例
问题:设置cookie时,如何设定关闭浏览器则cookie失效
request.set_cookie('k', 'v', exipre=None)
二十、总结
1.哪里还用到过threading.local
DBUtils
2.上下文管理
请求:
request:封装请求相关信息
session:保存用户回话相关信息
应用:
app:当前应用相关信息
g:每个请求周期都会创建一个用于在请求周期中传递值的一个容器
3.多app应用&蓝图
都是分发URL,多app应用是在app前面分发,蓝图是在app后面分发
4.为什么用栈?
存在app上下文嵌套关系时,会将信息堆栈,但是不用担心取值的问题,因为当前app每次取值都是取的最后一个,用完之后就清除了,而不会影响其他app的使用,相当于一个先进后出的队列
5.面向对象
封装
View Code
某个值 + 括号
函数/方法:看谁调用,判断函数或方法
类和对象
特殊的双下划线方法,flask中的LocalProxy里面都使用过
View Code
强制调用私有字段,只能在自己这个类中调用
子类和派生类中都不能调用基类私有字段https://www.cnblogs.com/ccmldl/p/9651663.html