蓝图、g对象、数据库连接池
一、蓝图(blueprint)
1、介绍与作用
我们的应用经常会有很多小模块,比如用户模块、后台管理模块等,虽然这些模块都在同一个应用中,但是功能大不相同,把他们放在同一个文件中,显得十分杂乱,不便于管理维护,那么有没有什么方法可以将模块分开管理呢?是有的!Flask 蓝图(Blueprint),它可以模块化管理路由,使用蓝图可以把不同模块的视图函数写在不同的py文件中,在主视图中导入分路由视图的模块,并注册蓝图对象,降低各个功能模块的耦合度使程序结构更加简单、清晰。
2、蓝图的使用
不用蓝图,划分目录
-no_blueprint_flask # 项目名
-src #核心源码位置
-__init__.py # 包 里面实例化得到了app对象,
-models.py #放表模型
-views.py # 放视图函数
-static # 放静态资源
-templates # 放模板
-home.html # 模板
-manage.py # 启动文件
使用上述结构编写flask项目的时候需要注意,在src的双下init文件中需要导入views.py文件,这样内部的视图函数才会被注册
部分关键文件代码展示
manage.py
from src import app
if __name__ == '__main__':
app.run()
src的双下init.py
from flask import Flask
app = Flask(__name__, template_folder='../templates', static_folder='../static')
app.debug = True
app.secret_key = 'asdfasdjfklewlogsfjaojsifj'
from . import views
ps:有没有感觉和django的目录结构很像
3、使用蓝图,划分小型项目目录
蓝图的使用步骤
第一步:导入蓝图类
from flask import Blueprint
第二步:实例化得到蓝图对象
us=Blueprint('user', __name__)
第三步:在app中注册蓝图
app.register_blueprint(us)
第四步:在不同的views.py 使用蓝图注册路由
@us.route('/login')
"""
补充:蓝图可以有自己的静态文件和模板
补充:注册蓝图时,可以使用前缀,必须以/开头
"""
划分目录
-little_blueprint # 项目名
-src # 核心代码
-static # 静态文件
-1.jpg # 图片
-templates # 模板文件
-user.html # 模板
-views # 视图函数存放位置
-order.py # 订单相关视图
-user.py # 用户相关视图
-__init__.py # 包
-models.py # 表模型
-manage.py # 启动文件
manage.py
from src import app
if __name__ == '__main__':
app.run()
src的双下init.py
from flask import Flask
app = Flask(__name__)
app.debug = True
app.secret_key = 'asdfasdjfklewlogsfjaojsifj'
from .views.user import user_bp
from .views.order import order_bp
app.register_blueprint(user_bp)
app.register_blueprint(order_bp)
user.py
from src import app
from flask import Blueprint, render_template
user_bp = Blueprint('user', __name__)
@app.route('/user-index')
def user_index():
return 'user-index'
@app.route('/home')
def user_home():
return render_template('home.html', name='zzh')
4、使用蓝图划分大型项目目录
# 使用蓝图,划分大型项目目录 分成多个app,像django一样
-big_blueprint # 项目名
-src # 核心文件
-admin # admin的app
-static # 静态文件
-1.jpg # 图片
-templates # 模板文件目录
-admin_home.html # 模板文件
-__init__.py # 包
-models.py # 表模型
-views.py # 视图函数
-home # home app
-order # orderapp
-__init__.py # 包
-settings.py # 配置文件
-manage.py # 启动文件
我们在编写大型项目目录的时候把蓝图对象的创建放到了每个app文件夹内的双下init文件中,我们需要在其内部导入包内的views.py文件,执行视图的路由注册
在注册蓝图对象的时候,可以设置蓝图的路由前缀,使用的属性如下(必须要在前面带上斜杠):
url_prefix='/admin'
部分关键文件代码展示
manage.py
from src import app
if __name__ == '__main__':
app.run()
src的双下init.py
from flask import Flask
app = Flask(__name__)
app.config.from_pyfile('settings.py')
from .admin import admin_bp
# from .home import home_bp
# from .order import order_bp
app.register_blueprint(admin_bp, url_prefix='/admin')
# app.register_blueprint(home_bp, url_prefix='home')
# app.register_blueprint(order_bp, url_prefix='order')
admin app的双下init.py
from flask import Blueprint
admin_bp = Blueprint('admin', __name__, static_folder='static', template_folder='templates')
from . import views
admin app的views.py
from flask import render_template
from . import admin_bp
@admin_bp.route('/home')
def home():
return render_template('/home.html')
5、其他知识点
当我们使用蓝图的时候,可以在每个视图内使用请求扩展,他只作用于当前的视图(用蓝图对象去注册请求扩展方法),如果我们想把请求扩展用于全局,就是使用app(Flask对象)去注册
二、g对象
1、g对象是什么?
g是global的缩写,在python中是个关键字,不能以关键字作为变量名,干脆用了g
g对象是个全局变量,在任意的位置导入使用即可,在整个请求的全局,可以放值,可以取值
2、作用
为什么不学django使用request作为上下文【因为使用request,可能会造成request数据的污染,不小心改了request的属性,但你不知道】
防止和 request 内部的属性混乱,比如不知道 request 里面有没有 name 属性,可以直接 g.name 设值。只对这个请求设值
所以flask使用g,建议使用g是空的,放入之后在当次请求中全局优先。
以后想在当次请求中,放入一些数据,后面使用,就可以使用g对象
3、g和session有什么区别?
-
g是只针对当次请求
-
session针对于多次请求
from flask import Flask, g, request
app = Flask(__name__)
app.debug = True
@app.before_request
def before():
if 'home' in request.path:
g.xx = 'xx'
def add(a, b):
# print('---',g.name)
print('---', request.name)
return a + b
@app.route('/')
def index():
print(g.xx)
name = request.args.get('name')
# g.name = name
request.method = name
res = add(1, 2)
print(res)
return 'index'
@app.route('/home')
def home():
print(g.xx)
return 'index'
if __name__ == '__main__':
app.run()
三、数据库连接池
flask操作mysql
使用pymysql
-
在视图函数中,创建pymysql的连接,查数据,查完,返回给前端
存在问题:来一个请求,创建一个连接,请求介绍,连接关闭(django就是这么做的)
-
把连接对象,做成全局的,在视图函数中,使用全局的连接,查询,返回给前端
存在问题:会出现数据错乱,详见下图
带池的代码
@app.route('/article_pool') def article_pool(): conn = pool.connection() cursor = conn.cursor(pymysql.cursors.DictCursor) cursor.execute('select id,title,author_img from aritcle limit 2') res = cursor.fetchall() print(res) return jsonify(res)不带池的代码
def article(): conn = pymysql.connect(user='root', password="", host='127.0.0.1', database='cnblogs', port=3306) cursor = conn.cursor(pymysql.cursors.DictCursor) time.sleep(random.randint(1,3)) cursor.execute('select id,title,author_img from aritcle limit 2') res = cursor.fetchall() cursor.close() conn.close() return jsonify(res)压力测试代码
from threading import Thread import requests def task(): res = requests.get('http://127.0.0.1:5000/article_pool') print(len(res.text)) if __name__ == '__main__': for i in range(500): t = Thread(target=task) t.start()效果:
使用池得到连接数明显小
不使用池连接数明显很大
查看数据库连接数:
show status like 'Threads%'


浙公网安备 33010602011771号