一 flask_wtf与flask_bootstrap
首先,要做的就是安装 flask_wtf 这个库
pip install flask-WTF
注意:这里在安装的时候,看好库名,是 -WTF ,并不是 _wtf ,但是在应用的时候,却是后者
from flask_wtf import FlaskForm
导入这个库里面的 FlaskForm这个类
这里图简单一点,会一次性导入许多的东西,当然都是下面的例子会用到的
from wtforms import StringField, PasswordField, SubmitField, FileField
导入一些常用的表单类型,相当于input标签中type的作用
from wtforms.validators import DataRequired, Length, Email, Regexp, EqualTo
导入一些常用的验证表单,用来确保表单内容是否合法
这里写一个用户登陆和注册时的案例,flask_wtf的作用就是用来限制登陆和注册时的信息
from flask_wtf import FlaskForm
# 确定表单的类型, 相当于input标签中type的作用
from wtforms import StringField, PasswordField, SubmitField, FileField
# 确保表单内容是否合法;
from wtforms.validators import DataRequired, Length, Email, Regexp, EqualTo
# Regexp == regular experssion (用于编写正则表达式的)
class LoginForm(FlaskForm):
user = StringField(
label="用户名/手机/邮箱",
validators=[
DataRequired(message="用户名不能为空"),
Length(5, 12),
]
)
passwd = PasswordField(
label="密码",
validators=[
Length(6)
]
)
submit = SubmitField(
label="登录"
)
class RegisterForm(FlaskForm):
user = StringField(
label="用户名/手机/邮箱",
validators=[
Length(5, 12),
]
)
email = StringField(
label="邮箱",
validators=[
Email("邮箱格式不正确!")
]
)
phone = StringField(
label="电话",
validators=[
Regexp(r'1\d{10}', message="手机格式不正确!")
]
)
passwd = PasswordField(
label="密码",
validators=[
Length(6)
]
)
repasswd = PasswordField(
label="确认密码",
validators=[
EqualTo('passwd', "两次密码不一致!")
]
)
submit = SubmitField(
label="注册"
)
上面的代码,需要注意的一点就是:
lable:(是用来对要填写内容的提示)
validators:(是用来对要填写内容的限制),一些具体的限制内容祥解,在上一篇博客中写过
这里还有一点,被我藏起来了(没想到吧),没写到上面的代码中,下面来提起
在用户注册的时候,有时候会被要求,上传图像,这里就有不同的地方了
来,划重点:
face = FileField(
label="上传头像",
validators=[
FileAllowed(['png', 'jpg'], message="文件非图片")
]
)
validators 中的 FileAllowed 是从from flask_wtf.file import FileAllowed
这里导出的,还有 FileRequired(必填文件) 也一样,并不同于其它的要求
下面是需要注意的几点:
1). 如何在flask中使用Boostrap?
要想在程序中集成Bootstrap,显然要对模板做所有必要的改动。不过,更简单的方法是使用一个名为Flask-Bootstrap 的Flask 扩展,简化集成的过程。Flask-Bootstrap 使用pip安装:
pip install flask_bootstrap
2). Flask 扩展一般都在创建程序实例时初始化,下面是Flask_Bootstrap的初始化方法
from flask_bootstrap import Bootstrap
app = Flask(__name__)
bootstrap = Bootstrap(app)
初始化Flask-Bootstrap 之后,就可以在程序中使用一个包含所有Bootstrap 文件的基模板。这个模板利用Jinja2 的模板继承机制,让程序扩展一个具有基本页面结构的基模板,其中就有用来引入Bootstrap 的元素。
3). 如何引用bootatrap的基模板?
{%extends "bootstrap/base.html"%}
{%block title %}Flask{% endblock %}
这两个块分别表示页面中的导航条和主体内容。在这个模板中,navbar 块使用Bootstrap 组件定义了一个简单的导航条。content 块中有个
4). Flask-Bootstrap定义的其他可用块
参考链接:https://pythonhosted.org/Flask-Bootstrap/basic-usage.html#available-blocks
恩~,还是翻译一下:
块名 | 说明 |
---|---|
doc | 整个html文档 |
html_attribs | html标签属性 |
html | html标签中的内容 |
head | head标签中的内容 |
title | title标签中的内容 |
metas | 一组meta标签 |
styles | 层叠样式表定义 |
body_attribs | body标签的属性 |
body | body标签中的内容 |
navbar | 用户定义的导航条 |
content | 用户定义的页面内容 |
scripts | 文档底部的JavaScript 声明 |
5). 如何继承原有内容
上表中的很多块都是Flask-Bootstrap 自用的,如果直接重定义可能会导致一些问题。例如,Bootstrap 所需的文件在styles 和scripts 块中声明。如果程序需要向已经有内容的块中添加新内容,必须使用Jinja2 提供的super() 函数。例如,如果要在衍生模板中添加新的JavaScript 文件,需要这么定义scripts 块:
{% block scripts %}
{{ super() }}
{% endblock %}
二 flask_sqlalchemy
flask_sqlalchemy为 Flask 提供了一个 SQLAlchemy 扩展,用来处理数据库的操作
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
app = Flask(__name__)
#Flask-SQLAlchemy 中存在的配置值
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:westos@localhost/User'
# SQLAlchemy 将会追踪对象的修改并且发送信号。
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
具体的配置键说明:
配置键 | 说明 |
---|---|
SQLALCHEMY_DATABASE_URI | 用于连接数据的数据库,例如:sqlite:////tmp/test.db; mysql://username:password@server/db |
SQLALCHEMY_TRACK_MODIFICATIONS | 如果设置成 True (默认情况),Flask-SQLAlchemy 将会追踪对象的修改并且发送信号。这需要额外的内存, 如果不必要的可以禁用它。 |
当然 mysql://username:password@server/db
在连接的时候,默认的是 Python2 中的 MySQLdb 。要想使用 Python3 中的 pymysql ,需要在mysql+pymysql://username:password@server/db
后面加上 mysql+pymysql
这样才是完整连接 URI 格式,才会连接上Python3中使用的数据库
一个简单的示例:
class User(db.Model):
# __tablename__ = "students"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __repr__(self):
return '' % self.username
其中:
1). 默认情况下创建一个表, 表名为类名; 如果指定了__tablename__, 那么表名为你指定的名称
2). 用 Column 来定义一列。列名就是您赋值给那个变量的名称。如果您想要在表中使用不同的名称,您可以提供一个想要的列名的字符串作为可选第一个参数
3). 主键用 primary_key=True 标记。可以把多个键标记为主键,此时它们作为复合主键
4). 列的类型是 Column 的第一个参数。您可以直接提供它们或进一步规定(比如提供一个长度)。下面的类型是最常用的:
类型 | 解释说明 |
---|---|
Integer | 一个整数 |
String (size) | 有长度限制的字符串 |
Text | 一些较长的 unicode 文本 |
DateTime | 表示为 Python datetime 对象的 时间和日期 |
Float | 存储浮点值 |
Boolean | 存储布尔值 |
PickleType | 存储为一个持久化的 Python 对象 |
LargeBinary | 存储一个任意大的二进制数据 |
一对多的简单示例:
class Person(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
addresses = db.relationship('Address', backref='person')
class Address(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(50))
person_id = db.Column(db.Integer, db.ForeignKey('person.id'))
其中:
1). 一的一端需要写反向引用:关系使用 relationship()
函数表示
2). 多的一端需要写外键:必须用类 sqlalchemy.schema.ForeignKey
来单独声明
还有一点需要注意:
db.drop_all()
创建定义的表结构
db.create_all()
删除定义的表结构
CREATE DATABASE User CHARACTER SET utf8 COLLATE utf8_general_ci;
然后再在库上建立数据。
from datetime import datetime
from flask_sqlalchemy import SQLAlchemy
from flask import Flask
from sqlalchemy import desc
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:redhat@localhost/User'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
db = SQLAlchemy(app)
# 用户表
class User(db.Model):
# autoincrement=True自增
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
# unique=True, name的值不能重复, 是唯一的;
name = db.Column(db.String(50), unique=True)
# 长度为100, 是因为网站密码一般会加密;
passwd = db.Column(db.String(100))
# 指定用户注册/创建的时间,
# default, 指定默认值, datetime.now()获取当前时间;
# 用户注册时间为当前时间;
add_time = db.Column(db.DateTime, default=datetime.now())
# 用户的角色id,不能随便写, 必须要关联其他的数据库表(role) --- 外键
role_id = db.Column(db.INTEGER, db.ForeignKey('role.id'))
def __repr__(self):
return '' %(self.name)
# 用户角色表
class Role(db.Model):
id = db.Column(db.Integer, autoincrement=True, primary_key=True)
name = db.Column(db.String(50), unique=True)
# Role表中的users属性与User表关联, 并且User这个表中可以由role这个对象属性;
users = db.relationship('User',backref='role')
def __repr__(self):
return "" %(self.name)
if __name__ == '__main__':
db.create_all()
1). 增加数据
在查询数据之前我们必须先插入数据。您的所有模型都应该有一个构造函数,如果您 忘记了,请确保加上一个。只有您自己使用这些构造函数而 SQLAlchemy 在内部不会使用它, 所以如何定义这些构造函数完全取决与您。
向数据库插入数据分为三个步骤:
1. 创建 Python 对象
2. 把它添加到会话
3. 提交会话
这里的会话不是 Flask 的会话,而是 Flask-SQLAlchemy 的会话。它本质上是一个 数据库事务的加强版本。它是这样工作的:
创建用户角色:
role1 = Role(name="超级会员")
role2 = Role(name="会员")
db.session.add(role1)
db.session.add(role2)
db.session.commit()
添加100个用户,其中50个为超级会员, 50个为会员:
for i in range(50):
u = User(name='westos%s' %(i), passwd='westos', role_id=1)
db.session.add(u)
db.session.commit()
for i in range(50):
u = User(name='redhat%s' % (i), passwd='redhat', role_id=2)
db.session.add(u)
db.session.commit()
2). 查询数据
Flask-SQLAlchemy 在您的 Model 类上提供了 query 属性。当您访问它时,您会得到一个新的所有记录的查询对象。在使用 all() 或者 first() 发起查询之前可以使用方法 filter() 来过滤记录。
(1)查询所有数据
print(Role.query.all())
print(User.query.all())
(2)根据条件查询数据(筛选数据(filter_by)); 相当于slect * from table where xxx=xxx;
print(User.query.filter_by(role_id=1).all())
print(User.query.filter_by(role_id=2).all())
(3)对于找到的内容进行更新
u = User.query.filter_by(name='westos0').first()
print(u)
u.passwd = '123456'
db.session.add(u)
db.session.commit()
(4)筛选数据方法2(filter),通过这种方式可以查看原生的sql语句
user = User.query.filter(User.role_id==1)
print(user)
(5)对于查询的信息进行显示限制
users = User.query.filter_by(role_id=1).limit(5).all()
print(users, len(users), end='\n')
(6)对于查询的信息进行排序输出(默认情况由小到大进行排序), 如果想要由大到小: desc(User.add_time)
users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).all()
print(users)
(7)多个过滤函数加一个显示函数
users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).limit(5).all()
print(users)
# offset指定偏移量, limit 指定输出数量, 类似于切片操作;
# 1 2 3 4 5 6 7 8 9
# limit(5): 1 2 3 4 5
# limit(5).offset(2): 3 4 5 6 7
users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).limit(5).offset(2).all()
print(users)
# 切片操作li[2:7]
users = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).slice(2,7).all()
print(users)
count = User.query.filter_by(role_id=1).order_by(desc(User.add_time)).slice(2, 7).count()
print(count)
(8)分页:第一个参数代表显示第几页的数据, 第二个参数代表每页显示多少条数据
users = User.query.paginate(1, 5)
print(users.items)
users = User.query.paginate(2, 5)
print(users.items)
(9)反向引用的使用
u = User.query.filter_by(name='westos0').first()
print(u.name, u.passwd, u.add_time, u.role_id, u.role, u.role.id, u.role.name)
3). 删除数据
删除数据与增加数据是十分类似的,使用 delete() 代替 add()
user=User.query.filter_by(name='redhat0').first()
db.session.delete(user)
db.session.commit()
三 flask_migrate与flask_script
flask_migrate
Flask-Migrate是用于处理SQLAlchemy 数据库迁移的扩展工具。当Model出现变更的时候,通过migrate去管理数据库变更
一般分为三步(init、migrate、upgrade)
flask_script
Flask_script扩展提供向Flask插入外部脚本的功能,包括运行一个开发用的服务器,一个定制的Python shell,设置数据库的脚本,cronjobs,及其他运行在web应用之外的命令行任务;使得脚本和系统分开;Flask_script和Flask本身的工作方式类似,只需定义和添加从命令行中被Manager实例调用的命令
结合的简单使用
需求:现在,在 Role 数据表中需要添加一个新的属性(grace:级别),需要该怎么做,总不能将数据库删了重新建吧。
这里就需要用到这两个库了,做数据库的扩展
可以将代码写在 manage 文件下,与 models 文件同级
manage文件就是存放 关于数据库扩展的文件
from flask_migrate import Migrate, MigrateCommand
from flask_script import Shell, Manager
from models import app, db, User, Role
# 用来管理命令的对象, Manager用来跟踪所有名林不过并处理他们如何从命令行调用;
manager = Manager(app)
migrate = Migrate(app, db)
# 添加一条数据库管理的命令
manager.add_command('db', MigrateCommand)
# 实现添加用户的命令
if __name__ == "__main__":
# 准备
manager.run()
不用运行,manager文件读取该文件就行了
执行 db 参数后,可得到下列的命令,用来对 models 中建立的数据库操作
(2048) [kiosk@foundation69 day30]$ python manage.py db
usage: Perform database migrations
Perform database migrations
positional arguments:
{init,revision,migrate,edit,merge,upgrade,downgrade,show,history,heads,branches,current,stamp}
init Creates a new migration repository
revision Create a new revision file.
migrate Alias for 'revision --autogenerate'
edit Edit current revision.
merge Merge two revisions together. Creates a new migration
file
upgrade Upgrade to a later version
downgrade Revert to a previous version
show Show the revision denoted by the given symbol.
history List changeset scripts in chronological order.
heads Show current available heads in the script directory
branches Show current branch points
current Display the current revision for each database.
stamp 'stamp' the revision table with the given revision;
don't run any migrations
optional arguments:
-?, --help show this help message and exit
1).下来就是操作的三部曲了
(1) init : 初始化数据,创建迁移仓库
python manage.py db init
可以看到,创建了一个 migrations 目录,其中 versions 就记录着数据库的变迁
models 文件中,不是给 Role 数据表添加了一个 grace 属性
(2)migrate :增加属性
python manage.py db migrate -m "Role中添加属性grace"
其中: -m 可以指定此次操作的名称
可以看到 versions 文件中记录了此次的变化
(3)upgrade :数据库更新此次变化
python manage.py db upgrade
2). 当然,此库还有一个强大的功能就在于,可以返回原先的操作
从历史中可以查看到,对原先的数据库(base),做了更改
退回base状态:
从数据库中查看结果:
可以明显的看到更改前后的不同之处
3). 当然你也可以自定义一些操作
使用装饰器来装饰你的函数
(1)manager.command
@manager.command
def showUser():
"""显示所有的用户"""
users = User.query.all()
print(users[:5])
# 由于用户太多了,这里只显示前5个
可以看到这里多个一个位置参数,用来显示所有的用户
调用这个参数,就可以显示所有的用户了
(2)manager.option
同 command 不同的点在于,此方法可以传递参数
比如说添加一个角色:
@manager.option('-n', '--name', help="角色名称")
def add_role(name):
try:
role1 = Role(name=name)
db.session.add(role1)
db.session.commit()
except Exception:
print("创建用户角色失败!")
else:
print("创建用户角色%s成功!" %(name))
第一行括号里面可以写成帮助文档,用来执行命令
就像 ls 命令一样
第一个为缩写,第二个为全称,第三个为帮助文档
创建白金会员成功,当然假如创建已经存在的,当然会失败了
关于Flask框架的一些基本内容就说到这了。