Flask之測試與部署

5.1 藍圖Blueprint

爲何學習藍圖?

咱們學習Flask框架,是從寫單個文件,執行hello world開始的。咱們在這單個文件中能夠定義路由、視圖函數、定義模型等等。但這顯然存在一個問題:隨着業務代碼的增長,將全部代碼都放在單個程序文件中,是很是不合適的。這不只會讓代碼閱讀變得困難,並且會給後期維護帶來麻煩。html

以下示例:咱們在一個文件中寫入多個路由,這會使代碼維護變得困難。python

    from flask import Flask    
    app = Flask(__name__)    
    @app.route('/')
    def index():
        return 'index'

    @app.route('/list')
    def list():
        return 'list'

    @app.route('/detail')
    def detail():
        return 'detail'

    @app.route('/')
    def admin_home():
        return 'admin_home'

    @app.route('/new')
    def new():
        return 'new'

    @app.route('/edit')
    def edit():
        return 'edit'

問題:一個程序執行文件中,功能代碼過多。就是讓代碼模塊化。根據具體不一樣功能模塊的實現,劃分紅不一樣的分類,下降各功能模塊之間的耦合度。python中的模塊製做和導入就是基於實現功能模塊的封裝的需求。mysql

嘗試用模塊導入的方式解決: 咱們把上述一個py文件的多個路由視圖函數給拆成兩個文件:app.py和admin.py文件。app.py文件做爲程序啓動文件,由於admin文件沒有應用程序實例app,在admin文件中要使用app.route路由裝飾器,須要把app.py文件的app導入到admin.py文件中。sql

# 文件app.py
from flask import Flask
# 導入admin中的內容
from admin import *
app = Flask(__name__)

@app.route('/')
def index():
    return 'index'

@app.route('/list')
def list():
    return 'list'

@app.route('/detail')
def detail():
    return 'detail'

if __name__ == '__main__':
    app.run()

# 文件admin.py    
from app import app
@app.route('/')
def admin_home():
    return 'admin_home'

@app.route('/new')
def new():
    return 'new'

@app.route('/edit')
def edit():
    return 'edit'

啓動app.py文件後,咱們發現admin.py文件中的路由都沒法訪問。 也就是說,python中的模塊化雖然能把代碼給拆分開,但不能解決路由映射的問題。數據庫

什麼是藍圖?

藍圖:用於實現單個應用的視圖、模板、靜態文件的集合。flask

藍圖就是模塊化處理的類。session

簡單來講,藍圖就是一個存儲操做路由映射方法的容器,主要用來實現客戶端請求和URL相互關聯的功能。 在Flask中,使用藍圖能夠幫助咱們實現模塊化應用的功能。app

藍圖的運行機制:

藍圖是保存了一組未來能夠在應用對象上執行的操做。註冊路由就是一種操做,當在程序實例上調用route裝飾器註冊路由時,這個操做將修改對象的url_map路由映射列表。當咱們在藍圖對象上調用route裝飾器註冊路由時,它只是在內部的一個延遲操做記錄列表defered_functions中添加了一個項。當執行應用對象的 register_blueprint() 方法時,應用對象從藍圖對象的 defered_functions 列表中取出每一項,即調用應用對象的 add_url_rule() 方法,這將會修改程序實例的路由映射列表。框架

藍圖的使用:

1、建立藍圖對象。模塊化

#Blueprint必須指定兩個參數,admin表示藍圖的名稱,__name__表示藍圖所在模塊
admin = Blueprint('admin',__name__)

2、註冊藍圖路由。

@admin.route('/')
def admin_index():
    return 'admin_index'

3、在程序實例中註冊該藍圖。

app.register_blueprint(admin,url_prefix='/admin')

文件目錄:

程序執行文件/test4/test.py

from flask import Flask
#導入藍圖對象
from login import logins
from user import users

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'
#註冊藍圖,第一個參數logins是藍圖對象,url_prefix參數默認值是根路由,若是指定,會在藍圖註冊的路由url中添加前綴。
app.register_blueprint(logins,url_prefix='')
app.register_blueprint(users,url_prefix='')

if __name__ == '__main__':
    app.run(debug=True)

建立藍圖:/test4/user.py

from flask import Blueprint,render_template
#建立藍圖,第一個參數指定了藍圖的名字。
users = Blueprint('user',__name__)

@users.route('/user')
def user():
    return render_template('user.html')

建立藍圖:/test4/login.py

from flask import Blueprint,render_template
#建立藍圖
logins = Blueprint('login',__name__)

@logins.route('/login')
def login():
    return render_template('login.html')

運行/test4/test.py文件

動態路由示例(做者--圖書):

文件目錄:Flask_test4/delete.py

from flask import Blueprint,redirect,url_for
app_au = Blueprint('app_au',__name__)
app_bk = Blueprint('app_bk',__name__)

from test4 import *

@app_au.route('/delete_au<id>')
def delete_au(id):
    del_au = Author.query.filter_by(id=id).first()
    db.session.delete(del_au)
    db.session.commit()
    return redirect(url_for('index'))

@app_bk.route('/delete_bk<id>')
def delete_bk(id):
    del_bk = Book.query.filter_by(id=id).first()
    db.session.delete(del_bk)
    db.session.commit()
    return redirect(url_for('index'))

文件目錄:Flask_test4/test4.py

#coding=utf-8
#目的:建立兩個模型類型,實現數據庫的鏈接和數據的操做
from flask import Flask,render_template,request,redirect,url_for
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms import StringField,SubmitField
from wtforms.validators import DataRequired
#導入delete文件中的藍圖對象
from delete import app_au,app_bk

app = Flask(__name__)
#對數據庫鏈接的基本設置
app.config['SQLALCHEMY_DATABASE_URI']='mysql://root:mysql@localhost/test0'
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#把應用程序的實例和SQLAlchemy進行關聯
db = SQLAlchemy(app)
app.config['SECRET_KEY'] = 'a'

#自定義表單,實現數據的輸入保存操做
class Append(FlaskForm):
    author = StringField(validators=[DataRequired()])
    book = StringField(validators=[DataRequired()])
    submit = SubmitField(u'提交')

#自定義模型類
class Author(db.Model):
    __tablename__ = 'authors'
    id = db.Column(db.Integer,primary_key=True)
    name = db.Column(db.String(32),unique=True)

    def __repr__(self):
        return 'author:%s'%self.name

class Book(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer,primary_key=True)
    info = db.Column(db.String(32),unique=True)
    def __repr__(self):
        return 'book:%s'%self.info

@app.route('/',methods=['GET','POST'])
def index():
    au = Author.query.all()
    bk = Book.query.all()
    form = Append()
    if form.validate_on_submit():
        #從表單中獲取數據
        wtf_au = form.author.data
        wtf_bk = form.book.data
        #把數據存入模型類中
        db_au = Author(name=wtf_au)
        db_bk = Book(info=wtf_bk)
        #添加到數據庫操做
        db.session.add_all([db_au,db_bk])
        db.session.commit()
        au = Author.query.all()
        bk = Book.query.all()
        return render_template('index.html',au=au,bk=bk,form=form)

    if request.method == 'GET':
        return render_template('index.html',au=au,bk=bk,form=form)

#註冊藍圖
app.register_blueprint(app_au)
app.register_blueprint(app_bk)

if __name__ == '__main__':    
    print app.url_map
    app.run(debug=True)

查看藍圖路由:藍圖路由能夠分爲兩塊,"."前面的是藍圖名稱,"."後面的是視圖函數名。

相關文章
相關標籤/搜索