博客 / 詳情

返回

模板引擎Jinja2語法介紹

前言

Flask和Django,以及其它很多Python框架如Ansible,都默認使用Jinja2來作為模版引擎。我們用Jinja2在服務器上直接生成配置和其他文件。 Jinja是一個基於Python設計語言的“全功能模板引擎”,個人認為Jinja語法本身並不複雜,但掌握好基本的Jinja語法會幫助你在構建Ansible、Jenkins、Web等批處理作業時做到事半功倍的效果。

模板引擎Jinja2語法介紹

更新歷史

2020年02月20日 - 初稿

閲讀原文 - https://wsgzao.github.io/post...


Jinja簡介

Jinja is a modern and designer-friendly templating language for Python, modelled after Django’s templates. It is fast, widely used and secure with the optional sandboxed template execution environment:

{% extends "base.html" %}
{% block title %}Members{% endblock %}
{% block content %}
  <ul>
  {% for user in users %}
    <li><a href="{{ user.url }}">{{ user.username }}</a></li>
  {% endfor %}
  </ul>
{% endblock %}

Features:

  • sandboxed execution
  • powerful automatic HTML escaping system for XSS prevention
  • template inheritance
  • compiles down to the optimal python code just in time
  • optional ahead-of-time template compilation
  • easy to debug. Line numbers of exceptions directly point to the correct line in the template.
  • configurable syntax

Jinja2 是一個現代的,設計者友好的,仿照 Django 模板的 Python 模板語言。 它速度快,被廣泛使用,並且提供了可選的沙箱模板執行環境保證安全:

特性:

  • 沙箱中執行
  • 強大的 HTML 自動轉義系統保護系統免受 XSS
  • 模板繼承
  • 及時編譯最優的 python 代碼
  • 可選提前編譯模板的時間
  • 易於調試。異常的行數直接指向模板中的對應行。
  • 可配置的語法
為什麼要叫Jinja?

之所以叫Jinja,是因為日本的神社(Jinja)英文單詞是temple,而模板的英文是template,兩者發音很相似(這麼説來,它本來也有可能叫Miao的……)。

Jinja的速度怎麼樣?

和Mako差不多,但比Genshi以及Django的模板引擎快10~20倍。

把邏輯判斷(Logic)放到模板裏是個好主意嗎?

毫無疑問,你放到模板裏邏輯判斷(Logic)應該越少越好。但為了讓大家都開心,適當的邏輯判斷是需要的。儘管如此,它有很多對於你能做什麼,不能做什麼的限制。

出於諸多考慮(速度,易讀性等等),Jinja既不允許你放置任意的Python代碼,也不允許所有的Python表達式。這也是為什麼我們要了解Jinja2的語法。

在Jinja官方文檔中建議大家可以優先閲讀以下2個章節:

  • Frequently Asked Questions
  • Template Designer Documentation

什麼是模版引擎

在Python中,什麼是模版?就是在一個靜態HTML加入一些類似變量的標籤,然後引擎在渲染這個HTML時候會動態的把變量填入內容,生成一個最終的HTML。
什麼是模版引擎?其實就是一種能解析類似Python語言的標記語言的解釋器。

比如我們在HTML模版中輸入一個`<p> {{ post.title }} </p>`,顯然這不是真正的HTML語法。但是當Jinja2解釋器讀取到`{{ ...}}`後知道里面是一個變量,那麼就把這個變量替換為真正的值,最後翻譯出來就變成了`<p> 大標題 </p>`這樣的HTML內容。

Jinja2是一個模版語言,只是類似Python,比較符合Python語法,但不完全相同!

所有的模版引擎,實際上都差不多,不管是基於VBS語言的ASP模版,還是基於PHP語言的PHP模版,都不是與原本語言一摸一樣,而只是做到儘量一樣而已。

Jinja2語言基礎

注意:Jinja2模版語言,是不區分縮進的,和純python不同。實際上所有模版語言都不區分縮緊。

常用標記:

註釋:`{# 這是註釋 #}`
變量:`{{ post.title }}`,或字典元素`{{your_dict['key']}}`,或列表`{{your_list[0]}}`
多行代碼塊:`{% 開始 %} HTML標籤 {% 結束 %}`

示例:

{% if user %}
    {{ user }}
{% else %}
    hello!
    {% for index in indexs %}
        {{ index }} 
{% endfor %}

Delimiters(分隔符)

