Flask基础
什么是Flask
Flask诞生于2010年,是Armin ronacher(人名)用 Python 语言基于 Werkzeug 工具箱编写的轻量级Web开发框架。
Flask 本身相当于一个内核,其他几乎所有的功能都要用到扩展(邮件扩展Flask-Mail,用户认证Flask-Login,数据库Flask-SQLAlchemy),都需要用第三方的扩展来实现。比如可以用 Flask 扩展加入ORM、窗体验证工具,文件上传、身份验证等。Flask 没有默认使用的数据库,你可以选择 MySQL,也可以用 NoSQL。
其 WSGI 工具箱采用 Werkzeug(路由模块),模板引擎则使用 Jinja2。这两个也是 Flask 框架的核心。
官网: https://flask.palletsprojects.com
官方文档: http://docs.jinkan.org/docs/flask/
Flask常用第三方扩展包
扩展名称
功能
Flask-SQLAlchemy
操作数据库,提供对象关系映射 (ORM) 功能
Flask-Script
终端脚本工具,提供脚手架功能
Flask-Migrate
管理数据库迁移
Flask-Session
指定 Session 存储方式
Flask-WTF
表单处理
Flask-Mail
邮件处理
Flask-Babel
提供国际化和本地化支持,翻译
Flask-Login
认证用户状态
Flask-OpenID
认证,OAuth
Flask-RESTful
开发 REST API 的工具
Flask JSON-RPC
开发远程过程调用 (RPC) 服务
Flask-Bootstrap
集成前端 Twitter Bootstrap 框架
Flask-Moment
本地化日期和时间处理
Flask-Admin
简单且可扩展的管理接口框架
创建Flask项目
创建flask虚拟环境
virtualenv venv/flask -p python3
安装flask
virtualenv venv/flask -p python3
在项目目录下创建入口程序文件,名称可以是app.py
、run.py
、main.py
、index.py
from flask import Flask""" import_name Flask程序所在的包(模块),传 __name__ 就可以 其可以决定 Flask 在访问静态文件时查找的路径 static_path 静态文件访问路径(不推荐使用,使用 static_url_path 代替) static_url_path 静态文件访问路径,可以不传,默认为:/ + static_folder static_folder 静态文件存储的文件夹,可以不传,默认为 static template_folder 模板文件存储的文件夹,可以不传,默认为 templates """ app = Flask(import_name=__name__) @app.route('/' ) def index (): return "<h1>hello world</h1>" class Config (object ): DEBUG = True app.config.from_object( Config ) if __name__ == '__main__' : app.run(host="0.0.0.0" , port=5000 )
Flask路由
什么是Flask路由
在 Flask 中,路由用于定义 URL 与视图函数之间的映射关系。通过定义路由,可以将不同的 URL 请求分发到对应的视图函数来处理。
Flask路由命名规范
使用有意义的名称:为了增加代码的可读性和可理解性,建议为路由选择有意义的名称,以反映其功能或用途。例如,对于用户相关的路由,可以使用类似于 /users/<username>
或 /profile/<user_id>
这样的命名。
使用动词表示操作:在 RESTful 风格的应用程序中,建议使用动词来表示操作。例如,使用 GET
方法获取资源的路由可以命名为 get_resource
,使用 POST
方法创建资源的路由可以命名为 create_resource
,以此类推。
使用名词表示资源:对于表示资源的路由,建议使用名词来命名。例如,如果应用程序提供了博客文章的路由,可以使用 /articles
或 /posts
来表示博客文章的资源。
使用下划线分隔单词:为了提高可读性,建议在路由名称中使用下划线 _
来分隔单词。例如,使用 user_profile
而不是 userprofile
。
避免使用动词或复杂的命名:在命名路由时,应避免使用过于复杂或包含动词的名称。路由应该更加关注资源和功能,而不是操作。例如,避免使用类似于 /get_user_profile
或 /delete_user_by_id
这样的命名。
使用路由名称生成 URL:Flask 提供了 url_for()
函数,可以根据路由的名称生成对应的 URL。使用路由名称生成 URL 可以提高代码的可维护性,因为如果路由的 URL 发生更改,只需修改路由定义而不需要在整个应用程序中手动更新 URL。
基本语法
示例:访问路径为/
;当浏览器访问根路径时处理函数为index
函数
from flask import Flaskapp = Flask(__name__) @app.route('/' ) def index (): return 'Hello, World!'
限定路由参数
限定路由参数的类型,flask系统自带转换器编写在venv/flask/lib/python3.10/site-packages/werkzeug/routing/converters.py
文件中。底部可以看到以下字典:
DEFAULT_CONVERTERS: t.Mapping[str , type [BaseConverter]] = { "default" : UnicodeConverter, "string" : UnicodeConverter, "any" : AnyConverter, "path" : PathConverter, "int" : IntegerConverter, "float" : FloatConverter, "uuid" : UUIDConverter, }
转换器介绍:
转换器名称
描述
string
默认类型,接受不带斜杠的任何文本
int
接受正整数
float
接受正浮点值
path
接收 string 但也接受斜线
uuid
接受 UUID(通用唯一识别码)字符串 xxxx-xxxx-xxxxx-xxxxx
示例:接受int类型参数
@app.route('/user/<int:user_id>' ) def user_info (user_id ): return 'hello %d' % user_id
限定路由请求方式
请求方式
描述
GET
用于获取资源,不对服务器数据做修改
POST
用于向服务器提交数据,对数据进行新增操作
PUT
用于向服务器提交数据,对数据进行修改操作
PATCH
用于向服务器提交数据,对数据进行局部修改操作
DELETE
用于删除服务器上的资源
OPTIONS
用于获取目标资源支持的请求方法列表
HEAD
与 GET 类似,但只返回响应头部,不返回实体主体
示例:
from flask import Flask,request@app.route(rule="/user" , methods=["post" ,"put" ,"get" ,"delete" ,"patch" ] ) def user (): print (request.method) print (request.query_string) print (request.path) print (request.url) return request.method
自定义参数转换器
自定义参数转换器也叫正则匹配路由参数;在 web 开发中,可能会出现限制用户访问规则的场景,那么这个时候就需要用到正则匹配,根据自己的规则去限定请求参数再进行访问
具体实现步骤为:
导入转换器基类:在 Flask 中,所有的路由的匹配规则都是使用转换器对象进行记录
自定义转换器:自定义类继承于转换器基类
添加转换器到默认的转换器字典中
使用自定义转换器实现自定义匹配规则
示例:
定义了一个名为 MyConverter 的自定义转换器类,并在其 to_python 方法中将参数值转换为 Python 对象。
在 to_url 方法中将 Python 对象转换为 URL 字符串。
通过 app.url_map.converters 字典将自定义转换器注册到 Flask 应用中。
使用 @app.route() 装饰器指定了一个路由,其中的路由参数使用了我们自定义的转换器 <myconverter:date>
。
当访问类似于 /date/2022-01-01 的 URL 时,Flask 会自动匹配并调用我们定义的转换器,将参数转换为 Python 对象,并将其传递给视图函数 show_date。
from flask import Flaskapp = Flask(__name__) class MyConverter : def __init__ (self, url_map ): self .regex = r'\d{4}-\d{2}-\d{2}' self .url_map = url_map def to_python (self, value ): year, month, day = value.split('-' ) return datetime.date(int (year), int (month), int (day)) def to_url (self, value ): return value.strftime('%Y-%m-%d' ) app.url_map.converters['myconverter' ] = MyConverter @app.route('/date/<myconverter:date>' ) def show_date (date ): return f"Date: {date} " if __name__ == '__main__' : app.run()
示例:手机号码转换器
from flask import Flask,requestapp = Flask(import_name=__name__) @app.route(rule='/' ) def index (): return "<h1>hello world!</h1>" from werkzeug.routing import BaseConverterclass MobileConverter (BaseConverter ): """手机号码类型限制""" def __init__ (self,map ,*args ): super ().__init__(map ) self .regex = "1[3-9]\d{9}" app.url_map.converters['mob' ] = MobileConverter @app.route(rule='/user/<mob:mobile>' ) def user (mobile ): return mobile from werkzeug.routing import BaseConverterclass RegexConverter (BaseConverter ): """根据正则进行参数限制""" def __init__ (self,map ,*args ): super ().__init__(map ) self .regex = args[0 ] app.url_map.converters['re' ] = RegexConverter @app.route(rule='/user/<re("\w+@\w+\.\w+"):email>' ) def user2 (email ): print (app.url_map) return email class Config (): DEBUG = True app.config.from_object(Config) if __name__ == '__main__' : app.run(host="0.0.0.0" )
请求与响应 请求
什么是请求?
在 Flask 中,请求是指客户端向服务器发送的 HTTP 请求。Flask 提供了一个 Request 对象,用于处理和访问当前请求的相关信息。Request 对象包含了请求的方法、URL、头部信息、表单数据等。
常用的 Flask 请求对象的属性和方法
属性/方法
描述
method
获取请求的方法
url
获取请求的完整 URL
args
获取请求的查询参数
form
获取请求的表单数据
files
获取请求中上传的文件
headers
获取请求的头部信息
cookies
获取请求中的 Cookie 数据
get(key)
获取指定键的查询参数值
getlist(key)
获取指定键的查询参数值列表
get_json()
获取请求的 JSON 数据
get_data()
获取请求的原始数据
get_file(key)
获取指定键对应的上传文件
get_header(key)
获取指定键的头部字段值
get_cookie(key)
获取指定键的 Cookie 值
示例:获取请求各项数据
from flask import Flask,requestapp = Flask(import_name=__name__) @app.route(rule='/' ) def index (): return "<h1>hello world!</h1>" """== 获取查询字符串 ==""" @app.route(rule="/args" ,methods=["post" ,"get" ] ) def args (): print (request.args) """ 请求地址: http://127.0.0.1:5000/args?name=xiaoming&password=123&lve=swimming&lve=shopping 打印效果: ImmutableMultiDict([('name', 'xiaoming'), ('password', '123')]) ImmutableMultiDict是一个由flask封装的字典类,在字典的基础上,提供了一些其他的方法而已。 格式: ImmutableMultiDict([('键', '值'), ('键', '值')]) 字典本身不支持同名键的,ImmutableMultiDict类解决了键同名问题 操作ImmutableMultiDict,完全可以操作字典操作,同时还提供了get,getlist方法,获取指定键的1个值或多个值 """ print (request.args["name" ]) print (request.args.get("name" )) print (request.args.getlist("lve" )) print (request.args.to_dict(flat=False )) print (request.args.to_dict(flat=True )) return "ok" """== 获取请求体数据 ==""" @app.route(rule="/data" ,methods=["post" ,"put" ,"patch" ] ) def data (): """接受客户端发送过来的请求体数据,是request.json,request.form,request.files等无法接受的数据,全部会保留到这里""" print (request.data) print (request.form) print (request.json) avatar = request.files["avatar" ] print (avatar) print ( request.headers ) print ( request.headers.get("Host" ) ) print ( request.headers.get("company" ) ) print ( request.headers["company" ] ) print ( request.url) print ( request.path ) return "ok" class Config (): DEBUG = True app.config.from_object(Config) if __name__ == '__main__' : app.run(host="0.0.0.0" )
响应
什么是flask响应
在 Flask 中,响应(Response)是服务器返回给客户端的数据。Flask 提供了一个 Response 对象来创建和设置响应。 Flask 响应对象包含了响应的内容、状态码、响应头等信息。你可以通过创建一个响应对象并设置相应的属性来构建自定义的响应。
常用的 Flask 响应对象的属性和方法
属性/方法
描述
data
响应的内容
status
响应的状态码
headers
响应的头部信息
content_type
响应的内容类型
set_cookie(key, value, **kwargs)
设置响应的 Cookie
delete_cookie(key, **kwargs)
删除响应中的指定 Cookie
make_response([response])
创建一个响应对象
response
Flask 视图函数返回的默认响应对象
response.data
获取响应的内容
response.status
获取响应的状态码
response.headers
获取响应的头部信息
response.content_type
获取响应的内容类型
response.set_cookie(key, value, **kwargs)
设置响应的 Cookie
response.delete_cookie(key, **kwargs)
删除响应中的指定 Cookie
响应html数据
from flask import make_response@app.route("/" ) def index (): return make_response("<h1>hello user</h1>" )
响应JSON数据
from flask import Flask, request, jsonify@app.route("/" ) def index (): data = [ {"id" :1 ,"username" :"liulaoshi" ,"age" :18 }, {"id" :2 ,"username" :"liulaoshi" ,"age" :17 }, {"id" :3 ,"username" :"liulaoshi" ,"age" :16 }, {"id" :4 ,"username" :"liulaoshi" ,"age" :15 }, ] return jsonify(data)
重定向到百度
from flask import redirect@app.route("/user" ) def user (): return redirect("http://www.baidu.com" )
重定向到index函数
@app.route("/" ) def index (): data = [ {"id" :1 ,"username" :"liulaoshi" ,"age" :18 }, {"id" :2 ,"username" :"liulaoshi" ,"age" :17 }, {"id" :3 ,"username" :"liulaoshi" ,"age" :16 }, {"id" :4 ,"username" :"liulaoshi" ,"age" :15 }, ] return jsonify(data) @app.route("/login" ) def login (): return redirect( url_for("index" ) )
重定向到带参数的视图函数
@app.route('/user/<user_id>' ) def user_info (user_id ): return 'hello %d' % user_id @app.route('/demo4' ) def demo4 (): return redirect( url_for(endpoint="user" ,user_id=100 ) )
自定义状态码和响应头
自定义状态码:
from flask import Flask, make_responseapp = Flask(__name__) @app.route('/' ) def custom_status_code (): response = make_response('Custom status code' , 666 ) return response
使用 make_response()
函数创建了一个响应对象,并指定了自定义的状态码为 666。
自定义响应头:
from flask import Flask, make_responseapp = Flask(__name__) @app.route('/' ) def custom_response_header (): response = make_response('Custom response header' ) response.headers['X-Custom-Header' ] = 'Custom Value' return response
会话控制 会话: 客户端浏览器和服务端网站之间一次完整的交互过程。会话的开始是在用户通过浏览器第一次访问服务端网站开始,会话的结束时在用户通过关闭浏览器以后,与服务端断开。 会话控制: 就是在客户端浏览器和服务端网站之间,进行多次http请求响应之间,记录、跟踪和识别用户的信息而已。 因为 http 是一种无状态协议,浏览器请求服务器是无状态的。 无状态: 指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。 无状态原因: 浏览器与服务器是使用 socket 套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 连接,而且服务器也会在处理页面完毕之后销毁页面对象。
实现状态保持主要有两种方式:
在客户端存储信息使用Cookie,token[jwt,oauth]
在服务器端存储信息使用Session
Cookie
什么是Cookie
Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie的key/value可以由服务器端自己定义。Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用。Cookie基于域名安全,不同域名的Cookie是不能互相访问的。当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息。
设置Cookie
from flask imoprt Flask,make_response@app.route('/set_cookie' ) def set_cookie (): resp = make_response('this is to set cookie' ) resp.set_cookie('username' , 'xiaoming' , max_age=3600 ) return resp
获取Cookie
from flask import Flask,request@app.route('/get_cookie' ) def resp_cookie (): resp = request.cookies.get('username' ) return resp
Session
什么是Session
在 Flask 中,Session 是一种在客户端和服务器之间存储和共享数据的机制。它允许你在多个请求之间保持用户的状态,并在每个请求中访问和修改这些数据。 Flask 使用一个称为 Flask Session 的扩展来管理会话。该扩展提供了一个字典对象,你可以像操作字典一样操作会话数据。会话数据存储在服务器端,但在每个请求中,一个唯一的会话标识符会通过 Cookie 或 URL 参数发送给客户端,以便将会话与用户关联起来。 通过使用 Flask Session,你可以在会话中存储用户的认证状态、用户偏好设置、购物车内容等。会话数据被加密和签名,以确保数据的安全性和完整性。
常用的session方法和属性
功能/方法
描述
session
会话对象,用于访问和修改会话数据
session[key]
访问会话数据中指定键的值
session[key] = value
设置会话数据中指定键的值
session.get(key, default)
获取会话数据中指定键的值,如果键不存在则返回默认值
session.pop(key, default)
删除会话数据中指定键的值,并返回该值
session.clear()
清除会话数据,使会话变为空
session.modified
判断会话数据是否被修改过
设置Session
from flask import session@app.route('/set_session' ) def set_session (): session['username' ] = 'xiaoming' return 'ok!'
获取Session
from flask import session@app.route('/get_session' ) def get_session (): return session.get('username' )
Flask Session
Flask Session是什么
Flask-Session是Flask框架的一个扩展,用于管理和处理会话(Session)数据。会话是一种在Web应用中存储和跟踪用户状态信息的机制。Flask-Session扩展提供了在Flask应用中使用会话的功能,包括会话数据的存储、读取和修改等操作。
Flask-Session扩展的主要功能
功能
描述
存储会话数据
将会话数据存储在不同的位置,如服务器端的内存、数据库或文件系统中,以便于后续的访问和使用。
加密会话数据
支持对会话数据进行加密,确保数据的安全性和完整性,防止数据被篡改或窃取。
会话数据的访问和操作
可以方便地读取和修改会话数据,比如获取当前用户的登录状态、存储用户的个人偏好设置等。
会话过期和超时处理
支持设置会话的过期时间和超时时间,可以根据需求自定义会话的有效期,并提供相应的处理机制。
会话的持久化
可以选择将会话数据持久化到数据库或文件系统中,以保证会话数据的持久性,即使应用程序重启或用户重新访问时仍能保持会话状态。
会话的共享
支持在多个应用实例之间共享会话数据,以实现分布式环境下的会话管理和状态同步。
安装使用Flask Session
安装
pip install flask-Session
配置secket key
SECRET_KEY = "*(%#4sxcz(^(#$#8423 "
redis保存session的配置
import redisclass Config (object ): DEBUG = True SECRET_KEY = "*(%#4sxcz(^(#$#8423" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/flask_students" SQLALCHEMY_TRACK_MODIFICATIONS = True SQLALCHEMY_ECHO = True SESSION_TYPE="redis" SESSION_PERMANENT = False SESSION_USE_SIGNER = False SESSION_KEY_PREFIX = "session:" SESSION_REDIS = redis.Redis(host='127.0.0.1' , port='6379' )
使用session视图函数代码
from flask import Flaskfrom config import Configfrom flask_session import Sessionfrom flask import sessionapp = Flask(__name__,template_folder='templates' ) app.config.from_object(Config) Session(app) @app.route("/" ) def index (): return "ok" @app.route("/set_session" ) def set_session (): """设置session""" session["username" ] = "小明" return "ok" if __name__ == '__main__' : app.run()
SQLAlchemy存储session的基本配置
需要手动创建session表,在项目第一次启动的时候,使用db.create_all()来完成创建
db = SQLAlchemy(app) app.config['SESSION_TYPE' ] = 'sqlalchemy' app.config['SESSION_SQLALCHEMY' ] = db app.config['SESSION_SQLALCHEMY_TABLE' ] = 'session' app.config['SESSION_PERMANENT' ] = True app.config['SESSION_USE_SIGNER' ] = False app.config['SESSION_KEY_PREFIX' ] = 'session:' Session(app)
调整session配置
分析SQLAlachemy的构造方式可以发现,初始化并非一定要传递app应用对象到内部,事实上它提供了init_app方法给我们后续调用。而 init_app 方法是flask框架要求任何的第三方组件都要实现这个方法。
init_app方法内部就是要第三方组件开发者编写一些使用当前组建的默认配置项以及把当前组件设置成一个对象,加载到app对象内部extensions字典才能让开发者在flask框架内部配置和使用当前组件。
我们可以利用这种组件开发机制,那么把配置代码抽离出去。
配置文件
import redisfrom flask_sqlalchemy import SQLAlchemydb = SQLAlchemy() class Config (object ): DEBUG = True SECRET_KEY = "*(%#4sxcz(^(#$#8423" SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/flask_students" SQLALCHEMY_TRACK_MODIFICATIONS = True SQLALCHEMY_ECHO = True """把session保存到redis中""" SESSION_TYPE= 'sqlalchemy' SESSION_SQLALCHEMY= db SESSION_SQLALCHEMY_TABLE= 'sessions' SESSION_PERMANENT= True SESSION_USE_SIGNER= False SESSION_KEY_PREFIX= 'session:'
视图函数代码
from flask import Flaskfrom config import Config,dbfrom flask_session import Sessionfrom flask import sessionapp = Flask(__name__,template_folder='templates' ) app.config.from_object(Config) db.init_app(app) Session(app) @app.route("/" ) def index (): return "ok" @app.route("/set_session" ) def set_session (): """设置session""" session["username" ] = "小明" return "ok" if __name__ == '__main__' : print ( app.url_map ) app.run()
数据库模型 SQLAlchemy
什么是SQLALchemy
flask默认提供模型操作,但是并没有提供ORM,所以一般开发的时候我们会采用flask-SQLAlchemy模块来实现ORM操作。 SQLAlchemy是一个关系型数据库框架,它提供了高层的 ORM 和底层的原生数据库的操作。flask-sqlalchemy 是一个简化了 SQLAlchemy 操作的flask扩展。 SQLAlchemy: https://www.sqlalchemy.org/
安装 flask-sqlalchemy【清华源】
pip install flask-sqlalchemy -i https://pypi.tuna.tsinghua.edu.cn/simple
如果是mysql数据库
pip install flask-mysqldb -i https://pypi.tuna.tsinghua.edu.cn/simple
Flask支持的数据库类型
扩展包
支持的数据库
Flask-SQLAlchemy
SQLite, MySQL, PostgreSQL, Oracle 等
Flask-MongoEngine
MongoDB
Flask-PyMongo
MongoDB
Flask-Redis
Redis
Flask-CouchDB
CouchDB
Flask-SQLite
SQLite
其他原生 Python 数据库驱动程序
根据驱动程序和数据库类型而定
数据库连接设置 不同类型数据库连接字符串,参考:
数据库类型
配置示例
SQLite
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///path/to/database.db'
MySQL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://username:password@host:port/database_name'
PostgreSQL
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://username:password@host:port/database_name'
MongoDB
app.config['MONGODB_SETTINGS'] = 'db': 'database_name','host': 'mongodb://username:password@host:port/database_name'
Redis
app.config['REDIS_URL'] = 'redis://:password@host:port/0'
使用配置文件:
在 Flask 的配置文件(例如 config.py
)中添加数据库连接相关的配置项,如下所示:
SQLALCHEMY_DATABASE_URI = '数据库连接字符串' SQLALCHEMY_TRACK_MODIFICATIONS = False
在应用程序中导入配置文件,并加载配置:
from flask import Flaskfrom flask_sqlalchemy import SQLAlchemyapp = Flask(__name__) app.config.from_pyfile('config.py' ) db = SQLAlchemy(app)
直接在应用程序中设置:
在应用程序中直接设置数据库连接相关的配置项,如下所示:
from flask import Flaskfrom flask_sqlalchemy import SQLAlchemyapp = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI' ] = '数据库连接字符串' app.config['SQLALCHEMY_TRACK_MODIFICATIONS' ] = False db = SQLAlchemy(app)
SQLAlchemy字段类型
字段类型
示例
Integer
Integer
BigInteger
BigInteger
SmallInteger
SmallInteger
Float
Float
Numeric
Numeric
String
String(255)
Text
Text
Boolean
Boolean
Date
Date
Time
Time
DateTime
DateTime
Interval
Interval
Enum
Enum('option1', 'option2')
JSON
JSON
PickleType
PickleType
LargeBinary
LargeBinary
ForeignKey
ForeignKey('other_table.id')
Relationship
relationship('OtherModel')
SQLAlchemy字段约束条件
约束条件
示例
PrimaryKey
primary_key=True
Unique
unique=True
CheckConstraint
CheckConstraint('column_name >= 0')
ForeignKeyConstraint
ForeignKeyConstraint(['column1', 'column2'], ['other_table.column1', 'other_table.column2'])
Index
Index('index_name', 'column')
UniqueConstraint
UniqueConstraint('column1', 'column2', name='uq_column1_column2')
Default
default='default_value'
Nullable
nullable=False
AutoIncrement
autoincrement=True
OnDelete
ondelete='CASCADE'
OnUpdate
onupdate='CASCADE'
ForeignKey
ForeignKey('other_table.id', ondelete='CASCADE', onupdate='CASCADE')
定义模型类 from flask import Flaskapp = Flask(import_name=__name__) class Config (): DEBUG = True SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8" SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ECHO = True app.config.from_object(Config) from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy() db.init_app(app) class Student (db.Model): __tablename__ = "tb_student" id = db.Column(db.Integer, primary_key=True , comment="主键" ) name = db.Column(db.String(64 ), index=True , comment="姓名" ) sex = db.Column(db.Boolean, default=True , comment="性别" ) age = db.Column(db.SmallInteger, nullable=True , comment="年龄" ) email = db.Column(db.String(128 ), unique=True , comment="邮箱地址" ) money = db.Column(db.Numeric(8 ,2 ), default=0 , comment="钱包" ) def __repr__ (self ): return 'Student:%s' % self .name class Teacher (db.Model): __tablename__ = 'tb_teacher' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) option = db.Column(db.Enum("讲师" ,"助教" ,"班主任" ), default="讲师" ) def __repr__ (self ): return 'Teacher:%s' % self .name class Course (db.Model): __tablename__ = 'tb_course' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) price = db.Column(db.Numeric(6 ,2 )) def __repr__ (self ): return 'Course:%s' % self .name @app.route(rule='/' ) def index (): return "ok" if __name__ == '__main__' : app.run(debug=True )
数据库表操作 创建表
删除表
示例代码:
from flask import Flaskapp = Flask(import_name=__name__) class Config (): DEBUG = True SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/students?charset=utf8" SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ECHO = True app.config.from_object(Config) from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy() db.init_app(app) class Student (db.Model): __tablename__ = "tb_student" id = db.Column(db.Integer, primary_key=True , comment="主键" ) name = db.Column(db.String(64 ), index=True , comment="姓名" ) sex = db.Column(db.Boolean, default=True , comment="性别" ) age = db.Column(db.SmallInteger, nullable=True , comment="年龄" ) email = db.Column(db.String(128 ), unique=True , comment="邮箱地址" ) money = db.Column(db.Numeric(8 ,2 ), default=0 , comment="钱包" ) def __repr__ (self ): return 'Student:%s' % self .name class Teacher (db.Model): __tablename__ = 'tb_teacher' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) option = db.Column(db.Enum("讲师" ,"助教" ,"班主任" ), default="讲师" ) def __repr__ (self ): return 'Teacher:%s' % self .name class Course (db.Model): __tablename__ = 'tb_course' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) price = db.Column(db.Numeric(6 ,2 )) def __repr__ (self ): return 'Course:%s' % self .name @app.route(rule='/' ) def index (): return "ok" if __name__ == '__main__' : with app.app_context(): db.create_all() app.run(debug=True )
数据操作 基本查询 查询数据
操作
示例
查询所有数据
Model.query.all()
根据主键查询单条数据
Model.query.get(id)
根据条件查询数据
Model.query.filter_by(column=value).all()
使用复杂条件查询数据
Model.query.filter(condition).all()
查询第一条数据
Model.query.first()
查询单个结果(只返回第一个结果)
Model.query.filter_by(column=value).first()
插入数据
操作
示例
创建一个实例对象
new_data = Model(column1=value1, column2=value2, ...)
将实例对象添加到会话中
db.session.add(new_data)
提交会话以保存数据
db.session.commit()
更新数据
操作
示例
根据条件查询要更新的数据
data = Model.query.filter_by(condition).first()
更新数据的属性值
data.column = new_value
提交会话以保存更新
db.session.commit()
删除数据
操作
示例
根据条件查询要删除的数据
data = Model.query.filter_by(condition).first()
将数据从会话中删除
db.session.delete(data)
提交会话以保存删除
db.session.commit()
常用的SQLAlchemy查询过滤器
过滤器
描述
filter()
根据指定条件筛选结果,可以使用多个条件组合,条件之间是逻辑与关系。
filter_by()
根据指定的关键字参数筛选结果,适用于简单的等值条件筛选。
limit()
限制查询结果的数量,指定返回的记录数。
offset()
设置查询结果的偏移量,指定要跳过的记录数。
order_by()
按照指定的属性排序查询结果,可以使用多个属性和排序方式。
group_by()
根据指定的属性对查询结果进行分组。
distinct()
去除查询结果中的重复记录。
join()
进行表之间的连接查询,可以通过指定关联条件实现不同表之间的联接。
outerjoin()
进行外连接查询,包括左外连接和右外连接。
having()
对分组后的结果进行筛选,类似于 WHERE
条件但用于分组后的结果。
exists()
检查是否存在符合指定条件的记录。
any()
检查指定关联对象集合中是否至少存在一个符合条件的对象。
all()
检查指定关联对象集合中是否全部符合条件。
scalar()
返回查询结果的第一列值。
first()
返回查询结果的第一条记录。
one()
返回查询结果的唯一一条记录,如果结果不唯一则抛出异常。
count()
返回查询结果的记录数。
sum()
对指定属性的值进行求和计算。
avg()
对指定属性的值进行平均计算。
max()
返回指定属性的最大值。
min()
返回指定属性的最小值。
常用的SQLAlchemy查询结果的方法
方法
描述
all()
获取查询结果的所有记录,返回一个包含所有记录的列表。
first()
获取查询结果的第一条记录,返回一个单个记录对象或 None
。
one()
获取查询结果的唯一一条记录,如果结果不唯一则抛出异常。
scalar()
返回查询结果的第一列值。
get()
根据主键值获取查询结果的记录,返回一个单个记录对象或 None
。
count()
返回查询结果的记录数。
limit(n)
限制查询结果的数量,指定返回的记录数为 n
。
offset(n)
设置查询结果的偏移量,跳过前 n
条记录。
order_by(column)
按照指定的属性对查询结果进行排序。
distinct()
去除查询结果中的重复记录。
group_by(column)
根据指定的属性对查询结果进行分组。
having(condition)
对分组后的结果进行筛选。
join(table)
进行表之间的连接查询。
outerjoin(table)
进行外连接查询。
delete()
删除查询结果的记录。
update(values)
更新查询结果的记录属性值。
Filter模糊查询
ret = Student.query.filter (Student.name.endswith("g" )).all () ret = Student.query.filter (Student.name.contains("u" )).all () ret = Student.query.filter (Student.name.startswith("w" )).all ()
逻辑条件查询 逻辑非,返回名字不等于wang的所有数据
""" 查询出名字不等于liu的所有男学生 """ ret = Student.query.filter (Student.name!="liu" ,Student.sex==True ).all ()
not_ 取反
from sqlalchemy import not_""" 查询出名字不等于liu的所有男学生 """ ret = Student.query.filter (not_(Student.name=="liu" ),Student.sex==True ).all ()
逻辑与,需要导入and,返回and()条件满足的所有数据
from sqlalchemy import and_""" and_ 且,与 查询出年龄在18-21之间的女生 """ ret1 = Student.query.filter (and_(Student.age>=18 ,Student.age<=21 ,Student.sex==False )).all () ret2 = Student.query.filter (Student.age>=18 ,Student.age<=21 ,Student.sex==False ).all () print (ret1)print (ret2)
逻辑或,需要导入or_
from sqlalchemy import or_""" 查询出大于21,小于20的男生 """ ret = Student.query.filter (or_(Student.age>21 ,Student.age<20 ),Student.sex==True ).all () """ 查询大于21的男生和小于20的女生 """ ret1 = Student.query.filter (or_(and_(Student.age>21 ,Student.sex==True ),and_(Student.age<20 ,Student.sex==False ))).all () print (ret1)
in_范围查询
"""查询id为2, 3, 5, 7, 8这几个学生信息""" student_list = Student.query.filter (Student.id .in_([2 , 3 , 5 , 7 , 8 ])).all () print (student_list)
order_by 排序
ret = Student.query.order_by(Student.age.desc()).all () ret = Student.query.order_by(Student.age.desc(),Student.id .desc()).all ()
count统计
from sqlalchemy import and_ret = Student.query.filter ( Student.age>=19 , Student.sex==True ).count()
对结果进行偏移量和数量的限制
ret1 = Student.query.order_by(Student.age.desc()).limit(3 ).all () ret2 = Student.query.order_by(Student.age.desc(),Student.id .desc()).offset(4 ).limit(4 ).all () print (ret1,ret2)ret = Student.query.filter (Student.name.startswith("li" ),Student.email.startswith("li" )).all () Student.query.filter (or_(Student.age==18 ,Student.email.endswith("163.com" ))).all () student_list = Student.query.filter (Student.id .in_([1 , 3 , 5 , 7 , 9 ])).all () print (student_list)ret = Student.query.filter_by(sex=True ).count() ret = Student.query.filter_by(sex=False ).count()
分页器使用
from flask import Flask,request,jsonify,render_templatefrom config import Configfrom models import db,Student,Course,Teacherapp = Flask(import_name=__name__,template_folder='templates' ) app.config.from_object(Config) db.init_app(app) """分页器使用""" @app.route(rule="/list" ) def list (): pagination = Student.query.paginate(per_page=3 ) return render_template("list.html" ,pagination=pagination) if __name__ == '__main__' : app.run(debug=True )
分组查询 分组都会结合聚合函数来一起使用。SQLAlchemy中所有的聚合函数都在func模块中声明的
聚合函数
描述
func.count()
计算指定列的非空记录数量。
func.sum()
计算指定列的数值总和。
func.avg()
计算指定列的平均值。
func.min()
找出指定列的最小值。
func.max()
找出指定列的最大值。
func.distinct()
返回指定列的不重复值。
func.concat()
连接多个字符串列的值。
func.lower()
将指定列的值转换为小写。
func.upper()
将指定列的值转换为大写。
func.trim()
去除指定列值的前导和尾随空格。
func.coalesce()
返回第一个非空值。
func.group_concat()
将指定列的值连接为一个字符串,多个值之间使用指定的分隔符。仅适用于某些数据库(如 MySQL)特定的聚合函数。
示例代码
from sqlalchemy import funcret = db.session.query(Student.age,func.count(Student.id )).group_by(Student.age).having(Student.age>19 ).all () ret = db.session.query(Student.sex,func.min (Student.age)).group_by(Student.sex).all ()
关联查询
常用的SQLAlchemy关系选项
关系选项
描述
backref
在另一个模型中自动创建反向引用关系。
primaryjoin
指定两个模型之间的主键关系。
secondary
指定多对多关系中的中间表。
secondaryjoin
指定多对多关系中的联接条件。
uselist
定义关系是否返回单个对象或对象列表。
lazy
定义关系的加载方式。
cascade
定义关系的级联操作。
single_parent
定义关系中是否允许一个对象只有一个父对象。
order_by
指定关系中对象的排序方式。
back_populates
在另一个模型中手动设置反向引用关系。
post_update
定义关系中对象的更新行为。
remote_side
指定关系中另一侧的属性或列。
passive_deletes
定义关系中的被动删除行为。
passive_updates
定义关系中的被动更新行为。
foreign_keys
定义关系中的外键约束。
ondelete
定义关系中的删除行为。
onupdate
定义关系中的更新行为。
constraint
定义关系中的约束条件。
inherit_condition
定义关系中的继承条件。
viewonly
定义关系是否只读。
collection_class
指定关系的集合类。
order_by
定义关系中对象的排序方式。
一对一关联查询
models.py代码
from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy() class Student (db.Model): __tablename__ = "tb_student" id = db.Column(db.Integer, primary_key=True , comment="主键" ) name = db.Column(db.String(64 ), index=True , comment="姓名" ) sex = db.Column(db.Boolean, default=True , comment="性别" ) age = db.Column(db.SmallInteger, nullable=True , comment="年龄" ) email = db.Column(db.String(128 ), unique=True , comment="邮箱地址" ) money = db.Column(db.Numeric(8 ,2 ), default=0 , comment="钱包" ) info = db.relationship("StudentInfo" ,uselist=False ,backref="own" ) def __repr__ (self ): return 'Student:%s' % self .name class StudentInfo (db.Model): __tablename__ = "tb_student_info" id = db.Column(db.Integer, primary_key=True , comment="主键" ) address = db.Column(db.String(299 ), comment="住址" ) edu = db.Column(db.Enum("高中以下" ,"大专高技" ,"本科" ,"硕士" ,"博士以上" )) uid = db.Column(db.Integer, db.ForeignKey(Student.id ),comment="外键" ) class Teacher (db.Model): __tablename__ = 'tb_teacher' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) option = db.Column(db.Enum("讲师" ,"助教" ,"班主任" ), default="讲师" ) def __repr__ (self ): return 'Teacher:%s' % self .name class Course (db.Model): __tablename__ = 'tb_course' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) price = db.Column(db.Numeric(6 ,2 )) def __repr__ (self ): return 'Course:%s' % self .name
视图函数run.py代码
from flask import Flask,request,jsonify,render_templatefrom config import Configfrom models2 import db,Student,Course,Teacher,StudentInfoapp = Flask(import_name=__name__,template_folder='templates' ) app.config.from_object(Config) db.init_app(app) @app.route(rule='/' ) def index (): """1对1模型操作""" return "ok" if __name__ == '__main__' : app.run(debug=True )
一对多关联查询
modes.py代码
from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy() class Student (db.Model): __tablename__ = "tb_student" id = db.Column(db.Integer, primary_key=True , comment="主键" ) name = db.Column(db.String(64 ), index=True , comment="姓名" ) sex = db.Column(db.Boolean, default=True , comment="性别" ) age = db.Column(db.SmallInteger, nullable=True , comment="年龄" ) email = db.Column(db.String(128 ), unique=True , comment="邮箱地址" ) money = db.Column(db.Numeric(8 ,2 ), default=0 , comment="钱包" ) info = db.relationship("StudentInfo" ,uselist=False ,backref="own" ) def __repr__ (self ): return 'Student:%s' % self .name class StudentInfo (db.Model): __tablename__ = "tb_student_info" id = db.Column(db.Integer, primary_key=True , comment="主键" ) address = db.Column(db.String(299 ), comment="住址" ) edu = db.Column(db.Enum("高中以下" ,"大专高技" ,"本科" ,"硕士" ,"博士以上" )) uid = db.Column(db.Integer, db.ForeignKey(Student.id ),comment="外键" ) class Teacher (db.Model): __tablename__ = 'tb_teacher' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) option = db.Column(db.Enum("讲师" ,"助教" ,"班主任" ), default="讲师" ) course = db.relationship("Course" , uselist=True , backref="teacher" ,lazy='dynamic' ) def __repr__ (self ): return 'Teacher:%s' % self .name class Course (db.Model): __tablename__ = 'tb_course' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) price = db.Column(db.Numeric(6 ,2 )) teacher_id = db.Column(db.Integer, db.ForeignKey(Teacher.id )) def __repr__ (self ): return 'Course:%s' % self .name
run.py视图函数代码
from flask import Flask,request,jsonify,render_templatefrom config import Configfrom models2 import db,Student,Course,Teacher,StudentInfoapp = Flask(import_name=__name__,template_folder='templates' ) app.config.from_object(Config) db.init_app(app) @app.route(rule='/more' ) def more (): """一对多/多对一模型操作""" return "ok" if __name__ == '__main__' : app.run(debug=True )
多对多关联查询
modes.py模型代码
from flask import Flask,render_templateapp = Flask(__name__) class Config (object ): DEBUG = True SECRET_KEY = "dsad32DASSLD*13%^32" SQLALCHEMY_DATABASE_URI="mysql://root:123@127.0.0.1:3306/students?charset=utf8mb4" SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_ECHO = True app.config.from_object(Config) from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy() db.init_app(app) class Student (db.Model): """学生信息""" __tablename__ = "tb_student" id = db.Column(db.Integer, primary_key=True , comment="ID" ) name = db.Column(db.String(64 ), index=True , comment="姓名" ) sex = db.Column(db.Boolean, default=True , comment="性别" ) age = db.Column(db.SmallInteger, nullable=True , comment="年龄" ) email = db.Column(db.String(128 ), unique=True , comment="邮箱地址" ) money = db.Column(db.Numeric(8 ,2 ), default=0 , comment="钱包" ) info = db.relationship("StudentInfo" , uselist=False , backref="student" ,lazy="subquery" ) course_list = db.relationship("Achievement" , backref="student" , lazy=True ) def __repr__ (self ): return "%s" % self .name class StudentInfo (db.Model): """学生信息附加表""" __tablename__ = "tb_student_info" id = db.Column(db.Integer, primary_key=True , comment="ID" ) sid = db.Column(db.Integer, db.ForeignKey("tb_student.id" ),comment="学生ID" ) address = db.Column(db.String(250 ), nullable=True , comment="家庭地址" ) mobile = db.Column(db.String(15 ), nullable=True , comment="紧急联系人" ) def __repr__ (self ): return "%s" % self .student.name class Teacher (db.Model): __tablename__ = 'tb_teacher' id = db.Column(db.Integer, primary_key=True , comment="ID" ) name = db.Column(db.String(64 ), comment="姓名" ) option = db.Column(db.Enum("讲师" ,"助教" ,"班主任" ), default="讲师" , comment="身份" ) course_list = db.relationship("Course" , backref="teacher" ,lazy=True ) def __repr__ (self ): return '%s[%s]' % (self .option,self .name) class Course (db.Model): __tablename__ = 'tb_course' id = db.Column(db.Integer, primary_key=True ) teahcer_id = db.Column(db.Integer, db.ForeignKey(Teacher.id ), comment="老师ID" ) name = db.Column(db.String(64 ), unique=True ) price = db.Column(db.Numeric(6 ,2 )) student_list = db.relationship("Achievement" , backref="course" ,lazy=True ) def __repr__ (self ): return '%s' % self .name class Achievement (db.Model): """学生和课程之间的成绩关系模型""" __tablename__ = 'tb_achievement' id = db.Column(db.Integer, primary_key=True ) student_id = db.Column(db.Integer,db.ForeignKey(Student.id ), comment="学生" ) course_id = db.Column(db.Integer,db.ForeignKey(Course.id ), comment="课程" ) def __repr__ (self ): return '%s-%s' % (self .student,self .course) @app.route("/" ) def index (): """ 多对多 """ """1. 添加主键模型,给外键模型添加数据""" """2. 查询操作""" student = Student.query.filter (Student.name=="xiaoming" ).first() print (student.course_list) for achievement in student.course_list: print (achievement.course.name) return "ok" if __name__ == '__main__' : app.run(debug=True )
数据库迁移
在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库。最直接的方式就是删除旧表,但这样会丢失数据。
更好的解决办法是使用数据库迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中。
在Flask中可以使用Flask-Migrate扩展,来实现数据迁移。并且集成到Flask-Script中,所有操作通过命令就能完成。
为了导出数据库迁移命令,Flask-Migrate提供了一个MigrateCommand类,可以附加到flask-script的manager对象上。
首先要在虚拟环境中安装Flask-Migrate
pip install flask-migrate
示例代码:
from flask import Flaskfrom config import Configfrom flask_migrate import Migrate,MigrateCommandfrom flask_script import Manager,Commandapp = Flask(__name__,template_folder='templates' ) app.config.from_object(Config) manage = Manager(app) """模型的创建""" from flask_sqlalchemy import SQLAlchemydb = SQLAlchemy(app) migrate = Migrate(app,db) manage.add_command('db' ,MigrateCommand) achieve = db.Table('tb_achievement' , db.Column('student_id' , db.Integer, db.ForeignKey('tb_student.id' )), db.Column('course_id' , db.Integer, db.ForeignKey('tb_course.id' )) ) class Course (db.Model): __tablename__ = 'tb_course' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) price = db.Column(db.Numeric(6 ,2 )) teacher_id = db.Column(db.Integer, db.ForeignKey('tb_teacher.id' )) students = db.relationship('Student' , secondary=achieve, backref='courses' , lazy='subquery' ) def __repr__ (self ): return 'Course:%s' % self .name class Student (db.Model): __tablename__ = 'tb_student' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) email = db.Column(db.String(64 ),unique=True ) age = db.Column(db.SmallInteger,nullable=False ) sex = db.Column(db.Boolean,default=1 ) def __repr__ (self ): return 'Student:%s' % self .name class Teacher (db.Model): __tablename__ = 'tb_teacher' id = db.Column(db.Integer, primary_key=True ) name = db.Column(db.String(64 ), unique=True ) courses = db.relationship('Course' , backref='teacher' , lazy='subquery' ) def __repr__ (self ): return 'Teacher:%s' % self .name @app.route("/" ) def index (): return "ok" if __name__ == '__main__' : manage.run()
创建迁移版本仓库
创建迁移版本
python main.py db migrate -m 'initial migration'
升级版本库的版本
python main.py db upgrade
降级版本库的版本
python main.py db downgrade
可以根据history命令找到版本号,然后传给downgrade命令:
python manage.py db history 输出格式:<base> -> 版本号 (head ), initial migration
回滚到指定版本
python manage.py db downgrade python manage.py db downgrade 版本号
数据库迁移的步骤:
1. 初始化数据迁移的目录 python manage.py db init 2. 数据库的数据迁移版本初始化 python manage.py db migrate -m 'initial migration' 3. 升级版本[创建表/创建字段/修改字段] python manage.py db upgrade 4. 降级版本[删除表/删除字段/恢复字段] python manage.py db downgrade
蓝图 Blueprint
什么是蓝图 Blueprint
在Flask框架中,蓝图(Blueprint)是一种组织和管理路由、视图函数和静态文件等的机制。它可以将应用程序的不同功能模块划分为独立的蓝图,从而使代码结构更清晰、模块化,并且便于维护和扩展。
蓝图 Blueprint主要功能
路由和视图函数的组织:通过蓝图,可以将相关联的路由和视图函数进行组织和管理。每个蓝图可以定义自己的路由规则和处理函数,使代码结构更清晰和可读。
URL前缀和子域名:蓝图可以定义URL前缀,用于对蓝图下的路由进行命名空间的管理。同时,蓝图还支持通过子域名来进行路由的分组和管理。
静态文件的处理:蓝图可以定义自己的静态文件目录,使静态文件的访问路径与蓝图关联起来。这样可以方便地组织和管理静态文件,避免冲突和混淆。
错误处理和异常处理:蓝图可以定义自己的错误处理和异常处理函数,用于处理在蓝图范围内发生的错误和异常情况。这样可以提供更灵活和定制化的错误处理机制。
中间件的使用:蓝图可以应用中间件,对请求和响应进行预处理和后处理。中间件可以用于认证、授权、日志记录等功能,增强蓝图的功能和灵活性。
蓝图使用步骤
使用蓝图可以分为四个步骤
创建一个蓝图的包,例如users,并在__init__.py文件中创建蓝图对象
users=Blueprint('users' ,__name__)
在这个蓝图目录下, 创建views.py文件,保存当前蓝图使用的视图函数
@admin.route('/' ) def home (): return 'user.home'
在users/init.py中引入views.py中所有的视图函数
from flask import Blueprintusers=Blueprint('users' ,__name__) from .views import *
在主应用main.py文件中的app对象上注册这个users蓝图对象
from users import usersapp.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在使用时,如果要生成一个蓝图里面的视图对应的路由地址,则需要声明当前蓝图名称+视图名称
注册蓝图中的静态文件的相关路由
和应用对象不同,蓝图对象创建时不会默认注册静态目录的路由。需要我们在 创建时指定 static_folder 参数。示例将蓝图所在目录下的static_users目录设置为静态目录
user_blu = Blueprint("users" ,__name__,static_folder='static_users' ) from users import user_bluapp.register_blueprint(user_blu,url_prefix='/users' )
现在就可以使用/admin/static_admin/ 访问static_admin目录下的静态文件了 定制静态目录URL规则 :可以在创建蓝图对象时使用 static_url_path 来改变静态目录的路由。示例将为 static_admin 文件夹的路由设置为 /lib
admin = Blueprint("admin" ,__name__,static_folder='static_admin' ,static_url_path='/lib' ) app.register_blueprint(admin,url_prefix='/admin' )
设置蓝图中模版的目录
蓝图对象默认的模板目录为系统的模版目录,可以在创建蓝图对象时使用 template_folder 关键字参数设置模板目录。创建蓝图中的模板目录template_users :
admin = Blueprint('admin' ,__name__,template_folder='templates_users' )