文章目录
一.缓存
1.缓存介绍
(1)缓存目的
缓存优化加载,减少数据库的IO操作
(2)实现方案
a.缓存到数据库 b.缓存到文件 c.缓存到内存 d.缓存到内存中的数据库Redis
(3)实现流程
a.从路由函数进入程序
b.路由函数到视图函数
c.视图函数去缓存中查找
d.缓存中找到,直接进行数据返回
e.如果没找到,去数据库中查找
f.查找到之后,添加到缓存中
g.返回到页面上
2.缓存使用
(1)安装 flask-cache
pip install flask-cache
(2)初始化
在ext文件中,指定使用的缓存方案
cache = Cache(config={‘CACHE_TYPE’:‘redis’})
cache.init_app(app=app)
(3)flask-cache版本问题
初始化后,在云服务器中启动会报错
1.这是由于flask更新了,werkzeug也跟着更新,但是flask-cache版本没有更新,所以版本兼容性就出现了问题。此时的flask-cache兼容0.16.1版本的werkzeug。
解决方案:(1)先将werkzeug卸载:pip uninstall werkzeug
(2)然后安装0.16.1版本:pip install werkzeug==0.16.1
2.解决上面的问题后,又出现No module named 'flask.ext’的问题
解决方案 :(1)进入到flask-cache的库,然后点击jinja2ext.py
(2)将from flask.ext.cache import make_template_fragment_key,修改为from flask_cache import make_template_fragment_key
设置完成后,则能正常运行。
(4)装饰器缓存
在views文件中添加:
@blue.route('/testCache/')
@cache.cached(timeout=20)
def testCache():
time.sleep(5)#睡眠5秒
return '测试缓存'
1.这里要引用cache变量,所以是让ext文件中的cache = Cache(config={‘CACHE_TYPE’:‘redis’})放到函数外,作为全局变量
2.装饰器缓存,timeout是缓存的生存时间,20秒内有缓存
3.缓存如果生效,第一次访问需要5秒,睡眠5秒,然后只要在缓存时间内的第二次以后的访问都不需要睡眠5秒。
(5)基本使用
需求:如果你是第一次访问,那么显示欢迎来到我的博客,如果你是第二次访问,那么显示爬虫快走开。
@blue.route('/testCache1/')
def testCache1():
#cache.get(key)获取
value = cache.get('ip')
if value:
return '爬虫快走开'
else:
#如果没有拿到这个value的时候,就在缓存中设置一下
#等下一次访问就可以拿到了
ip = request.remote_addr
#cache.set(key value)设置的意思
cache.set('ip', ip, timeout=10)
return '欢迎来到我的博客'
运行结果:
第一次访问:
第二次访问:
二.钩子
现连接数据库进行增删改查,一般我们会如下操作:
@blue.route('/add/')
def add():
print('连接数据库')
return 'add'
@blue.route('/delete/')
def delete():
print('连接数据库')
return 'delete'
@blue.route('/update/')
def update():
print('连接数据库')
return 'update'
@blue.route('/find/')
def find():
print('连接数据库')
return 'find'
通过上面的代码,我们发现代码冗余,并没有实现解耦合,add、delete、update、find,它们每一个动作都是做自己的事 和连接数据库没有任何的关系。
这时,有人可能会想到将其封装,如下:
def getConn():
print('连接数据库')
@blue.route('/add/')
def add():
getConn()
return 'add'
@blue.route('/delete/')
def delete():
getConn()
return 'delete'
@blue.route('/update/')
def update():
getConn()
return 'update'
@blue.route('/find/')
def find():
getConn()
return 'find'
如果将4个方法中公用的逻辑封装方法,那么也不是很好,因为耦合度同样很高,我们这种治标不治本,只不过看似代码减少。
解决方案:在执行视图函数之前,就执行某个方法
例如:如果我们能够在执行add、delete、update、find视图函数之前就执行某个方法而且这些方法还不会再add、delete、update、find中体现,那么耦合度是不是降到了最低。
blue.before_request就是在执行视图函数之前执行的方法
钩子的用法体现了一种思想,面向切面编程,也叫做面向方面编程(AOP)
代码都是一行一行的从上到下的执行,面对对象开发都是纵向开发,钩子这种方式实现了横向的开发,我们把这种方式叫做面向切面编程(AOP)
如果我们定义了@blue.before_request,那么所有的视图函数执行之前都会执行before_request。
@blue.route('/add/')
def add():
print('==================')
return 'add'
@blue.route('/delete/')
def delete():
return 'delete'
@blue.route('/update/')
def update():
return 'update'
@blue.route('/find/')
def find():
return 'find'
@blue.before_request
def conn():
print('连接数据库')
运行结果:
那么我们如何过滤请求?如下:
@blue.before_request
def conn():
REQ_LIST = ['/add/','/delete/','/update/', '/find/']
if request.path in REQ_LIST:
print('连接数据库')
运行结果:
有在执行函数之前执行的方法,自然有在执行函数之后执行的方法。
@blue.after_request
def testClose(a):
print('关闭连接')
return a
运行结果:
三.四大内置对象
不需要创建就可以直接使用的对象
1.request和session
request和session我们之前写到过,这里就不说了,详情请看我之前的博文:Flask的Request、Response以及异常和Flask的会话技术:cookie、session以及session持久化问题
2.config
可以用来查看当前项目的配置信息,可以在模板中直接使用
在视图函数中:
@blue.route('/testConfig/')
def testConfig():
for c in current_app.config:
print(c)
return render_template('testConfig.html')
创建testConfig.html文件:
<body>
<ul>
{% for c in config %}
<li>{{ c }}</li>
{% endfor %}
</ul>
</body>
运行结果:
3.g
g:global(全局),可以帮助开发者实现跨函数传递数据
@blue.route('/g/')
def g():
ip = request.remote_addr
return '测试g'
思考:ip变量如何能在testg中使用?
@blue.route('/testg/')
def testg():
return 'testg'
这时我们可以使用内置对象g:
@blue.route('/g/')
def g():
g.ip = request.remote_addr
return '测试g'
@blue.route('/testg/')
def testg():
print('================')
print(g.ip)
print('================')
return 'testg'
如果先运行testg,则会出现以下情况:
所以必须要在使用的那个视图函数之前使用,先运行g再运行testg:
四.模板和static的路径问题
创建视图函数testRoute:
@blue.route('/testRoute/')
def testRoute():
return render_template('testRoute.html')
创建testRoute.html模板:
<body>
今天天气真好,适合爬山
</body>
运行结果:
思考:如果我们将static和templates拿出App文件夹,与App同级,是否能正常运行?
运行结果:
由上可知,路径出现错误,这时就需要在init文件中添加:
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
template_folder = os.path.join(BASE_DIR,'templates')
static_folder = os.path.join(BASE_DIR,'static')
app = Flask(__name__,template_folder=template_folder,static_folder=static_folder)
保存上传,即可运行成功。