jinja2是一个用纯 python 编写的模板引擎。它提供受 Django启发的非 XML 语法,但支持内联表达式和可选的沙盒 环境。除了是一个易于使用的独立模板引擎之外,它体积小但速度快。 flask 是一个基于 Python 的微型 Web框架,可让您快速高效地编写 Web 应用程序。
在这个由三部分组成的系列中,我将从Flask 的角度介绍jinja2模板的基础知识。在本系列的后续部分中,我将介绍高级模板主题,同时学习如何在基于 Flask 的应用程序中以模块化和可扩展的设计布局模板。
我假设您对 Flask 和使用 virtualenv的环境设置最佳实践有基本的了解, 在开发 Python 应用程序时要遵循。
安装包
Flask 与 Jinja2 一起打包,因此我们只需要安装 Flask。对于本系列,我建议使用 Flask 的开发版本,它包括更稳定的命令行支持以及许多其他功能和对 Flask 的总体改进。
pip install https://github.com/mitsuhiko/flask/tarball/master
需要模板引擎?
在 Flask 中,我们可以编写一个完整的 Web 应用程序,而不需要任何第三方模板引擎。让我们看一下Hello World下面的一个小应用程序:
from flask import Flask app = Flask(__name__) @app.route('/') @app.route('/hello') @app.route('/hello/<user>') def hello_world(user=None): user = user or 'Shalabh' return ''' <html> <head> <title>Templating in Flask</title> </head> <body> <h1>Hello %s!</h1> <p>Welcome to the world of Flask!</p> </body> </html>''' % user if __name__ == '__main__': app.run()
很明显,上述编写应用程序的模式在 HTML、 css和 JS 代码在数千行代码范围内的真实 Web 应用程序中是不可行的。在这里,模板可以节省我们的时间,因为我们可以通过将模板分开来构造我们的视图代码。Flask 默认提供对 Jinja2 的支持,但任何其他模板引擎也可以根据需要使用。
布置模板
默认情况下,Flask期望将模板放置在以templates应用程序根级别命名的文件夹中。然后,Flask 通过使该文件夹可用于该render_template()方法来自动读取内容。我将通过重新构建上面显示的琐碎应用Hello World程序来证明这一点。
应用程序结构如下所示。
flask_app/ my_app.py templates/ - index.html
应用程序本身
烧瓶应用程序/my_app.py
from flask import Flask, render_template, request app = Flask(__name__) @app.route('/') @app.route('/hello') @app.route('/hello/<user>') def hello_world(user=None): user = user or 'Shalabh' return render_template('index.html', user=user)
flask_app/templates/index.html
<html> <head> <title>Templating in Flask</title> </head> <body> <h1>Hello {{ user }}!</h1> <p>Welcome to the world of Flask!</p> </body> </html>
要运行应用程序,只需在命令行上执行以下命令:
flask --app=my_app run
在浏览器中打开 http://127.0.0.1:5000/ 以查看正在运行的应用程序。在http://127.0.0.1:5000/hello的情况下,结果也是一样的 。
尝试以您的姓名作为最后一部分打开 URL。因此,如果您的名字是 John,那么 URL 将是 http://127.0.0.1:5000/hello/John。现在页面看起来像这样:
很简单,在该方法hello_world 中,URL after 的最后一部分hello 是从请求中获取的,并传递给正在渲染的模板的上下文render_template()。然后使用 Jinja2 占位符从模板上下文中解析该值{{ user }}。此占位符根据模板上下文评估放置在其中的所有表达式。
了解模板中的块和继承
通常,任何 Web 应用程序都会有许多彼此不同的网页。页眉和页脚等代码块在整个站点的几乎所有页面中都是相同的。同样,菜单也保持不变。事实上,通常只有中心容器块发生变化,其余部分通常保持不变。为此,Jinja2 提供了一种很好的模板间继承方式。拥有一个基本模板是一个很好的做法,我们可以在其中构建网站的基本布局以及页眉和页脚。
我将创建一个小应用程序来展示不同类别下的产品列表。对于样式,我将使用 Bootstrap框架为模板提供基本设计。应用程序结构现在如下图所示。
flask_app/ my_app.py templates/ - base.html - home.html - product.html static/ css/ - bootstrap.min.css - main.css js/ - bootstrap.min.js
在这里 static/css/bootstrap.min.css,static/js/bootstrap.min.js可以从上面提到的引导网站下载。其余的应用程序代码如下所示。
烧瓶应用程序/my_app.py
from flask import Flask, render_template, abort app = Flask(__name__) PRODUCTS = { 'iphone': { 'name': 'iPhone 5S', 'category': 'Phones', 'price': 699, }, 'galaxy': { 'name': 'Samsung Galaxy 5', 'category': 'Phones', 'price': 649, }, 'ipad-air': { 'name': 'iPad Air', 'category': 'Tablets', 'price': 649, }, 'ipad-mini': { 'name': 'iPad Mini', 'category': 'Tablets', 'price': 549 } } @app.route('/') @app.route('/home') def home(): return render_template('home.html', products=PRODUCTS) @app.route('/product/<key>') def product(key): product = PRODUCTS.get(key) if not product: abort(404) return render_template('product.html', product=product)
在这个文件中,我对产品列表进行了硬编码,以使应用程序更简单,并且只关注模板部分。我创建了两个端点, home和 product,前者用于列出所有产品,后者打开单个页面。
flask_app/static/css/main.css
body { padding-top: 50px; } .top-pad { padding: 40px 15px; text-align: center; }
这个文件包含一些我添加的自定义 CSS 以使模板更清晰。现在让我们看看模板。
flask_app/templates/base.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Jinja2 Tutorial - Tutsplus</title> <link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet"> <link href="{{ url_for('static', filename='css/main.css') }}" rel="stylesheet"> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top" role="navigation"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="{{ url_for('home')}}">Tutsplus - Jinja2 Tutorial</a> </div> </div> </div> <div class="container"> {% block container %}{% endblock %} </div> <!-- jquery (necessary for Bootstrap's javascript plugins) --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script> <script src="{{ url_for('static', filename='js/bootstrap.min.js') }}"></script> </body> </html>
请注意 url_for()用于为静态文件和其他链接创建 URL。它是 Flask 提供的一个非常方便的工具。在文档中阅读有关此内容的更多信息 。这里要注意的另一个重点是 的使用 {% block container %}{% endblock %},这是 Jinja2 致力于使模板模块化和可继承的非常重要的组件。接下来的几个文件将使这一点更清楚。
flask_app/templates/home.html
{% extends 'base.html' %} {% block container %} <div class="top-pad"> {% for id, product in products.iteritems() %} <div class="well"> <h2> <a href="{{ url_for('product', key=id) }}">{{product['name'] }}</a> <small>$ {{ product['price'] }}</small> </h2> </div> {% endfor %} </div> {% endblock %}
查看此模板如何扩展base.html 并提供 {% block container %}. {% for %}行为就像我们在这里用来创建产品列表的任何语言中的普通 for 循环一样。
flask_app/templates/product.html
{% extends 'home.html' %} {% block container %} <div class="top-pad"> <h1>{{ product['name'] }} <small>{{ product['category'] }}</small> </h1> <h3>$ {{ product['price'] }}</h3> </div> {% endblock %}
上面的模板实现了单个产品页面。
现在通过执行以下命令运行应用程序。
flask --app=my_app run
正在运行的应用程序将如下面的屏幕截图所示。只需 在浏览器中打开http://127.0.0.1:5000/home即可。
单击任何产品以查看单个产品页面。
结论
在本教程中,我们了解了如何使用 Jinja2 在基于 Flask 的应用程序中布局模板结构。我们还看到了如何使用块来利用模板中的继承。
- 烧瓶应用程序/my_app.py
- flask_app/templates/index.html
- 烧瓶应用程序/my_app.py
- flask_app/static/css/main.css
- flask_app/templates/base.html
- flask_app/templates/home.html
- flask_app/templates/product.html