使用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函數,該函數的功能是向模板頁面發送一消息,它接受兩個參數,消息的內容和分類,最后重定向到登陸頁面。