{% … %} 語句([Statements](http://jinja.pocoo.org/docs/dev/templates/#list-of-control-structures))
{{ … }} 打印模板輸出的表達式([Expressions](http://jinja.pocoo.org/docs/dev/templates/#expressions))
{# … #} 註釋
# … ## 行語句([Line Statements](http://jinja.pocoo.org/docs/dev/templates/#line-statements))

Variables(變量)

除了普通的字符串變量,Jinja2還支持列表、字典和對象,你可以這樣獲取變量值:

{{ mydict['key'] }}
{{ mylist[3] }}
{{ mylist[myintvar] }}
{{ myobj.somemethod() }}

獲取一個變量的屬性有兩種方式:

{{ foo.bar }}
{{ foo['bar'] }}

這兩種方法基本相同(深層次的區別可以暫不考慮)

Filter 過濾器()

一個filter過濾器的本質就是一個function函數。使用格式為:變量名 | 函數
它做到的就是,把變量傳給函數,然後再把函數返回值作為這個代碼塊的值。

如:

<!-- 帶參數的 -->
{{變量 | 函數名(*args)}}

<!-- 不帶參數可以省略括號 -->
{{變量 | 函數名}}

鏈式調用(管道式):
和命令行的pipline管道一樣,可以一次調用多個函數(過濾器),如:

{{ "hello world" | reverse | upper }}

文本塊調用(將中間的所有文字都作為變量內容傳入到過濾器中):

{% filter upper %}
    一大堆文字
{% endfilter %}
Jinja2常用過濾器

字符串操作:

safe:禁用轉義
<p>{{ '<em>hello</em>' | safe }}</p>

capitalize:把變量值的首字母轉成大寫,其餘字母轉小寫
<p>{{ 'hello' | capitalize }}</p>

lower:把值轉成小寫
<p>{{ 'HELLO' | lower }}</p>

upper:把值轉成大寫
<p>{{ 'hello' | upper }}</p>

title:把值中的每個單詞的首字母都轉成大寫
<p>{{ 'hello' | title }}</p>

reverse:字符串反轉
<p>{{ 'olleh' | reverse }}</p>

format:格式化輸出
<p>{{ '%s is %d' | format('name',17) }}</p>

striptags:渲染之前把值中所有的HTML標籤都刪掉
<p>{{ '<em>hello</em>' | striptags }}</p>

truncate: 字符串截斷
<p>{{ 'hello every one' | truncate(9)}}</p>

列表操作:

first:取第一個元素
<p>{{ [1,2,3,4,5,6] | first }}</p>

last:取最後一個元素
<p>{{ [1,2,3,4,5,6] | last }}</p>

length:獲取列表長度
<p>{{ [1,2,3,4,5,6] | length }}</p>

sum:列表求和
<p>{{ [1,2,3,4,5,6] | sum }}</p>

sort:列表排序
<p>{{ [6,2,3,1,5,4] | sort }}</p>

List of Builtin Filters

Tests(測試,判斷)

Jinja2提供的tests可以用來在語句裏對變量或表達式進行測試,如果要測試一個變量,可以在變量後加上“is”和test名,比如:

{% if user.age is equalto 42 %} {# 這裏也可以寫成... is equalto(42) #}
Ha, you are 42!
{% endif %}

如果要傳入參數,可以在test後增加括號,也可以直接寫在後面。

常用的test(未説明的均返回True或False):

  • boolean
  • defined
  • equalto
  • escaped
  • none
  • sequence
  • string
  • number
  • reverse
  • replace

List of Builtin Tests

For/If (列表控制結構)

A control structure refers to all those things that control the flow of a program - conditionals (i.e. if/elif/else), for-loops, as well as things like macros and blocks. With the default syntax, control structures appear inside blocks.

List of Control Structures

For

Loop over each item in a sequence. For example, to display a list of users provided in a variable called users:

<h1>Members</h1>
<ul>
{% for user in users %}
  <li>{{ user.username|e }}</li>
{% endfor %}
</ul>

As variables in templates retain their object properties, it is possible to iterate over containers like dict:

<dl>
{% for key, value in my_dict.items() %}
    <dt>{{ key|e }}</dt>
    <dd>{{ value|e }}</dd>
{% endfor %}
</dl>

循環索引

  • loop.index: 循環當前迭代(從1開始)。
  • loop.index0: 循環當前迭代(從0開始)。
  • loop.revindex: 循環迭代的數量(從1開始)。
  • loop.revindex0: 循環迭代的數量(從0開始)。
  • loop.first: 是否為迭代的第一步。
  • loop.last: 是否為迭代的最後一步。
  • loop.length: 序列中元素的數量。

If

The if statement in Jinja is comparable with the Python if statement. In the simplest form, you can use it to test if a variable is defined, not empty and not false:

{% if users %}
<ul>
{% for user in users %}
    <li>{{ user.username|e }}</li>
{% endfor %}
</ul>
{% endif %}

For multiple branches, elif and else can be used like in Python. You can use more complex Expressions there, too:

{% if kenny.sick %}
    Kenny is sick.
{% elif kenny.dead %}
    You killed Kenny!  You bastard!!!
{% else %}
    Kenny looks okay --- so far
{% endif %}

Ansible Jinja2 模版使用

更多用法可以閲讀參考文章中的鏈接

variables: 可以輸出數據

{{ my_variable }}
{{ some_dudes_name | capitalize }}

statements: 可以用來創建條件和循環等等

{% if my_conditional %}
    xxx
{% endif %}

{% for item in all_items %}
    {{ item }}
{% endfor %}

從上文中第二個variable的例子中可以看出,Jinja2支持使用帶過濾器的Unix型管道操作符。有很多的內置過濾器可供使用。

我們可以僅僅用一堆簡單if和for就可以建立建立幾乎任何的常規配置文件。不過如果你有意更進一步,Jinja2 Documentation包含了很多有趣的東西可供瞭解。我們可以看到Ansibe允許在模板中使用一些額外的模版變量。

按照Ansible template_module, 我們模板的示例:

- name: Create Nginx SSL configuration
  template:
    src: "nginx_ssl.j2"
    dest: "/etc/nginx/sites-available/{{ project_name }}"

我們同樣可以發現在Ansible Facts中有很多可用的Ansible變量。

參考文章

Jinja Documentation

Jinja2 中文文檔

Flask模板引擎:Jinja2語法介紹

一篇文章搞懂Jinja2 Template Engine 模版引擎

Ansible Templating (Jinja2)

ansible筆記(38):jinja2模板(一)

Ansible Jinja2 模板使用

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.