此文章主要是爲了記錄在使用 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 某某模板的時候,這個被調用的模板名稱也須要,並且強烈須要保證在整個項目,記住是整個項目中,其命名要具備惟一性。