Flask-Script 扩展命令行
from flask import Flask
from flask_script import Manager
app = Flask(__name__)
manager = Manager(app)
@app.route('/')
def index():
return '我的快乐时代'
if __name__ == "__main__":
manager.run()
通过使用Flask-Script扩展,我们可以在Flask服务器启动的时候,通过命令行的方式传入参数。而不仅仅通过app.run()方法中传参,
比如我们可以通过python hello.py runserver --host ip地址,告诉服务器在哪个网络接口监听来自客户端的连接。默认情况下,服务器只监听来自服务器所在计算机发起的连接,即localhost连接。
我们可以通过 python hello.py runserver --help 来查看参数:
Flask-WTF
相关参考链接
关于 web 表单
web表单是web应用程序的基本功能。 它是HTML页面中负责数据采集的部件。表单有三个部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。
在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,并且它有验证表单数据的功能。
WTForms支持的HTML标准字段
WTForms常用验证函数
表单中的 CSRF
使用Flask-WTF需要配置参数SECRET_KEY。 CSRF_ENABLED是为了CSRF(跨站请求伪造)保护。 SECRET_KEY用来生成加密令牌,当CSRF激活的时候,该设置会根据设置的密匙生成加密令牌。
在HTML页面中直接写form表单的模式
文件结构:
templates/login.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form method='post'>
<input type="text" name="username" placeholder='Username'>
<input type="password" name="password" placeholder='password'>
<input type="submit">
</form>
</body>
</html>
hello.py
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
print(username, password)
return render_template('login.html', method=request.method)
if __name__ == "__main__":
app.run()
使用Flask-WTF实现表单
安装:
pip install flask-wtf
首先需要配置参数: app.config['SECRET_KEY'] = 'ruiyang'
文件结构:
hello.py
from flask import Flask, render_template, redirect, url_for, request, flash
from flask_wtf import Form
from wtforms import SubmitField, StringField, PasswordField
from wtforms.validators import DataRequired, EqualTo
app = Flask(__name__)
app.config['SECRET_KEY'] = 'ruiyang'
class Login(Form):
us = StringField(label=u'用户:', validators=[DataRequired()])
ps = PasswordField(label=u'密码', validators=[DataRequired(),EqualTo('ps2','err')])
ps2 = PasswordField(label=u'确认密码', validators=[DataRequired()])
submit = SubmitField(u'提交')
@app.route('/', methods=['GET', 'POST'])
def index():
form = Login()
if form.validate_on_submit():
name = form.us.data
pswd = form.ps.data
pswd2 = form.ps2.data
print(name, pswd, pswd2)
return "login seccess"
else:
if request.method == 'POST':
flash(u'信息有误,请重新输入!')
print(form.validate_on_submit())
return render_template('login.html', form=form)
if __name__ == '__main__':
app.run(debug=True)
templates/login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<form method="post">
{{ form.csrf_token() }}
{{ form.us.label }}
<p>{{ form.us }}</p>
{{ form.ps.label }}
<p>{{ form.ps }}</p>
{{ form.ps2.label }}
<p>{{ form.ps2 }}</p>
<p>{{ form.submit() }}</p>
{% for x in get_flashed_messages() %}
{{ x }}
{% endfor %}
</form>
</body>
</html>
flask-sqlalchemy
相关参考链接
安装
pip install flask-sqlalchemy
需要连接mysql数据库,仍然需要安装 flask-mysqldb
pip install flask-mysqldb
配置
Flask的数据库设置:
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:ruiyang@127.0.0.1:3306/test'
常用的SQLAlchemy字段类型
常用的SQLAlchemy列选项
常用的SQLAlchemy关系选项
在程序中的基础操作
创建测试数据:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# 设置连接数据库的URL
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:ruiyang@127.0.0.1:3306/test'
# 设置每次请求结束后会自动提交数据库中的改动
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
# 查询时会显示原始SQL语句
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
us = db.relationship('User', backref='role')
def __repr__(self):
return 'Role:{}'.format(self.name)
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True, index=True)
email = db.Column(db.String(64), unique=True)
pswd = db.Column(db.String(64))
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
def __repr__(self):
return 'User:{}'.format(self.name)
if __name__ == '__main__':
db.drop_all()
db.create_all()
ro1 = Role(name='admin')
ro2 = Role(name='user')
db.session.add_all([ro1, ro2])
db.session.commit()
us1 = User(name='wang', email='wang@163.com', pswd='123456', role_id=ro1.id)
us2 = User(name='zhang', email='zhang@189.com', pswd='201512', role_id=ro2.id)
us3 = User(name='chen', email='chen@126.com', pswd='987654', role_id=ro2.id)
us4 = User(name='zhou', email='zhou@163.com', pswd='456789', role_id=ro1.id)
db.session.add_all([us1, us2, us3, us4])
db.session.commit()
app.run(debug=True)
运行程序之后启动 flask shell 进行操作:
创建和删除表:
>>> db.create_all()
2019-08-10 13:45:02,631 INFO sqlalchemy.engine.base.Engine DESCRIBE `roles`
2019-08-10 13:45:02,631 INFO sqlalchemy.engine.base.Engine ()
2019-08-10 13:45:02,632 INFO sqlalchemy.engine.base.Engine DESCRIBE `users`
2019-08-10 13:45:02,632 INFO sqlalchemy.engine.base.Engine ()
>>> db.drop_all()
2019-08-10 13:45:11,267 INFO sqlalchemy.engine.base.Engine DESCRIBE `roles`
2019-08-10 13:45:11,267 INFO sqlalchemy.engine.base.Engine ()
2019-08-10 13:45:11,268 INFO sqlalchemy.engine.base.Engine DESCRIBE `users`
2019-08-10 13:45:11,268 INFO sqlalchemy.engine.base.Engine ()
2019-08-10 13:45:11,270 INFO sqlalchemy.engine.base.Engine
DROP TABLE users
2019-08-10 13:45:11,270 INFO sqlalchemy.engine.base.Engine ()
2019-08-10 13:45:11,283 INFO sqlalchemy.engine.base.Engine COMMIT
2019-08-10 13:45:11,284 INFO sqlalchemy.engine.base.Engine
DROP TABLE roles
2019-08-10 13:45:11,284 INFO sqlalchemy.engine.base.Engine ()
2019-08-10 13:45:11,294 INFO sqlalchemy.engine.base.Engine COMMIT
插入单条数据:
>>> from hello import Role
>>> role_admin = Role(name="admin")
>>> db.session.add(role_admin)
>>> db.session.commit()
2019-08-10 13:46:40,071 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-08-10 13:46:40,071 INFO sqlalchemy.engine.base.Engine INSERT INTO roles (name) VALUES (%s)
2019-08-10 13:46:40,072 INFO sqlalchemy.engine.base.Engine ('admin',)
2019-08-10 13:46:40,073 INFO sqlalchemy.engine.base.Engine COMMIT
>>> role1 = Role(name="user1")
>>> db.session.add(role1)
>>> db.session.commit()
2019-08-10 13:47:03,975 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-08-10 13:47:03,975 INFO sqlalchemy.engine.base.Engine INSERT INTO roles (name) VALUES (%s)
2019-08-10 13:47:03,975 INFO sqlalchemy.engine.base.Engine ('user1',)
2019-08-10 13:47:03,976 INFO sqlalchemy.engine.base.Engine COMMIT
>>> role2 = Role(name="ruiyang")
>>> db.session.add(role2)
>>> db.session.commit()
2019-08-10 13:47:39,205 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-08-10 13:47:39,205 INFO sqlalchemy.engine.base.Engine INSERT INTO roles (name) VALUES (%s)
2019-08-10 13:47:39,205 INFO sqlalchemy.engine.base.Engine ('ruiyang',)
2019-08-10 13:47:39,206 INFO sqlalchemy.engine.base.Engine COMMIT
插入多条数据: add_all()
>>> us1 = User(name='wang',email='wang@163.com',pswd='123456',role_id=role_admin.id)
2019-08-10 13:49:09,064 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-08-10 13:49:09,064 INFO sqlalchemy.engine.base.Engine SELECT roles.id AS roles_id, roles.name AS roles_name
FROM roles
WHERE roles.id = %s
2019-08-10 13:49:09,065 INFO sqlalchemy.engine.base.Engine (1,)
>>> us2 = User(name='zhang',email='zhang@189.com',pswd='201512',role_id=role1.id)
2019-08-10 13:49:52,577 INFO sqlalchemy.engine.base.Engine SELECT roles.id AS roles_id, roles.name AS roles_name
FROM roles
WHERE roles.id = %s
2019-08-10 13:49:52,577 INFO sqlalchemy.engine.base.Engine (2,)
>>> us3 = User(name='chen',email='chen@126.com',pswd='987654',role_id=role1.id)
>>> us4 = User(name='zhou',email='zhou@163.com',pswd='456789',role_id=role2.id)
2019-08-10 13:50:20,853 INFO sqlalchemy.engine.base.Engine SELECT roles.id AS roles_id, roles.name AS roles_name
FROM roles
WHERE roles.id = %s
2019-08-10 13:50:20,853 INFO sqlalchemy.engine.base.Engine (3,)
>>> db.session.add_all([us1,us2,us3,us4])
>>> db.session.commit()
2019-08-10 13:50:38,442 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, email, pswd, role_id) VALUES (%s, %s, %s, %s)
2019-08-10 13:50:38,442 INFO sqlalchemy.engine.base.Engine ('wang', 'wang@163.com', '123456', 1)
2019-08-10 13:50:38,444 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, email, pswd, role_id) VALUES (%s, %s, %s, %s)
2019-08-10 13:50:38,444 INFO sqlalchemy.engine.base.Engine ('zhang', 'zhang@189.com', '201512', 2)
2019-08-10 13:50:38,445 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, email, pswd, role_id) VALUES (%s, %s, %s, %s)
2019-08-10 13:50:38,445 INFO sqlalchemy.engine.base.Engine ('chen', 'chen@126.com', '987654', 2)
2019-08-10 13:50:38,446 INFO sqlalchemy.engine.base.Engine INSERT INTO users (name, email, pswd, role_id) VALUES (%s, %s, %s, %s)
2019-08-10 13:50:38,446 INFO sqlalchemy.engine.base.Engine ('zhou', 'zhou@163.com', '456789', 3)
2019-08-10 13:50:38,446 INFO sqlalchemy.engine.base.Engine COMMIT
使用 filter_by 精确查询: 查询第一个和全部
>>> User.query.filter_by(name='wang').first()
2019-08-10 13:54:08,112 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE users.name = %s
LIMIT %s
2019-08-10 13:54:08,113 INFO sqlalchemy.engine.base.Engine ('wang', 1)
User:wang
>>> User.query.filter_by(name='wang').all()
2019-08-10 13:54:15,698 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE users.name = %s
2019-08-10 13:54:15,698 INFO sqlalchemy.engine.base.Engine ('wang',)
[User:wang]
使用 filter 模糊查询,返回结尾字符为 g 的所有数据:
>>> User.query.filter(User.name.endswith('g')).all()
2019-08-12 09:01:24,998 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE (users.name LIKE concat('%%', %s))
2019-08-12 09:01:24,999 INFO sqlalchemy.engine.base.Engine ('g',)
[User:wang, User:zhang]
逻辑非:返回名字不等于 wang 的全部数据:
>>> User.query.filter(User.name!='wang').all()
2019-08-12 09:02:03,321 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE users.name != %s
2019-08-12 09:02:03,321 INFO sqlalchemy.engine.base.Engine ('wang',)
[User:zhang, User:chen, User:zhou]
逻辑与,需要导入 _and 返回and() 条件满足的所有数据:
>>> User.query.filter(and_(User.name != 'wang',User.email.endswith('163.com'))).all()
2019-08-12 09:22:21,840 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE users.name != %s AND (users.email LIKE concat('%%', %s))
2019-08-12 09:22:21,841 INFO sqlalchemy.engine.base.Engine ('wang', '163.com')
[User:zhou]
逻辑或,需要导入 or_
>>> from sqlalchemy import or_
>>> User.query.filter(or_(User.name != "wang", User.email.endswith('163.com'))).all()
2019-08-12 09:24:17,577 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE users.name != %s OR (users.email LIKE concat('%%', %s))
2019-08-12 09:24:17,577 INFO sqlalchemy.engine.base.Engine ('wang', '163.com')
[User:wang, User:zhang, User:chen, User:zhou]
not_ 相当于取反
>>> from sqlalchemy import not_
>>> User.query.filter(not_(User.name == "chen")).all()
2019-08-12 09:25:49,716 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE users.name != %s
2019-08-12 09:25:49,716 INFO sqlalchemy.engine.base.Engine ('chen',)
[User:wang, User:zhang, User:zhou]
查询数据后删除
>>> user = User.query.first()
2019-08-12 09:26:58,334 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
LIMIT %s
2019-08-12 09:26:58,334 INFO sqlalchemy.engine.base.Engine (1,)
>>> user
User:wang
>>> db.session.delete(user)
>>> db.session.commit()
2019-08-12 09:27:27,209 INFO sqlalchemy.engine.base.Engine DELETE FROM users WHERE users.id = %s
2019-08-12 09:27:27,209 INFO sqlalchemy.engine.base.Engine (1,)
2019-08-12 09:27:27,225 INFO sqlalchemy.engine.base.Engine COMMIT
>>> User.query.all()
2019-08-12 09:27:36,097 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-08-12 09:27:36,098 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
2019-08-12 09:27:36,098 INFO sqlalchemy.engine.base.Engine ()
[User:zhang, User:chen, User:zhou]
更新数据:
>>> user = User.query.first()
2019-08-12 09:28:09,206 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
LIMIT %s
2019-08-12 09:28:09,206 INFO sqlalchemy.engine.base.Engine (1,)
>>> user
User:zhang
>>> user.name
'zhang'
>>> user.name = "furuiyang"
>>> db.session.commit()
2019-08-12 09:28:34,955 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=%s WHERE users.id = %s
2019-08-12 09:28:34,955 INFO sqlalchemy.engine.base.Engine ('furuiyang', 2)
2019-08-12 09:28:34,960 INFO sqlalchemy.engine.base.Engine COMMIT
>>> User.query.first()
2019-08-12 09:28:46,551 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
2019-08-12 09:28:46,552 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
LIMIT %s
2019-08-12 09:28:46,552 INFO sqlalchemy.engine.base.Engine (1,) User:furuiyang
使用 update 更新数据:
>>> User.query.filter_by(name='furuiyang').update({"name": "Katrina"})
2019-08-12 09:30:38,053 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE users.id = %s
2019-08-12 09:30:38,054 INFO sqlalchemy.engine.base.Engine (3,)
2019-08-12 09:30:38,058 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE users.id = %s
2019-08-12 09:30:38,059 INFO sqlalchemy.engine.base.Engine (4,)
2019-08-12 09:30:38,060 INFO sqlalchemy.engine.base.Engine UPDATE users SET name=%s WHERE users.name = %s
2019-08-12 09:30:38,060 INFO sqlalchemy.engine.base.Engine ('Katrina', 'furuiyang')
1
>>> User.query.all()
2019-08-12 09:31:00,951 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
2019-08-12 09:31:00,951 INFO sqlalchemy.engine.base.Engine ()
[User:Katrina, User:chen, User:zhou]
关联查询示例: 角色和用户是一对多的关系。一个角色可以有多个用户,但是一个用户只能属于一个角色:
查询某个角色组(ruiyang) 下的全部用户:
>>> role_ruiyang = Role.query.filter_by(name='ruiyang').first()
2019-08-12 09:35:24,302 INFO sqlalchemy.engine.base.Engine SELECT roles.id AS roles_id, roles.name AS roles_name
FROM roles
WHERE roles.name = %s
LIMIT %s
2019-08-12 09:35:24,302 INFO sqlalchemy.engine.base.Engine ('ruiyang', 1)
>>> role_ruiyang
Role:ruiyang
>>> role_ruiyang.us
2019-08-12 09:35:41,776 INFO sqlalchemy.engine.base.Engine SELECT users.id AS users_id, users.name AS users_name, users.email AS users_email, users.pswd AS users_pswd, users.role_id AS users_role_id
FROM users
WHERE %s = users.role_id
2019-08-12 09:35:41,776 INFO sqlalchemy.engine.base.Engine (3,)
[User:zhou]
查询某个用户所属的角色:
>>> user = User.query.get(3)
>>> user
User:chen
>>> user.role
Role:user1
数据库迁移之 Flask-Migrate
安装
pip install flask-migrate
创建一个测试 app
如下:定义了两个模型类,作者和书名:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:ruiyang@127.0.0.1:3306/test'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class Author(db.Model):
"""
定义模型类-作者
"""
__tablename__ = 'author'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32), unique=True)
email = db.Column(db.String(64))
au_book = db.relationship('Book', backref='author')
def __str__(self):
return f'Author:{self.name}'
class Book(db.Model):
"""
定义模型类-书名
"""
__tablename__ = 'books'
id = db.Column(db.Integer, primary_key=True)
info = db.Column(db.String(32), unique=True)
leader = db.Column(db.String(32))
au_book = db.Column(db.Integer, db.ForeignKey('author.id'))
def __str__(self):
return f'Book:{self.info},{self.lead}'
if __name__ == "__main__":
app.run()
开启 flask shell 创建表:
(ihome) furuiyang@furuiyangdeMacBook-Pro ~/codes/iHomeDemo master flask shell
Python 3.7.3 (default, Jun 19 2019, 07:38:49)
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
App: app [production]
Instance: /Users/furuiyang/codes/iHomeDemo/instance
>>> from app import db
>>> db.create_all()
在数据库中查看创建出的表结构:
mysql> desc author;
+-------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(32) | YES | UNI | NULL | |
| email | varchar(64) | YES | | NULL | |
+-------+-------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> desc books;
+---------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| info | varchar(32) | YES | UNI | NULL | |
| leader | varchar(32) | YES | | NULL | |
| au_book | int(11) | YES | MUL | NULL | |
+---------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
生成一些测试数据:
>>> au1 = Author(name='八月长安',email='changan@163.com')
>>> au2 = Author(name='余秋雨',email='qiuyu@126.com')
>>> au3 = Author(name='冯唐',email='tang@163.com')
>>> bk1 = Book(info='最好的我们',leader='耿耿&余淮')
>>> bk2 = Book(info='文化苦旅',leader='风景抒情')
>>> bk3 = Book(info='万物生长',leader='秋水')
>>> db.session.add_all([au1, au2, au3, bk1, bk2, bk3])
>>> db.session.commit()
查看数据库:
mysql> select * from author;
+----+--------------+-----------------+
| id | name | email |
+----+--------------+-----------------+
| 1 | 八月长安 | changan@163.com |
| 2 | 余秋雨 | qiuyu@126.com |
| 3 | 冯唐 | tang@163.com |
+----+--------------+-----------------+
3 rows in set (0.00 sec)
mysql> select * from books;
+----+-----------------+---------------+---------+
| id | info | leader | au_book |
+----+-----------------+---------------+---------+
| 1 | 最好的我们 | 耿耿&余淮 | NULL |
| 2 | 文化苦旅 | 风景抒情 | NULL |
| 3 | 万物生长 | 秋水 | NULL |
+----+-----------------+---------------+---------+
3 rows in set (0.00 sec)
添加一个模板展示页面:
<h1>书籍展示</h1>
<form method="post">
{{ form.csrf_token }}
<p>作者:{{ form.au_info }}</p>
<p>书名:{{ form.bk_info }}</p>
<p>{{ form.submit }}</p>
</form>
<ul>
<li>{% for x in author %}</li>
<li>{{ x }}</li><a href='/delete_author{{ x.id }}'>删除</a>
<li>{% endfor %}</li>
</ul>
<hr>
<ul>
<li>{% for x in book %}</li>
<li>{{ x }}</li><a href='/delete_book{{ x.id }}'>删除</a>
<li>{% endfor %}</li>
</ul>
添加视图路由:
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:ruiyang@127.0.0.1:3306/test'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SECRET_KEY'] = 'ruiyang'
db = SQLAlchemy(app)
class Author(db.Model):
"""
定义模型类-作者
"""
__tablename__ = 'author'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32), unique=True)
email = db.Column(db.String(64))
au_book = db.relationship('Book', backref='author')
def __str__(self):
return f'Author:{self.name}'
class Book(db.Model):
"""
定义模型类-书名
"""
__tablename__ = 'books'
id = db.Column(db.Integer, primary_key=True)
info = db.Column(db.String(32), unique=True)
leader = db.Column(db.String(32))
au_book = db.Column(db.Integer, db.ForeignKey('author.id'))
def __str__(self):
return f'Book:{self.info},{self.leader}'
class Append(Form):
"""创建表单类,用来添加信息"""
au_info = StringField(validators=[DataRequired()])
bk_info = StringField(validators=[DataRequired()])
submit = SubmitField(u'添加')
@app.route('/', methods=['GET', 'POST'])
def index():
# 查询所有作者和书名信息
author = Author.query.all()
book = Book.query.all()
# 创建表单对象
form = Append()
if form.validate_on_submit():
# 获取表单输入数据
wtf_au = form.au_info.data
wtf_bk = form.bk_info.data
# 把表单数据存入模型类
db_au = Author(name=wtf_au)
db_bk = Book(info=wtf_bk)
# 提交会话
db.session.add_all([db_au,db_bk])
db.session.commit()
# 添加数据后,再次查询所有作者和书名信息
author = Author.query.all()
book = Book.query.all()
return render_template('index.html', author=author, book=book, form=form)
else:
if request.method == 'GET':
render_template('index.html', author=author, book=book, form=form)
return render_template('index.html', author=author, book=book, form=form)
@app.route('/delete_author<id>')
def delete_author(id):
"""删除作者"""
# 精确查询需要删除的作者id
au = Author.query.filter_by(id=id).first()
db.session.delete(au)
# 直接重定向到index视图函数
return redirect(url_for('index'))
@app.route('/delete_book<id>')
def delete_book(id):
"""删除书名"""
# 精确查询需要删除的书名id
bk = Book.query.filter_by(id=id).first()
db.session.delete(bk)
# 直接重定向到index视图函数
return redirect(url_for('index'))
if __name__ == "__main__":
app.run(debug=True)
在 app 中加入扩展
创建迁移数据库
(ihome) ✘ furuiyang@furuiyangdeMacBook-Pro ~/codes/iHomeDemo master ●✚ flask db init
Creating directory /Users/furuiyang/codes/iHomeDemo/migrations ... done
Creating directory /Users/furuiyang/codes/iHomeDemo/migrations/versions ... done
Generating /Users/furuiyang/codes/iHomeDemo/migrations/script.py.mako ... done
Generating /Users/furuiyang/codes/iHomeDemo/migrations/env.py ... done
Generating /Users/furuiyang/codes/iHomeDemo/migrations/README ... done
Generating /Users/furuiyang/codes/iHomeDemo/migrations/alembic.ini ... done
创建迁移数据脚本
(ihome) furuiyang@furuiyangdeMacBook-Pro ~/codes/iHomeDemo master ●✚ flask db migrate -m 'first'
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.autogenerate.compare] Detected added table 'author'
INFO [alembic.autogenerate.compare] Detected added table 'books'
Generating /Users/furuiyang/codes/iHomeDemo/migrations/versions/947c0bffbb1b_first.py ... done
使用迁移脚本更新数据库
(ihome) furuiyang@furuiyangdeMacBook-Pro ~/codes/iHomeDemo master ●✚ flask db upgrade
INFO [alembic.runtime.migration] Context impl MySQLImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> 947c0bffbb1b, first
数据库变动
查看历史版本
flask db history
版本回退
flask db downgrade 版本号
注册shell上下文
在我们启动 flask shell的时候,我们就实现了在上下文中启动了一个python 解释器。这意味着我们可以有了当前的应用实例:
使用常规的解释器会话时,除非明确地被导入,否则app对象是未知的,但是当使用flask shell时,该命令预先导入应用实例。 flask shell的绝妙之处不在于它预先导入了app,而是你可以配置一个“shell上下文”,也就是可以预先导入一份对象列表。
在入口脚本中实现一个函数,通过添加数据库实例和模型来创建了一个shell上下文环境:
from app import app, db
from app.models import User, Post
@app.shell_context_processor
def make_shell_context():
return {'db': db, 'User': User, 'Post': Post}
app.shell_context_processor装饰器将该函数注册为一个shell上下文函数。 当flask shell命令运行时,它会调用这个函数并在shell会话中注册它返回的项目。 函数返回一个字典而不是一个列表,原因是对于每个项目,你必须通过字典的键提供一个名称以便在shell中被调用。