使用flask-migrate
almebic是一个数据库版本管理的工具,在对一个数据表进行添加列,删除列的时候相当于进行了数据库版本的改变。flask-migrate是对almbic进行的封装,方便在flask中使用alembic管理数据库。
使用flask-migrate首先要在create_app的时候将它注册到app上。
from flask_migrate import Migrate def create_app(config): app = Flask(__name__) app.config.from_object(configs.get(config)) db.init_app(app) Migrate(app, db) register_blueprints(app) return app
配置后完成运行
flask db
第一次使用需要进行初始化
flask db init
运行:
flask db migrate -m 'init database'
这个命令会在version目录下生成一个数据库升级脚本,-m后是本次提交的相关信息,检查无误后可以运行
flask db upgrade
将升级写入数据库
使用flask-wtf
wtforms是python实现的一个库,它能在python和HTML form之间建立一种映射关系,类似ORM,方便创建表单和在模板中渲染表单。flask-wtf则是对wtforms的封装,方便在flask中使用wtforms,并在wtforms的基础上添加了crsf token的生成和验证机制。使用flask-wtf,需要定义的表单中继承flask-wtf提供的FlaskForm基类,并为每一个表单输入一个声明字段。
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField, BooleanField from wtforms.validators import Length, Email, EqualTo, Required class RegisterForm(FlaskForm): username = StringField('用户名', validators=[Required(), Length(3, 24)]) email = StringField('邮箱', validators=[Required(), Email()]) password = PasswordField('密码', validators=[Required(), Length(6, 24)]) repeat_password = PasswordField('重复密码', validators=[Required(), EqualTo('password')]) submit = SubmitField('提交') class LoginForm(FlaskForm): email = StringField('邮箱', validators=[Required(), Email()]) password = PasswordField('密码', validators=[Required(), Length(6, 24)]) remember_me = BooleanField('记住我') submit = SubmitField('提交')
要在Form类为每个输入框声明一个对应的Field,Field一般提供两个参数,第一个是输入框html中的label,第二个一般是validators(验证器)。validators是一个列表,可以放入多个验证器,表单提交时,wtforms会使用列表里的验证器对提交的数据进行验证,验证失败的数据,wtforms会将失败信息写入Field下的errors列表下。
在注册路由的python文件中将相应的form传递到模板中
from **.forms import LoginForm, RegisterForm @front.route('/login') def login(): form = LoginForm() return render_template('login.html', form=form)
然后在login.html中进行表单的渲染。
{% extends "base.html" %} {% block title %} Login {% endblock %} {% block body %} <h2>登录</h2> <!-- 要在 form 里指定 POST 方法和点击提交后需要请求的 url --> <form method="POST" action="{{ url_for('front.login') }}"> <!-- flask-wtf 帮我们在表单类中添加了 csrf_token,我们只要简单的渲染就可以了, 渲染后会在 hmtl 页面生成一个隐藏域,里面是 csrf_token 值 --> {{ form.csrf_token }} <!-- 使用 Bootstrap 的表单样式渲染每个表单项 --> <div class="form-group"> <!-- 首先渲染 field label --> <!-- 接着渲染 field,StringField 渲染后会生成一个 <input> 标签,field 里面可以传入 html 的标签属性,这些属性会渲染到生成的 html 标签中 --> {{ form.email.label }} {{ form.email(class='form-control') }} </div> <div class="form-group"> {{ form.password.label }} {{ form.password(class='form-control') }} </div> <!-- BooleanField 的渲染有些特殊,使用了 Bootstrap 的 checkbox 类--> <div class="checkbox"> <label> {{ form.remember_me() }} <!-- 注意这里获取的是 label 的 text 属性,也就是我们在表单中定义的"记住我"这个字符串--> {{ form.remember_me.label.text }} </label> </div> <!-- 渲染提交按钮,传入 Bootstrap 的按钮类--> {{ form.submit(class="btn btn-primary") }} </form> {% endblock %}
由于在同一个网站中的表单结构和内容是相似的,因此可以使用macro对重复的动作进行封装,使用的是jinjia2的语法。
{% macro macro_name(arg1, arg2, ...)%}
....
{% endmacro %}
macro通常存放在macro.html中,使用该文件的某个macro时,使用Import导入即可
{% from "macro.html" import macro_name %}
使用{{}}格式语法进行调用
{{ macro_name(arg1, arg2 )}}
下面是一个render_form的宏用于渲染表单
<!-- 需要传入2个参数:要渲染的 form 和点击提交请求的 url --> {% macro render_form(form, url) %} <form method="POST" action="{{ url }}"> <!-- 将 csrf_token 渲染在表单开始的位置 --> {{ form.csrf_token }} <!-- 迭代每个表单 field --> {% for field in form %} <!-- 如果是 csrf_token 就不再渲染了 --> {% if field.type == 'CSRFTokenField' %} {{ '' }} <!-- SubmitField 单独特殊处理 --> {% elif field.type == 'SubmitField' %} {{ form.submit(class='btn btn-primary', type='submit') }} <!-- BooleanField 单独特殊处理 --> {% elif field.type == 'BooleanField' %} <div class="checkbox"> <label>{{ field() }} {{ field.label.text }}</label> </div> {% else %} <div class="form-group"> {{ field.label }} {{ field(class='form-control') }} </div> {% endif %} {% endfor %} </form> {% endmacro %}
将login.html使用render_form渲染:
{% extends "base.html" %} {% from "macros.html" import render_form %} {% block title %}Login{% endblock %} {% block body %} <div class="form"> <h2>登录</h2> {{ render_form(form, url_for('front.login')) }} </div> {% endblock %}
然后在RegisterForm下实现根据表单提交的数据创建用户
from simpledu.models import db, User class RegisterForm(FlaskForm): ... def create_user(self): user = User() user.username = self.username.data user.email = self.email.data user.password=self.password.data db.session.add(user) db.session.commit() return user
在front.py中实现注册功能的路由处理函数:
from flask import flash from flask import redirect,url_for @front.route('/register', methods=['GET', 'POST']) def register(): form = RegisterForm() if form.validate_on_submit(): form.create_user() flash('注册成功,请登录!', 'success') return redirect(url_for('.login')) return render_template('register.html', form=form)
validate_on_submit是flask-wtf提供的FlaskForm中封装的一个方法,返回值是一个布尔值。如果表单提交了并且我们在对应的form中声明的表单数据验证器对用户提交的表单数据验证通过,那么该方法返回True,否则返回False。
上面的代码中,表单提交并且数据验证成功后,条用我们之前实现的方法创建用户。有时候,网站需要对用户的一些操作给出成功、失败、警告等一系列反馈,我们调用了flash函数,该函数的功能是向模板页面发送一消息,它接受两个参数,消息的内容和分类,最后重定向到登陆页面。