蓝图
使用场景
如果代码非常多,要进行归类。不同的功能放在不同的文件,把相关的视图函数也放进去。
蓝图也就是对flask的目录结构进行分配(应用于小,中型的程序)
当然对于大型项目也可以通过 url_prefix 加前缀的方式实现
使用方法
# __init__.py from .views.account import ac from .views.user import usapp.register_blueprint(ac) app.register_blueprint(us)# account.py from flask import Blueprint,render_template ac = Blueprint("ac" ,__name__,template_folder="xxxx",static_url_path="xxxx")# template_folder 优先在 templates 文件夹找。找不到再去 xxxx 里找 # static_url_path 优先在 static 文件夹找。找不到再去 xxxx 里找 # url_prefix="/xx" 为当前蓝图的url里加前缀
目录结构
crm crmviewaccount.pyuser.pystatictemplateslogin.html__init__.pymanage.py
__init__.py
只要一导入crm就会执行__init__.py文件
在此文件实现app 对象的生成,以及所有蓝图的注册功能
from flask import Flask from .views.account import ac from .views.user import us def create_app():app = Flack(__name__)@app.before_request # 对全局的视图有效 def xx():print("app.before_request")app.register_blueprint(ac)app.register_blueprint(us)return app
account.py
各自的视图文件,创建蓝图对象
自己视图的使用为自己的蓝图对象
注意: 视图函数的名字不能和蓝图对象重名
from flask import Blueprint,render_template ac = Blueprint("ac" ,__name__,template_folder="xxxx",static_url_path="xxxx") # template_folder 优先在 templates 文件夹找。找不到再去 xxxx 里找 # static_url_path 优先在 static 文件夹找。找不到再去 xxxx 里找 # url_prefix="/xx" 为当前蓝图的url里加前缀 @ac.route("/login") def login():return render_template("login.html")
user.py
from flask import Blueprint us = Blueprint("us" ,__name__)@us.before_request # 仅对当前的视图有效 def xx():print("us.before_request")@us.route("/user") def user():return "user"
DBUtils 链接数据库
flask中是没有ORM的,如果在flask里面连接数据库有两种方式
pymysql SQLAlchemy是python 操作数据库的一个库。能够进行 orm 映射官方文档 sqlchemySQLAlchemy“采用简单的Python语言,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型”。SQLAlchemy的理念是,SQL数据库的量级和性能重要于对象集合;而对象集合的抽象又重要于表和行。
pymysql 实现数据库操作
方式一 数据库链接放在视图中
每次视图的执行进行数据库连接查询关闭。
反复创建数据库链接,多次链接数据库会非常耗时
解决办法:放在全局,单例模式
#!usr/bin/env python # -*- coding:utf-8 -*- import pymysql from flask import Flaskapp = Flask(__name__)@app.route('/index') def index():# 链接数据库conn = pymysql.connect(host="127.0.0.1",port=3306,user='root',password='123', database='pooldb',charset='utf8')cursor = conn.cursor()cursor.execute("select * from td where id=%s", [5, ])result = cursor.fetchall() # 获取数据cursor.close()conn.close() # 关闭链接print(result)return "执行成功"if __name__ == '__main__':app.run(debug=True)
方式二 放在全局
不在频繁链接数据库。
如果是单线程,这样没什么问题,
但是如果是多线程,就得加把锁。这样就成串行的了
为了支持并发,此方法依旧不可取
#!usr/bin/env python # -*- coding:utf-8 -*- import pymysql from flask import Flask from threading import RLockapp = Flask(__name__) CONN = pymysql.connect(host="127.0.0.1",port=3306,user='root',password='123', database='pooldb',charset='utf8')@app.route('/index') def index():with RLock:cursor = CONN.cursor()cursor.execute("select * from td where id=%s", [5, ])result = cursor.fetchall() # 获取数据cursor.close()print(result)return "执行成功" if __name__ == '__main__':app.run(debug=True)
为此。为了解决方式一二的问题,实现不频繁操作且可以并行的数据库链接,我们需要用到 DBUtils
方式三 DBUtils + thread.local
为每一个线程创建一个链接(是基于本地线程来实现的。thread.local),
每个线程独立使用自己的数据库链接,该线程关闭不是真正的关闭,本线程再次调用时,还是使用的最开始创建的链接,直到线程终止,数据库链接才关闭
#!usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask app = Flask(__name__) from DBUtils.PersistentDB import PersistentDB import pymysql POOL = PersistentDB(creator=pymysql, # 使用链接数据库的模块maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制setsession=[], # 开始会话前执行的命令列表。如:["set datestyle to ...", "set time zone ..."]ping=0,# ping MySQL服务端,检查是否服务可用。# 如:0 = None = never, 1 = default = whenever it is requested, 2 = when a cursor is created, 4 = when a query is executed, 7 = alwayscloseable=False,# 如果为False时, conn.close() 实际上被忽略,供下次使用,再线程关闭时,才会自动关闭链接。如果为True时, conn.close()则关闭链接,那么再次调用pool.connection时就会报错,因为已经真的关闭了连接(pool.steady_connection()可以获取一个新的链接)threadlocal=None, # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置host='127.0.0.1',port=3306,user='root',password='123',database='pooldb',charset='utf8' )@app.route('/func') def func():conn = POOL.connection()cursor = conn.cursor()cursor.execute('select * from tb1')result = cursor.fetchall()cursor.close()conn.close() # 不是真的关闭,而是假的关闭。 conn = pymysql.connect() conn.close()conn = POOL.connection()cursor = conn.cursor()cursor.execute('select * from tb1')result = cursor.fetchall()cursor.close()conn.close() if __name__ == '__main__': app.run(debug=True)
方式四 DBUtils + 链接池
创建一个链接池,为所有线程提供连接,使用时来进行获取,使用完毕后在放回到连接池。
PS:
假设最大链接数有10个,其实也就是一个列表,当你pop一个,人家会在append一个,链接池的所有的链接都是按照排队的这样的方式来链接的。
链接池里所有的链接都能重复使用,共享的, 即实现了并发,又防止了链接次数太多
#!usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask app = Flask(__name__) from DBUtils.PersistentDB import PersistentDB import pymysqlPOOL = PooledDB(creator=pymysql, # 使用链接数据库的模块maxconnections=6, # 连接池允许的最大连接数,0和None表示不限制连接数mincached=2, # 初始化时,链接池中至少创建的空闲的链接,0表示不创建maxcached=5, # 链接池中最多闲置的链接,0和None不限制maxshared=3, # 链接池中最多共享的链接数量,0和None表示全部共享。# PS: 无用,因为pymysql和MySQLdb等模块的 threadsafety都为1,所有值无论设置为多少,_maxcached永远为0,所以永远是所有链接都共享。blocking=True, # 连接池中如果没有可用连接后,是否阻塞等待。True,等待;False,不等待然后报错maxusage=None, # 一个链接最多被重复使用的次数,None表示无限制setsession=[], # 开始会话前执行的命令列 AQ 表。如:["set datestyle to ...", "set time zone ..."]threadlocal=None, # 本线程独享值得对象,用于保存链接对象,如果链接对象被重置ping=0,# ping MySQL服务端,检查是否服务可用。# 取值:# 0 = None = never, # 1 = default = whenever it is requested, # 2 = when a cursor is created, # 4 = when a query is executed, # 7 = alwayshost='127.0.0.1',port=3306,user='root',password='',database='core_master',charset='utf8' ) @app.route('/func') def func():conn = POOL.connection()cursor = conn.cursor()cursor.execute('select * from tb1')result = cursor.fetchall()cursor.close()conn.close() # 不是真的关闭,而是假的关闭。 conn = pymysql.connect() conn.close()conn = POOL.connection()cursor = conn.cursor()cursor.execute('select * from tb1')result = cursor.fetchall()cursor.close()conn.close() if __name__ == '__main__': app.run(debug=True)
转载请标明出处:11.4 Flask 蓝图,数据库链接
文章来源: 11.4 Flask 蓝图,数据库链接