{% raw %}

Python Jinja 教程

原文: http://zetcode.com/python/jinja/

Jinja 教程展示了如何使用 Jinja 模块在 Python 中创建模板。

Python Jinja 模块

Jinja 是 Python 的模板引擎。 它类似于 Django 模板引擎。

模板引擎或模板处理器是一个旨在将模板与数据模型结合以生成文档的库。 模板引擎通常用于在源代码预处理中生成大量电子邮件,或生成动态 HTML 页面。

我们创建一个模板引擎,在其中定义静态零件和动态零件。 动态部分随后将替换为数据。 渲染功能随后将模板与数据结合在一起。

Jinja 安装

  1. $ sudo pip3 install jinja2

我们使用pip3工具安装 Jinja。

Jinja 分隔符

Jinja 在模板字符串中使用各种分隔符。

  • {% %} - 陈述
  • {{ }} - 要打印到模板输出的表达式
  • {# #} - 模板输出中未包含的注释
  • # ## - 行语句

Jinja 简单的例子

在第一个示例中,我们创建一个非常简单的模板。

simple.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Template
  3. name = input("Enter your name: ")
  4. tm = Template("Hello {{ name }}")
  5. msg = tm.render(name=name)
  6. print(msg)

该示例要求输入用户名并生成消息字符串,该消息字符串将打印给用户。 模板引擎类似于 Python format()方法; 但是模板引擎功能更强大,并且具有更多功能。

  1. from jinja2 import Template

我们从jinja2模块导入Template对象。 Template是中央模板对象。 它代表一个已编译的模板,并用于对其进行求值。

  1. tm = Template("Hello {{ name }}")

在我们的模板中,我们具有用于打印变量的{{ }}语法。 变量以render()方法传递。

  1. msg = tm.render(name=name)

使用render()方法,我们生成最终输出。 该方法将模板字符串与作为参数传递的数据连接在一起。 传递给render()方法的变量称为上下文变量。

  1. $ ./simple.py
  2. Enter your name: Paul
  3. Hello Paul

这是一个示例输出。

在下一个示例中,我们使用两个变量。

simple2.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Template
  3. name = 'Peter'
  4. age = 34
  5. tm = Template("My name is {{ name }} and I am {{ age }}")
  6. msg = tm.render(name=name, age=age)
  7. print(msg)

模板字符串呈现两个变量:名称和年龄。 这次变量是硬编码的。

  1. $ ./simple2.py
  2. My name is Peter and I am 34

这是输出。

Jinja 对象

我们可以使用模板字符串中的对象。

objects.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Template
  3. class Person:
  4. def __init__(self, name, age):
  5. self.name = name
  6. self.age = age
  7. def getAge(self):
  8. return self.age
  9. def getName(self):
  10. return self.name
  11. person = Person('Peter', 34)
  12. tm = Template("My name is {{ per.getName() }} and I am {{ per.getAge() }}")
  13. msg = tm.render(per=person)
  14. print(msg)

在示例中,我们定义了Person对象。 我们通过两个获取器获取名称和年龄。

字典

Jinja 允许使用方便的点表示法来访问 Python 字典中的数据。

dicts.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Template
  3. person = { 'name': 'Person', 'age': 34 }
  4. tm = Template("My name is {{ per.name }} and I am {{ per.age }}")
  5. # tm = Template("My name is {{ per['name'] }} and I am {{ per['age'] }}")
  6. msg = tm.render(per=person)
  7. print(msg)

我们有一本人字典。 我们使用点运算符访问字典键。

  1. tm = Template("My name is {{ per.name }} and I am {{ per.age }}")
  2. # tm = Template("My name is {{ per['name'] }} and I am {{ per['age'] }}")

活动方式和注释方式均有效。 点符号更方便。

Jinja 原始数据

我们可以使用rawendraw标记转义 Jinja 分隔符。

raw_data.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Template
  3. data = '''
  4. {% raw %}
  5. His name is {{ name }}
  6. {% endraw %}
  7. '''
  8. tm = Template(data)
  9. msg = tm.render(name='Peter')
  10. print(msg)

通过使用rawendraw块,我们逃避了 Jinja {{ }}语法。 它是按字面意思印刷的。

Jinja 转义数据

为了转义诸如<>字符之类的数据,我们可以使用过滤器或escape()函数。

escape_data.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Template, escape
  3. data = '<a>Today is a sunny day</a>'
  4. tm = Template("{{ data | e}}")
  5. msg = tm.render(data=data)
  6. print(msg)
  7. print(escape(data))

该示例转义<>字符。

  1. tm = Template("{{ data | e}}")

使用e过滤器,可以转储数据。 过滤器应用|字符。

  1. print(escape(data))

转义函数执行相同的操作。

Jinja 表达式

for 表达式用于迭代模板中的数据收集。

现在,我们不再使用简单的字符串模板。 我们使用一个FileSystemLoader加载的文本文件。

for_expr.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Environment, FileSystemLoader
  3. persons = [
  4. {'name': 'Andrej', 'age': 34},
  5. {'name': 'Mark', 'age': 17},
  6. {'name': 'Thomas', 'age': 44},
  7. {'name': 'Lucy', 'age': 14},
  8. {'name': 'Robert', 'age': 23},
  9. {'name': 'Dragomir', 'age': 54}
  10. ]
  11. file_loader = FileSystemLoader('templates')
  12. env = Environment(loader=file_loader)
  13. template = env.get_template('showpersons.txt')
  14. output = template.render(persons=persons)
  15. print(output)

在此示例中,模板是showpersons.txt文件。 该文件位于templates目录中。

  1. persons = [
  2. {'name': 'Andrej', 'age': 34},
  3. {'name': 'Mark', 'age': 17},
  4. {'name': 'Thomas', 'age': 44},
  5. {'name': 'Lucy', 'age': 14},
  6. {'name': 'Robert', 'age': 23},
  7. {'name': 'Dragomir', 'age': 54}
  8. ]

数据是字典列表。

  1. file_loader = FileSystemLoader('templates')
  2. env = Environment(loader=file_loader)

我们定义一个FileSystemLoader。 从templates目录中检索模板。

  1. template = env.get_template('showpersons.txt')

我们使用get_template()方法获得模板。

templates/showpersons.txt

  1. {% for person in persons -%}
  2. {{ person.name }} {{ person.age }}
  3. {% endfor %}

在模板文件中,我们使用for表达式遍历集合。 我们显示此人的姓名和年龄。 %字符旁边的破折号用于控制空格。

Jinja 条件

条件是满足特定条件时要求值的表达式。

conditionals.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Environment, FileSystemLoader
  3. persons = [
  4. {'name': 'Andrej', 'age': 34},
  5. {'name': 'Mark', 'age': 17},
  6. {'name': 'Thomas', 'age': 44},
  7. {'name': 'Lucy', 'age': 14},
  8. {'name': 'Robert', 'age': 23},
  9. {'name': 'Dragomir', 'age': 54},
  10. ]
  11. file_loader = FileSystemLoader('templates')
  12. env = Environment(loader=file_loader)
  13. env.trim_blocks = True
  14. env.lstrip_blocks = True
  15. env.rstrip_blocks = True
  16. template = env.get_template('showminors.txt')
  17. output = template.render(persons=persons)
  18. print(output)

该示例仅打印未成年人。 未成年人是指未满 18 岁的人。

  1. env.trim_blocks = True
  2. env.lstrip_blocks = True
  3. env.rstrip_blocks = True

输出中的空白可以通过环境属性来控制。

templates/showminors.txt

  1. {% for person in persons %}
  2. {% if person.age < 18 %}
  3. {{- person.name }}
  4. {% endif %}
  5. {%- endfor %}

在模板中,我们仅使用if表达式输出 18 岁以下的人。

  1. $ ./conditionals.py
  2. Mark
  3. Lucy

这是输出。

Jinja sum过滤器

可以将过滤器应用于数据以对其进行修改。 例如,sum过滤器可以对数据求和,escape过滤器对它们进行转义,sort过滤器对它们进行排序。

sum_filter.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Environment, FileSystemLoader
  3. cars = [
  4. {'name': 'Audi', 'price': 23000},
  5. {'name': 'Skoda', 'price': 17300},
  6. {'name': 'Volvo', 'price': 44300},
  7. {'name': 'Volkswagen', 'price': 21300}
  8. ]
  9. file_loader = FileSystemLoader('templates')
  10. env = Environment(loader=file_loader)
  11. template = env.get_template('sumprices.txt')
  12. output = template.render(cars=cars)
  13. print(output)

在示例中,我们使用sum过滤器来计算所有汽车价格的总和。

  1. cars = [
  2. {'name': 'Audi', 'price': 23000},
  3. {'name': 'Skoda', 'price': 17300},
  4. {'name': 'Volvo', 'price': 44300},
  5. {'name': 'Volkswagen', 'price': 21300}
  6. ]

我们有汽车字典的列表。 每个字典都有一个价格键。 它将用于计算总和。

templates/sumprices.txt

  1. The sum of car prices is {{ cars | sum(attribute='price') }}

在模板文件中,我们将过滤器应用于汽车集合对象。 根据price属性计算总和。

  1. $ ./sum_filter.py
  2. The sum of car prices is 105900

这是输出。

Jinja 模板继承

模板继承是一项强大的功能,可减少代码重复并改善代码组织。 我们定义了一个基本模板,其他模板文件也从中继承。 这些模板文件将覆盖基本模板文件的特定块。

ineritance.py

  1. #!/usr/bin/env python3
  2. from jinja2 import Environment, FileSystemLoader
  3. content = 'This is about page'
  4. file_loader = FileSystemLoader('templates')
  5. env = Environment(loader=file_loader)
  6. template = env.get_template('about.html')
  7. output = template.render(content=content)
  8. print(output)

我们渲染about.html文件。 它继承自base.html文件。

base.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="X-UA-Compatible" content="ie=edge">
  7. <title>{% block title %}{% endblock %}</title>
  8. </head>
  9. <body>
  10. {% block content%}
  11. {% endblock %}
  12. </body>
  13. </html>

base.html文件中,我们声明两个块:标题和内容。 这些块将在子模板中填充特定的标签和文本。

about.html

  1. {% extends 'base.html' %}
  2. {% block title%}About page{% endblock %}
  3. {% block content %}
  4. <h1>About page</h1>
  5. <p>
  6. This is about page
  7. </p>
  8. {% endblock %}

about.html模板文件继承自base.html。 它添加了特定于此页面的数据。 我们避免代码重复; 我们不会在两个页面上重复相同的标签,例如bodyhtmlmeta标签。

  1. {% extends 'base.html' %}

继承是通过extends指令完成的。

  1. {% block title%}About page{% endblock %}

我们定义一个标题。

  1. {% block content %}
  2. <h1>About page</h1>
  3. <p>
  4. This is about page
  5. </p>
  6. {% endblock %}

并且我们定义内容。

Jinja Flask 示例

在下一个示例中,我们创建一个使用 Jinja 的简单 Flask 应用。

app.py

  1. #!/usr/bin/env python3
  2. from flask import Flask, render_template, request
  3. app = Flask(__name__)
  4. @app.route("/greet")
  5. def greet():
  6. username = request.args.get('name')
  7. return render_template('index.html', name=username)
  8. if __name__ == "__main__":
  9. app.run()

在此 Flask 应用中,我们获取用户名,并将其作为参数传递给render_template()方法。 greet()函数对/greet路径做出反应。

templates/index.html

  1. <!doctype html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Greeting</title>
  6. </head>
  7. <body>
  8. <p>
  9. Hello {{ name }}
  10. </p>
  11. </body>
  12. </html>

这是模板文件,位于templates目录中。 我们使用{{ name }}语法将用户名添加到模板文件中。

  1. $ python3 app.py
  2. * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

我们启动服务器。

  1. $ curl http://127.0.0.1:5000/greet?name=Peter
  2. <!doctype html>
  3. <html lang="en">
  4. <head>
  5. <meta charset="utf-8">
  6. <title>Greeting</title>
  7. </head>
  8. <body>
  9. <p>
  10. Hello Peter
  11. </p>
  12. </body>
  13. </html>

我们使用curl工具连接到应用。 我们添加一个名称参数。

在本教程中,我们介绍了 Python Jinja 模块。

您可能也对以下相关教程感兴趣: PyMongo 教程Python 日志记录教程pyDAL 教程Python 教程

{% endraw %}