使用 Blueprint 要注意 render_template 函數

此文章主要是爲了記錄在使用 Flask 的過程當中遇到的問題。本章主要討論 render_template 函數的問題。

使用 Flask 的同窗都應該知道,項目中的 url 和視圖函數是在字典裏一一對應着的,再詳細一點,就是 url 對應着 endpoint,視圖函數也對應着 endpoint,而且 endpoint 在字典裏是惟一存在的。css

而對於不一樣 Blueprint 裏的 url,是依靠所註冊的藍圖以及不一樣的前綴來進行區分。可是在視圖函數中所調用的 render_template 函數可得不到 endpoint 的支持,若是你使用的不一樣目錄下的同樣命名的模板文件,那麼就會出現問題了。html

先擺事實、再講道理。python

明瞭問題所在

實例項目的目錄結構以下:flask

app
├── admin
│   ├── errors.py
│   ├── forms.py
│   ├── __init__.py
│   ├── static
│   │   ├── css
│   ├── templates
│   │   ├── index.html
│   ├── views.py
├── __init__.py
├── main
│   ├── errors.py
│   ├── forms.py
│   ├── __init__.py
│   ├── templates
│   │   └── ousi
│   │       ├── index.html
│   │       ├── static
│   │       │   ├── css
│   ├── views.py
├── models.py

該項目中註冊兩個 Blueprint,即 admin 是所謂的後臺管理藍圖,main 是所謂的前臺展現藍圖。
藍圖 admin 的 __init__.py 內容以下:app

# -*- coding:utf-8 -*-
__author__ = '東方鶚'


from flask import Blueprint

admin = Blueprint('admin', __name__, template_folder="templates", static_folder='static')

# 在末尾導入相關模塊,是爲了不循環導入依賴,由於在下面的模塊中還要導入藍本main
from . import views, errors

藍圖 main 的 __init__.py 內容以下:函數

# -*- coding:utf-8 -*-
__author__ = '東方鶚'


from flask import Blueprint


main = Blueprint('main', __name__, template_folder="templates/ousi",
                                 static_folder='templates/ousi/static')

# 在末尾導入相關模塊,是爲了不循環導入依賴,由於在下面的模塊中還要導入藍本main
from . import views, errors

在定義兩個藍圖的時候,也對本藍圖所對應的模板文件夾和靜態文件夾進行了定義,此文主要關注模板文件夾測試

那麼,如今就說說出現了什麼問題。ui

在各自藍圖的視圖函數中都對主頁 '/' 或叫作 'index' 進行了定義。url

其中,藍圖 admin 的視圖函數定義以下:code

@admin.route('/', methods=['GET', 'POST'])
@login_required
def index():

    return render_template('index.html')

請記住最後的代碼,即 render_template('index.html'),此處調用的模板名叫作 index.html

藍圖 admin 的視圖函數定義以下:

@main.route('/', methods=['GET', 'POST'])
def index():

    return render_template('index.html')

請記住最後的代碼,即 render_template('index.html'),此處調用的模板名叫作 index.html

到此,你發現了什麼,你發現了什麼,我估計你已經看出來兩個視圖函數的最後一行代碼是同樣的,說得再精確點,調用的模板名是同樣的。可是此處咱們要保持清醒,雖然模板名稱同樣,可是所在目錄是不同的,它們所處的位置是各自所在的藍圖所定義的模板文件夾裏。

說了這麼多,到底怎麼了呢。

這時,若是你測試一下你的程序的話,你會發現兩個藍圖所顯示的內容是同樣的,無論你相信不相信本身的眼睛,它就是同樣的界面,並且絕對同樣,由於 render_template('index.html') 調用的是同一個模板,它可不會區分藍圖。

那麼,到底調用的是那個藍圖下的模板呢??繼續往下看。

這時你打開 app/__init__.py,內容以下:

def create_app(config_name):
    """ 使用工廠函數初始化程序實例"""
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app=app)

    # mail.init_app(app=app)
    moment.init_app(app=app)
    db.init_app(app=app)
    md.init_app(app=app)
    login_manager.init_app(app=app)

    # 註冊藍本 main
    from .main import main as main_blueprint
    app.register_blueprint(main_blueprint, url_prefix='/main')

    # 註冊藍本 admin
    from .admin import admin as admin_blueprint
    app.register_blueprint(admin_blueprint, url_prefix='/admin')

    # 註冊藍本 main
    #from .main import main as main_blueprint
    #app.register_blueprint(main_blueprint, url_prefix='/dynamic')

    return app

到底調用的是那個藍圖下的模板呢??

這個,我能夠明確告訴你,main 和 admin 兩個藍圖,哪一個在 app/__init__.py 中先註冊,就調用那個藍圖的模板,也就是說哪一個藍圖註冊時所用的代碼寫得靠上,就調用那個藍圖的模板。

這究竟是爲何呢?爲何呢?這是 flask 項目的一個小 bug。寫項目的時候,要注意此坑,render_template() 函數裏所調用的模板必定要保證命名在整個項目中的惟一性。

號外,號外

今天又發現了一個坑,就是 jinja2 內部的模板調用,好比 include 某某模板的時候,這個被調用的模板名稱也須要,並且強烈須要保證在整個項目,記住是整個項目中,其命名要具備惟一性。

相關文章
相關標籤/搜索