蓝图 Blueprint
首先来瞅瞅 没有模块化的flask的简陋项目:
from flask import Flask, render_template, request, jsonify
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__,template_folder='templates')
# 配置
class Config(object):
DEBUG = True
SECRET_KEY = os.urandom(24) # 随机生成一个密钥
# 数据库链接配置 = 数据库名称://登录账号:登录密码@数据库主机IP:数据库访问端口/数据库名称?charset=编码类型
SQLALCHEMY_DATABASE_URI = "mysql://root:123456@127.0.0.1:3306/students?charset=utf8mb4"
# 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
# 初始化SQLAlchemy
db = SQLAlchemy() # 初始化数据库操作对象
db.init_app(app) # 初始化数据库链接
# models创建模型类
class yanilo(db.Model):
# 表结构声明
__tablename__ = "yanilo"
# 字段声明
id = db.Column(db.Integer, primary_key=True, comment="主键ID") # 字段类型
name = db.Column(db.String(250), comment="姓名")
age = db.Column(db.Integer, comment="年龄")
sex = db.Column(db.Boolean, default=False, comment="性别")
# DECIMAL设置小数精度,最多八位小数点后面两位 ,允许有空值,comment为列注释
money = db.Column(db.DECIMAL(8,2), nullable=True, comment="钱包")
def __repr__(self): # 定义 __repr__ 是为了方便调试,你可以不定义,也可以定义的更详细一些。
return self.name
# 路由+视图部分
@app.route('/')
def index():
# qwq = yanilo(
# name='qwq',
# age=15,
# sex=True,
# money=1222,
# )
# db.session.add(qwq)
# db.session.commit()
a = yanilo.query.filter(yanilo.name=='qwq').first()
print(a.sex,a.money,a.name,a.age)
return 'ok'
if __name__ == '__main__':
# with app.app_context():
# db.create_all() # 根据模型创建所有的数据表
# db.drop_all() # 删除模型对应的所有数据表
app.run()
模块化
随着flask程序越来越复杂,我们需要对程序进行模块化的处理,之前学习过python的模块化管理,于是针对一个简单的flask程序进行模块化处理
简单来说,Blueprint 是一个存储视图方法的容器,这些操作在这个Blueprint 被注册到一个应用之后就可以被调用,Flask 可以通过Blueprint来组织URL以及处理请求。
Flask使用Blueprint让应用实现模块化,在Flask中,Blueprint具有如下属性:
- 一个项目可以具有多个Blueprint
- 可以将一个Blueprint注册到任何一个未使用的URL下比如 “/”、“/sample”或者子域名
- 在一个应用中,一个模块可以注册多次
- Blueprint可以单独具有自己的模板、静态文件或者其它的通用操作方法,它并不是必须要实现应用的视图和函数的
- 在一个应用初始化时,就应该要注册需要使用的Blueprint
但是一个Blueprint并不是一个完整的应用,它不能独立于应用运行,而必须要注册到某一个应用中。
Blueprint对象用起来和一个应用/Flask对象差不多,最大的区别在于一个 蓝图对象没有办法独立运行,必须将它注册到一个应用对象上才能生效
使用蓝图可以分为四个步骤
- 创建一个蓝图的包,例如users,并在
__init__.py
文件中创建蓝图对象
users=Blueprint('users',__name__)
- 在这个蓝图目录下, 创建views.py文件,保存当前蓝图使用的视图函数
@admin.route('/')
def home():
return 'user.home'
- 在users/init.py中引入views.py中所有的视图函数
from flask import Blueprint
# 等同于原来在 manage.py里面的 app = Flask()
users=Blueprint('users',__name__)
from .views import *
- 在主应用main.py文件中的app对象上注册这个users蓝图对象
from users import users
app.register_blueprint(users,url_prefix='/users')
当这个应用启动后,通过/users/可以访问到蓝图中定义的视图函数
运行机制
-
蓝图是保存了一组将来可以在应用对象上执行的操作,注册路由就是一种操作
-
当在app对象上调用 route 装饰器注册路由时,这个操作将修改对象的url_map路由表
-
然而,蓝图对象根本没有路由表,当我们在蓝图对象上调用route装饰器注册路由时,它只是在内部的一个延迟操作记录列表defered_functions中添加了一个项
-
当执行app对象的 register_blueprint() 方法时,应用对象将从蓝图对象的 defered_functions 列表中取出每一项,并以自身作为参数执行该匿名函数,即调用应用对象的 add_url_rule() 方法,这将真正的修改应用对象的usr_map路由表
-
蓝图的url前缀
-
当我们在应用对象上注册一个蓝图时,可以指定一个url_prefix关键字参数(这个参数默认是/)
-
在应用最终的路由表 url_map中,在蓝图上注册的路由URL自动被加上了这个前缀,这个可以保证在多个蓝图中使用相同的URL规则而不会最终引起冲突,只要在注册蓝图时将不同的蓝图挂接到不同的自路径即可
-
url_for在使用时,如果要生成一个蓝图里面的视图对应的路由地址,则需要声明当前蓝图名称+视图名称
url_for('users.home') # /users/home
蓝图模块化基础版
└── qwq # 项目文件名
├── database.py # SQLAlchemy初始化文件
├── __init__.py
├── main.py # 主文件 数据配置 创建flask对象 启动文件 main.py
├── templates # 存放公共html的
│ └── header.html
└── users # 存放子应用目录文件
├── __init__.py # 创建蓝图目录 并注册视图
├── models.py # 定义模型类
├── users_static # 存放子应用的静态文件 如css、js等
│ └── 1.jpg
├── users_templates # 存放子应用html的
│ └── index.html
└── views.py # 视图
第一步:
在创建子应用包,users
在包下创建users_static、users_templates 文件夹 ,接着在包下创建modelsy.py、views.py
- 打开users包下的__init__.py,创建蓝图
和应用对象不同,蓝图对象创建时不会默认注册静态目录的路由。需要我们在 创建时指定 static_folder 参数。
下面的示例将蓝图所在目录下的static_users目录设置为静态目录
from flask import Blueprint
# 1. 创建蓝图目录并对蓝图对象进行初始化
user =Blueprint("users",__name__,template_folder="users_templates",
static_folder='users_static',static_url_path="/libs")
# template_folder:自定义视图返回文件夹
# static_folder: 自定义静态资源返回文件夹
# static_url_path="/libs" 前端访问资源文件的前缀目录。 例:访问users_static下的图片
# 图片的路径: /users/libs/1.jpg 而不是/users/users_static/1.jpg
# 注:如果在 templates 中存在和 templates_users 有同名模板文件时, 则系统会优先使用 templates 中的文件
- 打开 views.py
from . import users
from flask import render_template
# @users.route('/')
# def home():
# return 'user.home'
@users.route("/")
def index():
# title 传递给index.html里的参数
return render_template("index.html",title="users/index/index.html")
@users.route("/list")
def list():
return "users/list"
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>蓝图下的模板</p>
<h1>{{ title }}</h1>
<p><img src="/users/libs/1.jpg" alt=""></p>
</body>
</html>
- 在打开包下的__init__.py,注册视图
# 1. 创建蓝图目录并对蓝图对象进行初始化
from flask import Blueprint
users=Blueprint('users',__name__,template_folder='users_templates',static_folder='users_static',static_url_path='/xxx')
# 3. 注册视图
from .views import *
- 打开users同级目录的mian,py
from flask import Flask
app = Flask(__name__)
class Config():
# DEBUG调试模式
DEBUG = True
# json多字节转unicode编码
JSON_AS_ASCII = False
# 数据库链接配置
# SQLALCHEMY_DATABASE_URI = "mysql://账号:密码@IP/数据库名?编码"
SQLALCHEMY_DATABASE_URI = "mysql://root:123456@127.0.0.1:3306/students?charset=utf8mb4"
# 动态追踪修改设置,如未设置只会提示警告
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 查询时会显示原始SQL语句
SQLALCHEMY_ECHO = True
app.config.from_object(Config)
from database import db
db.init_app(app)
# 4. 注册蓝图
from users import users # 从users包下引入__init__里的users
from users.models import Yanilo # 从users包下引入models里的Ynilo模型类 为在创建数据库表
app.register_blueprint(users,url_prefix="/users") # 把users注册到flask对象里 方便调用,设置访问子路由的主路由
if __name__ == '__main__':
# with app.app_context():
# db.create_all()
app.run()
database.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
models.py:
from database import db
class Yanilo(db.Model):
__tablename__ = 'yanilo'
id = db.Column(db.Integer,primary_key=True,comment='主键id')
name = db.Column(db.String(250),comment='姓名')
age = db.Column(db.Integer,comment='年龄')
def __repr__(self):
return self.name