Flask笔记
简介:这是知了传音的Flaskb站公开课笔记
Flask项目:https://github.com/pallets/flask
教程:https://www.bilibili.com/video/BV17r4y1y7jJ
背景
简介:Flask
是一个基于Python
的web
开发框架,它以灵活、“微”框架著称。Flask
的出现也是一个偶然机会,在2010年4月1日愚人节这天,作者Armin Ronacher
开了个玩笑,在网上发表了一篇关于“下一代 Python微框架”的文章,众开发者信以为真,并期待他能真正把文章中的想法实现出来。在5天后,Armin Ronacher
真的发布了一个“微”框架,他就是Flask
。
Flask
虽然是作者在愚人节开的一个玩笑,但是框架设计却非常优秀,并且深受开发者喜爱,截止 2021年6月,在Github
上的Star
数已经超过56k,仅次于2005年就发布的Django
的58k stars
数,相信在不久的将来,Flask
的Star
数一定会赶超Django
!
Flask
以“微”框架著称,本身不具备太多的功能,但是通过丰富的第三方插件,可以轻松应对现实开发中复杂的需求,并且有大量的企业在使用Flask
构建自己的产品。国内比较出名的有比如豆瓣、果壳网,国外的有Reddit
、Netflix
等,其稳定性和应对复杂业务需求的能力已经被大量企业所验证。因此读者无需担心Flask
无法适应企业需求,放心大胆的去学好Flask,能够让你的工作如虎添翼!
环境搭建
简介:使用pycharm开发,使用python3.9+的环境即可,flask使用2.0以上的版本。这里使用anaconda搭建:
# 新建conda环境
conda create -n flask python=3.9 -y
# 安装flask
conda activate flask
pip install flask
flask基本配置
注意:使用pycharm创建项目时,只建议用专业版进行学习,社区版的配置方案太少,配置环境解决方案少,出了问题很难解决。
新建flask项目
在pycharm中选择flask项目创建即可
项目构建好后,基本代码的介绍:
# 导包
from flask import Flask
# 使用Flask类创建一个app对象
# __name__:代表当前app.py这个模块
# 1.对以后出现的bug,可以帮助我们快速定位
# 2.对于寻找模板文件,有一个相对路径
app = Flask(__name__)
# 创建一个路由和视图函数的映射
# 访问百度时,https://www.baidu,com,就会访问根路径
# 在网站开发中叫根路由
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
设置debug模式
简介:使用编辑配置编辑,选择debug模式即可。
作用:
- 可以无需重启服务器,使用
ctrl+s
即可完成修改。 - 开发的时候出现bug,可以在浏览器看到输出信息
修改host&端口
修改host:可以修改为0.0.0.0即可让局域网电脑访问服务器
修改port:可以让flask跑在其他端口,防止端口冲突
url与视图映射
简介:url后的path
是通过route
组件控制的,path
是指域名后的路径,例如:
# 导包
from flask import Flask, request
# 使用Flask类创建一个app对象
# __name__:代表当前app.py这个模块
# 1.对以后出现的bug,可以帮助我们快速定位
# 2.对于寻找模板文件,有一个相对路径
app = Flask(__name__)
# 创建一个路由和视图函数的映射
# 访问百度时,https://www.baidu,com,就会访问根路径
# 在网站开发中叫根路由
@app.route('/')
def hello_world():
return 'Hello World!'
@app.route('/profile')
def profile():
return '我是个人中心'
@app.route('/blog/list')
def blog_list():
return "我是博客列表"
@app.route('/blog/<blog_id>')
def blog_detail(blog_id):
return "您访问的博客是:%s" % blog_id
# 查询字符串的方式传参
# 定义一个get请求
@app.route('/book/list')
def book_list():
# arguments:参数
# request.args:类字典类型
page = request.args.get("page", default=1, type=int)
return f"您获取的是第{page}的图书列表!"
if __name__ == '__main__':
app.run(debug=True)
get定义下列数据即可跳转相应页面:
jinja2模板
简介:jinja2库主要负责渲染html,利用后端渲染前端的静态页面
html传参
简介:使用jinja2将参数传递到html页面中
方法:在html使用{{ }}
对需要传递的地方进行标注
html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>博客详情</title>
</head>
<body>
<h1>您访问的博客详情是:{{ blog_id }}</h1>
</body>
</html>
python代码:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello_world():
return render_template('index.html')
@app.route('/blog/<blog_id>')
def blog_details(blog_id):
return render_template('blog_detail.html', blog_id=blog_id)
if __name__ == '__main__':
app.run(debug=True)
这里直接把get
获得的blog_id
返回到前端页面
传类和字典
简介:定义一个用户信息并返回前端
html代码:这里统一使用xxx.xxx
返回信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<p>{{ user.username }} / {{ user.password }}</p>
<p>{{ person.username }} / {{ person.email }}</p>
</body>
</html>
python代码:
# 使用类定义用户信息
class User:
def __init__(self, username, password):
self.username = username
self.password = password
# 使用字典定义用户信息
person={
"username":"张三",
"email":"zhangsan@qq.com"
}
@app.route('/')
def hello_world():
user = User(username="admin", password="123")
return render_template('index.html', user=user,person=person)
过滤器
简介:可以将参数处理的函数。
html代码:
<p>{{ user.username }} / {{ user.username|length }}</p>
jinja2
里有很多过滤器,这里使用length
过滤器来处理username
函数,作用是计算user.username
的字符长度
自定义过滤器
简介:如果jinja2的过滤器无法满足需求,可以自定义过滤器,这里定义一个整理时间格式的过滤器
html代码:这里使用自定义过滤器dformat
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>过滤器使用</title>
</head>
<body>
<p>{{ user.username }} / {{ user.username|length }}</p>
<p>{{ mytime|dformat }}</p>
</body>
</html>
python代码:导入datetime
,编写dformat
方法,添加至过滤器
改动部分:
from datetime import datetime
# 自定义过滤器
# 先定义函数方法
def datetime_format(value, format='%Y-%m-%d %H:%M:%S'):
return value.strftime(format)
# 导入函数,并重命名为datetime
app.add_template_filter(datetime_format,"dformat")
@app.route('/filter')
def filter_demo():
user = User(username="admin", password="123")
mytime = datetime.now()
return render_template('filter.html', user=user,mytime=mytime)
完整代码:
# 导包
from flask import Flask, render_template
from datetime import datetime
app = Flask(__name__)
# 使用类定义用户信息
class User:
def __init__(self, username, password):
self.username = username
self.password = password
# 使用字典定义用户信息
person={
"username":"张三",
"email":"zhangsan@qq.com"
}
# 自定义过滤器
# 先定义函数方法
def datetime_format(value, format='%Y-%m-%d %H:%M:%S'):
return value.strftime(format)
# 导入函数,并重命名为datetime
app.add_template_filter(datetime_format,"dformat")
@app.route('/')
def hello_world():
user = User(username="admin", password="123")
return render_template('index.html', user=user,person=person)
@app.route('/blog/<blog_id>')
def blog_details(blog_id):
return render_template('blog_detail.html', blog_id=blog_id)
@app.route('/filter')
def filter_demo():
user = User(username="admin", password="123")
mytime = datetime.now()
return render_template('filter.html', user=user,mytime=mytime)
if __name__ == '__main__':
app.run(debug=True)
效果:
if,for控制
简介:if,for两个判断语句可以判断参数条件,并对相应的内容渲染
这里编写一个if
判断数值样例和for
循环渲染
html代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% if int!=9 %}
<p>不是琪露诺</p>
{% else %}
<p>是⑨</p>
{% endif %}
{% for role in roles %}
<p>名称:{{ role.name }},工作:{{ role.work }}</p>
{% endfor %}
</body>
</html>
python代码:
@app.route('/control')
def control_demo():
int = 10
roles = [{
"name": "灵梦",
"work": "神社巫女"
},{
"name": "魔理沙",
"work": "学习魔法"
}]
return render_template('control.html', int=int, roles=roles)
效果:
模板继承
简介:有很多页面有顶部导航条和底部栏,我们不能每个页面都写入这些元素,这时可以使用模板继承来将这些元素继承:
html代码:由base,child1,child2组成
base:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<ul>
<li><a href="#">首页</a></li>
<li><a href="#">新闻</a></li>
</ul>
我是父模板
{% block body %}
{% endblock %}
<footer>这是底部的标签</footer>
</body>
</html>
child1:
{% extends "base.html" %}
{% block title %}
我是子模版的标题
{% endblock %}
{% block body %}
我是子模板的body
{% endblock %}
chlid2:
{% extends "base.html" %}
{% block title %}
我是child2
{% endblock %}
{% block body %}
我是child2
{% endblock %}
python代码:
@app.route('/child1')
def child1():
return render_template("child1.html")
@app.route('/child2')
def child2():
return render_template("child2.html")
效果:
加载静态资源
简介:可以通过url_for
的方法来引用静态文件。
对接mysql
简介:mysql是oricle的一个数据库产品,社区版是开源免费的,这里介绍oricle的对接介绍。
下载:https://dev.mysql.com/downloads/installer/
安装mysql
简介:原视频的教程使用了developer default
选项,但是现在的8.0.36版本没有这个选项,需要观看另外两个教程进行安装
教程:
https://blog.csdn.net/2201_75609002/article/details/136404667
https://www.bilibili.com/video/BV12q4y1477i
按照上述教程对flask教程安装完成即可
安装连接sql环境
简介:连接mysql的驱动有很多,这里使用pymysql进行演示,安装pymysql:
pip install pymysql
操作数据库需要使用ORM方式,这里使用flask-sqlalchemy
pip install flask-sqlalchemy
创建数据库
简介:操作数据库可以使用Navicat,在网上找破解版即可,这里涉及版权问题,不过多介绍了
操作:文件中选择新建MySQL连接
填写连接名和密码,连接名随便填,填写完成后点击确定:
连接完成后新建数据库,右键连接名,选择新建数据库:
数据库填写下列信息,点击确定完成创建:
编写程序连接mysql
简介:创建好环境后,运行下列代码查看是否连接成功,如成功则返回(1,)
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
app = Flask(__name__)
# MySQL所在的主机名
HOSTNAME = "127.0.0.1"
# MySQL所在的端口号
PORT = 3306
# 连接MySQL的用户名
USERNAME = "root"
# 连接MySQL的密码
PASSWORD = "root"
# MySQL上创建的数据库名称
DATABASE = "database_learn"
app.config["SQLALCHEMY_DATABASE_URI"] = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"
# 在app.config中设置好连接数据库的信息
# 使用SQLAlchemy(app)创建一个db对象
# SQLAlchemy会自动读取app.config中连接数据库的信息
db = SQLAlchemy(app)
# 测试是否连接成功代码
with app.app_context():
with db.engine.connect() as conn:
rs = conn.execute(text("select 1"))
print(rs.fetchone()) # (1,)
@app.route('/')
def hello_world(): # put application's code here
return 'Hello World!'
if __name__ == '__main__':
app.run()
运行结果如下:
创建ORM模型
简介:创建ORM模型的目的是为了方便更换数据库,使所有数据库操作都有一致的命令来操作
使用python创建一个orm模型并导入数据库:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
app = Flask(__name__)
# MySQL所在的主机名
HOSTNAME = "127.0.0.1"
# MySQL所在的端口号
PORT = 3306
# 连接MySQL的用户名
USERNAME = "root"
# 连接MySQL的密码
PASSWORD = "root"
# MySQL上创建的数据库名称
DATABASE = "database_learn"
app.config["SQLALCHEMY_DATABASE_URI"] = (f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:"
f"{PORT}/{DATABASE}?charset=utf8mb4")
# 在app.config中设置好连接数据库的信息
# 使用SQLAlchemy(app)创建一个db对象
# SQLAlchemy会自动读取app.config中连接数据库的信息
db = SQLAlchemy(app)
# 测试是否连接成功代码
# with app.app_context():
# with db.engine.connect() as conn:
# rs = conn.execute(text("select 1"))
# print(rs.fetchone()) # (1,)
class User(db.Model):
__tablename__ = "user"
# primary_key=True 设置主键 autoincrement=True 设置自动增加
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
# db.String指定varchar类型(变动char类型)
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100), nullable=False)
# user = User(username="张三", password="123456")
# 相当于这条语句sql: insert user(username, password) values('张三', '123456')
with app.app_context():
db.create_all()
@app.route('/')
def hello_world(): # put application's code here
return 'Hello World!'
if __name__ == '__main__':
app.run()
运行后可以在navicat中查看,右键选择设计表,可以看见我们刚才创建的表结构:
表结构如下:
对mysql进行CRUD操作
简介:CROD指的是增删改查:create,read,update,delete。这里所有的操作都要先对db.session进行修改,通过db.session同步到数据库
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
app = Flask(__name__)
# MySQL所在的主机名
HOSTNAME = "127.0.0.1"
# MySQL所在的端口号
PORT = 3306
# 连接MySQL的用户名
USERNAME = "root"
# 连接MySQL的密码
PASSWORD = "root"
# MySQL上创建的数据库名称
DATABASE = "database_learn"
app.config["SQLALCHEMY_DATABASE_URI"] = (f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:"
f"{PORT}/{DATABASE}?charset=utf8mb4")
# 在app.config中设置好连接数据库的信息
# 使用SQLAlchemy(app)创建一个db对象
# SQLAlchemy会自动读取app.config中连接数据库的信息
db = SQLAlchemy(app)
# 测试是否连接成功代码
# with app.app_context():
# with db.engine.connect() as conn:
# rs = conn.execute(text("select 1"))
# print(rs.fetchone()) # (1,)
class User(db.Model):
__tablename__ = "user"
# primary_key=True 设置主键 autoincrement=True 设置自动增加
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
# db.String指定varchar类型(变动char类型)
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100), nullable=False)
# user = User(username="张三", password="123456")
# 相当于这条语句sql: insert user(username, password) values('张三', '123456')
@app.route("/user/add")
def add_user():
# 1.创建ORM对象
user = User(username="张三", password="123456")
# 2.将ORM对象添加到db.session中
db.session.add(user)
# 3.将db.session中的改变同步到数据库中
db.session.commit()
return "用户创建成功"
@app.route("/user/query")
def query_user():
# 1.get查找:根据主键查找
# user = User.query.get(1)
# print(f"{user.id}: {user.username}-{user.password}")
# 2.filter_by查找
# Query:类数组
users = User.query.filter_by(username="张三")
for user in users:
print(user.username, user.password)
return "数据查找成功!"
@app.route("/user/update")
def update_user():
user = User.query.filter_by(username="张三").first()
user.password = "111111"
db.session.commit()
return "数据修改成功"
@app.route("/user/delete")
def delete_user():
# 1.查找
user = User.query.get(1)
# 2.从db.session中的修改,同步到数据库中
db.session.delete(user)
# 3.将db.session中的修改同步到数据库中
db.session.commit()
with app.app_context():
db.create_all()
@app.route('/')
def hello_world(): # put application's code here
return 'Hello World!'
if __name__ == '__main__':
app.run()
添加主键和外键
简介:数据库中的主键是每张表里唯一的,外键则起到关联表的作用,防止无效数据产生。
这里主要创建了一个user
表和一个关联user_id
的article
外键表,user_id
为user
表的主键,author_id
为article
表的外键。但是由于外键是写死的,要查看user_id
来get
。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
app = Flask(__name__)
# MySQL所在的主机名
HOSTNAME = "127.0.0.1"
# MySQL所在的端口号
PORT = 3306
# 连接MySQL的用户名
USERNAME = "root"
# 连接MySQL的密码
PASSWORD = "root"
# MySQL上创建的数据库名称
DATABASE = "database_learn"
app.config["SQLALCHEMY_DATABASE_URI"] = (f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:"
f"{PORT}/{DATABASE}?charset=utf8mb4")
# 在app.config中设置好连接数据库的信息
# 使用SQLAlchemy(app)创建一个db对象
# SQLAlchemy会自动读取app.config中连接数据库的信息
db = SQLAlchemy(app)
# 测试是否连接成功代码
# with app.app_context():
# with db.engine.connect() as conn:
# rs = conn.execute(text("select 1"))
# print(rs.fetchone()) # (1,)
class User(db.Model):
__tablename__ = "user"
# primary_key=True 设置主键 autoincrement=True 设置自动增加
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
# db.String指定varchar类型(变动char类型)
username = db.Column(db.String(100), nullable=False)
password = db.Column(db.String(100), nullable=False)
class Article(db.Model):
__tablename__ = "article"
# primary_key=True 设置主键 autoincrement=True 设置自动增加
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200), nullable=False)
# 这里引用的是text,string最多存255字符,已经不够用了
content = db.Column(db.Text, nullable=False)
# 添加作者id外键
author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
# backref:会自动给User模型添加一个articles的属性,用来获取文章列表
author = db.relationship("User", backref=db.backref("articles"))
with app.app_context():
db.create_all()
# user = User(username="张三", password="123456")
# 相当于这条语句sql: insert user(username, password) values('张三', '123456')
@app.route('/')
def hello_world(): # put application's code here
return 'Hello World!'
@app.route("/user/add")
def add_user():
# 1.创建ORM对象
user = User(username="张三", password="123456")
# 2.将ORM对象添加到db.session中
db.session.add(user)
# 3.将db.session中的改变同步到数据库中
db.session.commit()
return "用户创建成功"
@app.route("/user/query")
def query_user():
# 1.get查找:根据主键查找
# user = User.query.get(1)
# print(f"{user.id}: {user.username}-{user.password}")
# 2.filter_by查找
# Query:类数组
users = User.query.filter_by(username="张三")
for user in users:
print(user.username, user.password)
return "数据查找成功!"
@app.route("/user/update")
def update_user():
user = User.query.filter_by(username="张三").first()
user.password = "111111"
db.session.commit()
return "数据修改成功"
@app.route("/user/delete")
def delete_user():
# 1.查找
user = User.query.get(1)
# 2.从db.session中的修改,同步到数据库中
db.session.delete(user)
# 3.将db.session中的修改同步到数据库中
db.session.commit()
return "数据删除成功"
@app.route("/article/add")
def add_article():
article1 = Article(title="Flask学习大纲", content="Flaskxxx")
article1.author = User.query.get(2)
article2 = Article(title="Django学习大纲", content="Django最全学习大纲")
article2.author = User.query.get(2)
# 添加到session中
db.session.add_all([article1, article2])
db.session.commit()
return "文章添加成功"
@app.route("/article/query")
def query_article():
user = User.query.get(2)
for article in user.articles:
print(article.title)
return "文章查找成功!"
if __name__ == '__main__':
app.run()
注意:一定要有用户表否则无法产生外键关联
user表:
关联表:
迁移ORM模型
简介:之前创建数据库的表的指令db.create_all()
这种方式有很大的局限性,在创建好表以后,不能在对表结构进行修改。为了能够对表结构进行修改,需要使用migrate
库
安装flask-migrate
:
pip install flask-migrate
在连接代码后添加下面的代码:
db = SQLAlchemy(app)
migrate = Migrate(app, db)
添加完成后在终端进行操作:
# 1.flask db init: 这步只需要执行一次
python -m flask db init
# 2.flask db migrate: 识别ORM模型的改变,生成迁移脚本
flask db migrate
# 3.flask db upgrade: 运行迁移脚本,同步到数据库中
flask db upgrade
搭建问答平台
简介:一个基于flask的论坛
搭建
简介:新建项目,搭建项目架构。上面学的东西只是flask基础,项目架构才是一个项目真正的核心。
项目架构
简介:所有配置文件都要和app.py
关联。项目文件结果如图所示:
app.py
:项目的执行文件
from flask import Flask
import config
from exts import db
from models import UserModel
from blueprint.qa import bp as qa_bp
from blueprint.author import bp as author_bp
from flask_migrate import Migrate
app = Flask(__name__)
# 绑定配置文件
app.config.from_object(config)
# 这种db的创建方法允许先创建再导入模型
db.init_app(app)
migrate = Migrate(app, db)
# 导入蓝图
app.register_blueprint(qa_bp)
app.register_blueprint(author_bp)
if __name__ == '__main__':
app.run()
config.py
:配置文件,主要配置cookie和加密,使用app.config.form_object(config)
和app.py
绑定
models.py
:创建ORM模型的文件
from exts import db
class UserModel(db.Model):
pass
exts.py
:exts
主要存放插件方法。例如:
ORM
模型在开发时不会放在app.py
中,而是独立放在一个model.py
文件中。但是model.py
需要引用app.py
中的db
方法,app.py
又需要引用models.py
中的Usermodel
,这样会导致循环引用使代码不能执行,如图所示:
为了解决这个问题,需要建立exts.py
文件,存放db = SQLAlchemy()方法,使得app.py和models.py分别去调用db方法,这样就不会产生循环引用,如图所示:
# flask-sqlalchemy
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
blueprints
:在项目搭建过程中,我们不会把路由放到app.py中,而是放到blueprint.py中通过蓝图的形式导入。
author.py
:
from flask import Blueprint
# 这里指定/author前缀,用这个方法做路由的都有/author的前缀
bp = BLUEPRINT = Blueprint('author', __name__, url_prefix='/author')
# 这里的路由路径为:http://localhost/auth/login
@bp.route('/login')
def login_page():
pass
qa.py
:
from flask import Blueprint
# 这里不指定前缀
bp = BLUEPRINT = Blueprint('auth', __name__, url_prefix='/')
# 这里的路由路径为:http://localhost/login
@bp.route('/')
def login_page():
pass
创建数据库
简介:这里需要创建user数据库,并将数据库进行连接。
先创建一个forum数据库:
设置config.py:
# 数据库配置信息
HOSTNAME = "127.0.0.1"
PORT = 3306
USERNAME = "root"
PASSWORD = "root"
DATABASE = "forum_user"
DB_URI = 'mysql+pymysql://{}:{}@{}:{}/{}?charset=utf8'.format(USERNAME, PASSWORD, HOSTNAME, PORT, DATABASE)
SQLALCHEMY_DATABASE_URI = DB_URI
设置model.py数据库表:
from exts import db
from datetime import datetime
class UserModel(db.Model):
__tablename__ = "user"
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
username = db.Column(db.String(100), nullable=True)
password = db.Column(db.String(100), nullable=True)
email = db.Column(db.String(100), nullable=True, unique=True)
join_time = db.Column(db.DateTime, default=datetime.now)
设置app.py,添加migrate的引用:
from flask import Flask
import config
from exts import db
from models import UserModel
from blueprint.qa import bp as qa_bp
from blueprint.author import bp as author_bp
from flask_migrate import Migrate
app = Flask(__name__)
# 绑定配置文件
app.config.from_object(config)
# 这种db的创建方法允许先创建再导入模型
db.init_app(app)
# 新增内容
migrate = Migrate(app, db)
# 导入蓝图
app.register_blueprint(qa_bp)
app.register_blueprint(author_bp)
if __name__ == '__main__':
app.run()
使用命令创建数据库:
flask db init
flask db migrate
flask db upgrade