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