Flask 抛出 TemplateNotFound 错误即使模板文件存在
我正在尝试渲染一个文件 home.html
。这个文件在我的项目里确实存在,但每次我尝试渲染它时,总是出现 jinja2.exceptions.TemplateNotFound: home.html
的错误。为什么Flask找不到我的模板呢?
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return render_template('home.html')
/myproject
app.py
home.html
18 个回答
如果你是从一个已安装的包里运行你的代码,记得确保模板文件在这个目录下:<python root>/lib/site-packages/your-package/templates
。
一些细节:
在我的情况下,我试图运行项目flask_simple_ui的示例代码,结果jinja
总是提示我
jinja2.exceptions.TemplateNotFound: form.html
问题在于,示例程序会导入已安装的包flask_simple_ui
。而在这个包内部使用的jinja
,它查找模板文件的根目录是这个包的路径,也就是...python/lib/site-packages/flask_simple_ui
,而不是大家通常期待的os.getcwd()
。
不幸的是,setup.py
有个bug,没有复制任何html文件,包括缺失的form.html
。一旦我修复了setup.py
,TemplateNotFound的问题就消失了。
希望这能帮助到某些人。
我不知道为什么,但我不得不使用下面这种文件夹结构。我把“templates”文件夹放到上一级。
project/
app/
hello.py
static/
main.css
templates/
home.html
venv/
这可能说明其他地方的设置有问题,但我搞不清楚是什么问题,不过这样做是有效的。
如果你需要使用一个自定义的项目目录结构(也就是和大家常用的项目结构不一样),我们可以告诉Flask去合适的目录层级找文件。
比如说……
app = Flask(__name__, template_folder='../templates')
app = Flask(__name__, template_folder='../templates', static_folder='../static')
以 ../
开头表示向上移动一个目录,然后从那里开始。
以 ../../
开头表示向上移动两个目录,然后从那里开始(以此类推……)。
在一个子目录中……
template_folder='templates/some_template'
我觉得Flask默认使用的是一个叫做template
的文件夹。所以你的代码应该像这样写:
假设你的文件名是hello.py
:
from flask import Flask,render_template
app=Flask(__name__,template_folder='template')
@app.route("/")
def home():
return render_template('home.html')
@app.route("/about/")
def about():
return render_template('about.html')
if __name__=="__main__":
app.run(debug=True)
然后你的工作空间结构应该是这样的:
project/
hello.py
template/
home.html
about.html
static/
js/
main.js
css/
main.css
另外,你还需要创建两个HTML文件,分别命名为home.html
和about.html
,并把这两个文件放在templates
文件夹里。
你需要把模板文件放在正确的位置,也就是在和你的Python模块同级的templates
子目录下(这个模块就是你创建Flask应用的地方)。
错误提示说明在templates/
目录里找不到home.html
文件。确保你在和Python模块同一个目录下创建了这个目录,并且确实在这个子目录里放了home.html
文件。如果你的应用是一个包,那么模板文件夹应该放在包的内部。
myproject/
app.py
templates/
home.html
myproject/
mypackage/
__init__.py
templates/
home.html
另外,如果你把模板文件夹命名成了其他名字,而不想改回默认的templates
,你可以告诉Flask使用那个其他的目录。
app = Flask(__name__, template_folder='template') # still relative to module
你可以通过把EXPLAIN_TEMPLATE_LOADING
选项设置为True
,让Flask解释它是如何寻找某个模板的。每次加载模板时,都会在Flask
中记录一条信息,记录级别为app.logger
INFO
。
如果搜索成功,记录的内容大概是这样的;在这个例子中,foo/bar.html
模板扩展了base.html
模板,所以会进行两次搜索:
[2019-06-15 16:03:39,197] INFO in debughelpers: Locating template "foo/bar.html":
1: trying loader of application "flaskpackagename"
class: jinja2.loaders.FileSystemLoader
encoding: 'utf-8'
followlinks: False
searchpath:
- /.../project/flaskpackagename/templates
-> found ('/.../project/flaskpackagename/templates/foo/bar.html')
[2019-06-15 16:03:39,203] INFO in debughelpers: Locating template "base.html":
1: trying loader of application "flaskpackagename"
class: jinja2.loaders.FileSystemLoader
encoding: 'utf-8'
followlinks: False
searchpath:
- /.../project/flaskpackagename/templates
-> found ('/.../project/flaskpackagename/templates/base.html')
蓝图(Blueprints)也可以注册自己的模板目录,但如果你使用蓝图来更好地将一个大项目拆分成逻辑单元,这并不是必须的。即使使用蓝图的额外路径,Flask应用的主模板目录总是会被优先搜索。