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
应用程序:
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
应用本身
flask_app / 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
方法中,从请求中获取hello
之后的URL的最后一部分,然后传递给使用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
。 其余的应用程序代码如下所示。
flask_app / 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,我添加了这些自定义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的应用程序中布局模板结构。 我们还看到了如何使用块来利用模板中的继承。
在本系列的下一部分中,我们将看到如何编写自定义过滤器,自定义上下文处理器和宏。
翻译自: https://code.tutsplus.com/tutorials/templating-with-jinja2-in-flask-essentials--cms-25571