JinJa2模板
-
模板基本语法:
{% if user %} {{ user }} {% else %} hello! <ul> {% for index in indexs %} <li> {{ index }} </li> {% endfor %} </ul>
-
在Flask中,用
render_template()
来渲染模板-
return render_template('index.html') # 可以在里面传变量 return render_template('index.html', name='fxh', age=21)
-
也可以像 Django 一样传变量,但需要用
**
data = { "name": "python", "age": 18, "my_dict": {"city": "sz"}, "my_list": [1, 2, 3, 4, 5], "my_int": 0 } return render_template("index.html", **data)
-
-
在 Flask 中,模板变量可以进行加减运算的
<body> <p>name = {{ name }}</p> <p>age = {{ age }}</p> <p>my_dict: city= {{ my_dict["city"] }}</p> <p>my_dict: city= {{ my_dict.city }}</p> <p>my_list: {{ my_list }}</p> <p>my_list[my_int]: {{ my_list[my_int] }}</p> <p>my_list[0] + my_list[1] = {{ my_list[0] + my_list[1] }}</p> <p>{{"hello" + " python" }}</p> </body>
过滤器
-
过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,这就用到了过滤器
-
使用方法:{{ ‘hello’ | 过滤器名}}
-
字符串过滤器:
过滤器 功能 safe 禁用转义—>可以防止xss攻击 capitalize 首字母大写,其余字母小写 lower 把值转成小写 upper 把值转成大写 title 把值中的每个单词的首字母都转成大写 trim 把值的首尾空格去掉 reverse 字符串反转 format 格式化输出 striptags 渲染之前把值中所有的HTML标签都删掉 过滤器可以叠加使用,
{{ 'hello' | trim | upper }}
-
列表过滤器:
过滤器 功能 first 取第一个元素 last 取最后一个元素 length 获取列表长度 sum 列表求和 sort 列表排序 -
自定义过滤器
-
法一:通过
add_template_filter (过滤器函数, 模板中使用的过滤器名字)
def filter_double_sort(ls): return ls[::2] app.add_template_filter(filter_double_sort, 'double_2')
-
法二:通过装饰器
app.template_filter (模板中使用的装饰器名字)
@app.template_filter('db3') # db3为过滤器名 def filter_double_sort(ls): return ls[::-3]
-
表单
-
表单是HTML页面中负责数据采集的部件。表单有三个部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。
-
不使用Flask-WTF时,我们还需要自己去处理表单
from flask import Flask,render_template,request @app.route('/login',methods=['GET','POST']) def login(): if request.method == 'POST': username = request.form['username'] password = request.form['password'] print username,password return 'success' else: pass
-
使用Flask-WTF 表单扩展,可以帮助进行CSRF验证,帮助我们快速定义表单模板,而且可以帮助我们在视图中验证表单的数据
-
安装:
pip install Flask-WTF
-
WTForms支持的HTML标准字段
字段对象 说明 StringField 文本字段 TextAreaField 多行文本字段 PasswordField 密码文本字段 HiddenField 隐藏文本字段 DateField 文本字段,值为datetime.date格式 DateTimeField 文本字段,值为datetime.datetime格式 IntegerField 文本字段,值为整数 DecimalField 文本字段,值为decimal.Decimal FloatField 文本字段,值为浮点数 BooleanField 复选框,值为True和False RadioField 一组单选框 SelectField 下拉列表 SelectMultipleField 下拉列表,可选择多个值 FileField 文本上传字段 SubmitField 表单提交按钮 FormField 把表单作为字段嵌入另一个表单 FieldList 一组指定类型的字段 -
WTForms常用验证函数
验证函数 说明 DataRequired 确保字段中有数据 EqualTo 比较两个字段的值,常用于比较两次密码输入 Length 验证输入的字符串长度 NumberRange 验证输入的值在数字范围内 URL 验证URL AnyOf 验证输入值在可选列表中 NoneOf 验证输入值不在可选列表中
表单模型类
-
定义表单模型类
#导入wtf扩展的表单类 from flask_wtf import FlaskForm #导入自定义表单需要的字段 from wtforms import SubmitField,StringField,PasswordField class RegisterForm(Flask Form): '''自定义注册表单类,文本字段、密码字段、提交按钮''' # DataRequired 保证数据必须填写,并且不能为空 user_name = StringField(label=u"用户名", validators=[DataRequired(u"用户名不能为空")]) pw = PasswordField(label=u"密码", validators=[DataRequired(u"密码不能为空")]) pw2 = PasswordField(label=u"确认密码", validators=[DataRequired(u"确认密码不能为空"), EqualTo("password", u"两次密码不一致")]) submit = SubmitField(label=u"提交")
label
:名字,validators
:验证器,DataRequired(u'用户名不为空')
传的参数为提示信息 -
使用
@app.route('/register') def register(): # 创建表单对象,如果是post请求,前端发送了数据,flask会把数据在构造form对象的时候,存放到对象中 form = RegisterForm() # 判断form中的数据是否合理 # 如果form中的数据完全满足所有的验证器,则返回真,否则返回假 if form.validate_on_submit(): # 表示验证合格 # 提取数据 uname = form.user_name.data pwd = form.password.data pwd2 = form.password2.data print(uname, pwd, pwd2) session["user_name"] = uname return redirect(url_for("index")) return render_template("register.html", form=form)
-
模板文件中
<form method="post"> # 设置csrf_token {{ form.csrf_token() }} {{ form.user_name.label }} <p>{{form.user_name}}</p> {% for msg in form.user_name.errors %} # 显示错误的提示信息 <p>{{msg}}</p> {% endfor %} {{ form.pw.label }} <p>{{form.pw}}</p> {% for msg in form.pw.errors %} <p>{{msg}}</p> {% endfor %} {{ form.pw2.label }} <p>{{form.pw2}}</p> {% for msg in form.pw2.rrors %} <p>{{msg}}</p> {% endfor %} {{form.submit}} </form>
-
要注意的是,因为有CSRF验证,所以还需配置SECRET_KEY参数
app.config['SECRET_KEY'] = 'dasdasfdasx'
-
表单校验时,如果form中的数据完全满足所有的验证器,则返回True,否则返回False
宏
-
类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余
-
Jinja2支持宏,还可以导入宏,需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复
-
不带参数的宏
{% macro input() %} # macro相当于def,后面为宏的名字 <input type="text" name="username" value="" size="30"/> {% endmacro %}
- 调用宏:
{{ input() }}
- 调用宏:
-
带参数的宏
{% macro input(name,value='',type='text',size=20) %} <input type="{{ type }}" name="{{ name }}" value="{{ value }}" size="{{ size }}"/> {% endmacro %}
- 调用:
{{ input(value='name',type='password',size=40) }}
- 调用:
-
把宏单独封装在HTML文件中
-
如封装在
macro.html
文件中{% macro function() %} <input type="text" name="username" placeholde="Username"> <input type="password" name="password" placeholde="Password"> <input type="submit"> {% endmacro %}
-
在其他文件中,先导入再调用
{% import 'macro.html' as func %} {% func.function() %}
-
模板继承
-
与django的一样
{% block xxx %} {% endlock %}
包含
- 它的功能是将另一个模板整个加载到当前模板中,并直接渲染
{% include 'hello.html' %}
- 如该模板文件不存在,则会抛出异常,加上
ignore missing
时,则会忽略包含语句{% include 'hello.html' ignore missing %}
数据库
-
SQLAlchemy是一个关系型数据库框架,flask-sqlalchemy则是一个简化版
-
安装:
pip install flask-sqlalchemy pip install flask-mysqldb
-
配置使用Flask-SQLAlchemy来管理数据库
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test3'
-
数据库的初始化配置
class Config(object): """配置参数""" # sqlalchemy的配置参数 SQLALCHEMY_DATABASE_URI = "mysql://root:mysql@127.0.0.1:3306/db_python04" # 设置sqlalchemy自动更跟踪数据库 SQLALCHEMY_TRACK_MODIFICATIONS = True app.config.from_object(Config) # 创建数据库sqlalchemy工具对象 db = SQLAlchemy(app)
- 然后可以直接用db来操作数据库
-
常用的SQLAlchemy字段类型
类型名 python中类型 说明 Integer int 普通整数,一般是32位 SmallInteger int 取值范围小的整数,一般是16位 BigInteger int或long 不限制精度的整数 Float float 浮点数 Numeric decimal.Decimal 普通整数,一般是32位 String str 变长字符串 Text str 变长字符串,对较长或不限长度的字符串做了优化 Unicode unicode 变长Unicode字符串 UnicodeText unicode 变长Unicode字符串,对较长或不限长度的字符串做了优化 Boolean bool 布尔值 Date datetime.date 时间 Time datetime.datetime 日期和时间 LargeBinary str 二进制文件 -
常用的SQLAlchemy列选项
选项名 说明 primary_key 如果为True,代表表的主键 unique 如果为True,代表这列不允许出现重复的值 index 如果为True,为这列创建索引,提高查询效率 nullable 如果为True,允许有空值,如果为False,不允许有空值 default 为这列定义默认值 -
常用的SQLAlchemy关系选项
选项名 说明 backref 在关系的另一模型中添加反向引用 primary join 明确指定两个模型之间使用的联结条件 uselist 如果为False,不使用列表,而使用标量值 order_by 指定关系中记录的排序方式 secondary 指定多对多中记录的排序方式 secondary join 在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件
创建模型类
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
class Config(object):
"""配置参数"""
# sqlalchemy的配置参数
SQLALCHEMY_DATABASE_URI = "mysql://root:mysql@127.0.0.1:3306/db_python04"
# 设置sqlalchemy自动更跟踪数据库
SQLALCHEMY_TRACK_MODIFICATIONS = True
app.config.from_object(Config)
# 创建数据库sqlalchemy工具对象
db = SQLAlchemy(app)
class Role(db.Model):
"""用户角色/身份表"""
__tablename__ = "tbl_roles" # 指明数据库的表名
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32), unique=True)
users = db.relationship("User", backref="role")
# 表名的常见规范:数据库名缩写_表名
# 创建数据库模型类
class User(db.Model):
"""用户表"""
__tablename__ = "tbl_users"
id = db.Column(db.Integer, primary_key=True) # 整型的主键,会默认设置为自增主键
name = db.Column(db.String(64), unique=True)
email = db.Column(db.String(128), unique=True)
password = db.Column(db.String(128))
role_id = db.Column(db.Integer, db.ForeignKey("tbl_roles.id"))
id = db.Column(db.Integer, primary_key=True)
Integer为字段类型,primary_key相当于约束;
users = db.relationship("User", backref="role")
相当于给Role添加了一个users属性,方便从Role查询User中的信息,backref="role"
反向应用,相当于是给User添加了一个role属性,方便反过来查询
role_id
为外键,db.ForeignKey("tbl_roles.id")
指明与哪张表哪个字段关联
-
自定义显示信息
-
在模型类中
def __repr__(self): """定义之后,可以让显示对象的时候更直观""" return "Role object: name=%s" % self.name
-
创建数据库表
-
Flask开始没有像Django的终端命令创建数据库表,锝用到扩展才行,要创建数据库表,可以用
# 清除数据库里的所有数据(第一次,里面可能会有垃圾数据,之后就慎用) db.drop_all() # 创建所有的表 db.create_all()
数据操作
-
增
# 创建对象 role1 = Role(name="admin") # session记录对象任务 db.session.add(role1) # 提交任务到数据库中 db.session.commit() role2 = Role(name="stuff") db.session.add(role2) db.session.commit() us1 = User(name='wang', email='wang@163.com', password='123456', role_id=role1.id) us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=role2.id) us3 = User(name='chen', email='chen@126.com', password='987654', role_id=role2.id) us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=role1.id) # 一次保存多条数据 db.session.add_all([us1, us2, us3, us4]) db.session.commit()
-
查询
Role.query.all() # 查询所有,它返回的结果是Role的对象 Role.query.first() # 查询第一条 Role.query.get(2) # 根据主键id获取对象,若不存在,Django会报错,而Flask中则为None # 另一种查询方式 db.session.query(Role).all() # 过滤器 User.query.filter_by(name="fxh").all() User.query.filter_by(name="wang", role_id=2).first() User.query.filter(User.name=="wang", User.role_id==1).all()
-
模糊查询:or_、not_(相当与去反)
from sqlalchemy import not_ User.query.filter(not_(User.name=='chen')).all()
-
降序
User.query.order_by(User.id.desc()).all()
-
关联查询
role = Role.query.get(1) ro.users[0].name Role.query.get(user.role_id)
-
-
更新
-
查询后更改
user.name = 'fxh' db.session.add(user) db.session.commit()
-
查询时就更改
User.query.filter_by(name='fxh').updata({'name':'python'}) db.session.commit()
-
-
删除
user = User.query.get(2) db.session.delete(user) db.session.commit()
数据库迁移
-
在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库。最直接的方式就是删除旧表,但这样会丢失数据,这时就需要用到数据库的迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中
-
安装Flask-Migrate:
pip install flask-migrate
-
使用(database.html)
from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate,MigrateCommand from flask_script import Manager app = Flask(__name__) # 创建启动命令管理对象 manager = Manager(app) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test' # 设置sqlalchemy自动更跟踪数据库 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True db = SQLAlchemy(app) # 创建数据库迁移工具对象 Migrate(app,db) # 向启动命令管理对象中添加迁移命令 manager.add_command('db',MigrateCommand) #定义模型Role class Role(db.Model): pass #定义用户类 class User(db.Model): pass if __name__ == '__main__': manager.run()
Migrate(app,db)
:第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例;manager.add_command('db',MigrateCommand)
:manager是Flask-Script的实例,这条语句在flask-Script中添加一个名为db命令 -
创建迁移仓库(终端)
# 这个命令会创建migrations文件夹,所有迁移文件都放在里面。 python database.py db init # database.py为上面程序所在的文件
-
创建迁移脚本
#创建自动迁移脚本 python database.py db migrate -m 'initial migration'
该条语句会让迁移仓库中多一条迁移版本文件;等价与Django的*makemigations
*
-m
后面的为备注信息,可不加 -
更新数据库
# 把迁移文件同步到数据库中 python database.py db upgrade
-
查看历史操作记录:
python database.py db history
-
回退数据库:
python database.py db downgrade 版本号