Bootstrap

jinja语法总结

声明:本文为作者学习总结,内容浅薄。有写的不对的地方,望读者不吝赐教。

三种基本模式
{%语句%}    ##语句,控制结构
{{变量}}    ##打印模板输出的表达式(变量)
{#……#}    ##注释(“……”可包含多行)
访问变量

        访问变量有两种方式。

{{ foo.bar }}

        这种方式下的实现为:

  • 检查 foo 上是否有一个名为 bar 的属性。
  • 如果没有,检查 foo 中是否有一个 'bar' 项 。
  • 如果没有,返回一个未定义对象。

        第二种方式为:

{{ foo['bar'] }}

         在这种方式下,其实现为:

  • 检查在 foo 中是否有一个 'bar' 项。
  • 如果没有,检查 foo 上是否有一个名为 bar 的属性。
  • 如果没有,返回一个未定义对象。
过滤器

         变量可以通过过滤器进行修改,并且过滤器可链式调用(前一个的输出作为后一个的输入)。形如:

{{ name|striptags|title }}    ##移除 name 中的所有 HTML 标签并且改写 为标题样式的大小写格式
{{ list|join(', ') }}     ##把一个列表用逗号连接起来
测试

        要测试一个变量或表达式,你要在变量后加上一个 is 以及测试的名称。测试也可以接受参数。如果测试只接受一个参数,你可以省去括号来分组它们。形如:

{% if loop.index is divisibleby 3 %}
{% if loop.index is divisibleby(3) %}
 空格控制(?)

        Jinja2语句占据的空行,你自己输出的空格,Tab都将保留。

         举例:

<div>
    {% if True %}
        yay
    {% endif %}
</div>

        渲染后:

<div>

        yay

</div>

        要去掉Jinja2语句占据的空行,可以通过设置Jinja2的环境变量实现:

app.jinja_env.trim_blocks = True
app.jinja_env.lstrip_blocks = True

        渲染后结果如下:

<div>
        yay
</div>

         也可通过添加“-”的方式达到去除空白的效果。加一个减号 “-” 到块的开始或结束、注释或变量表达式,将删除该块之前或之后的空白。需要注意的是,-和标记之间没有空白(空格、制表符等)。

{%- if foo -%}...{% endif %}    ##正确
{% - if foo - %}...{% endif %}    ##无效
转义

        当你想输出{{时,可使用以下方法。

{{ '{{' }}

        对于较大的段落,如果不想让jinja处理它,可标记一个块为raw。如下所示。

{% raw %}
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
{% endraw %}

        在这个例子中,jinja不会处理{% raw %}和{% endraw %}两行中包含的行。

行语句

         启用行语句,可以简化编辑的过程。例如如果行语句前缀配置为 # ,下面的两个例子是等价的:

<ul>
# for item in seq
    <li>{{ item }}</li>
# endfor
</ul>

<ul>
{% for item in seq %}
    <li>{{ item }}</li>
{% endfor %}
</ul>

         jinja会把带有行语句前缀(这里配置为#)的行视为语句({%%})。

        为了语句有更好的可读 性,可在块的开始(比如 for 、 if 、 elif 等等)以冒号结尾。以下例子是可行的。

# for item in seq:
    ...
# endfor

        若有未闭合的圆括号、花括号或方括号,行语句可以跨越多行。以下例子是可行的。

<ul>
# for href, caption in [('index.html', 'Index'),
                        ('about.html', 'About')]:
    <li><a href="{{ href }}">{{ caption }}</a></li>
# endfor
</ul>

        从 Jinja 2.2 开始,行注释也可以使用了。如果将行注释前缀配置为##, “##语句”会被视为“{#语句#}”,行中所有 ## 之后的内容(不包括换行符)会被忽略。下面是一个例子。

# for item in seq:
    <li>{{ item }}</li>     ## this comment is ignored
# endfor
模板继承

        可定义父模板作为“模板骨架”,在其中定义块;定义子模板继承父模板,填充父模板中定义的块即可,而无需全部编写。一个简单的例子如下。

##父模板base.html
<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>

{% block content %}{% endblock %}

##子模版
{% extends "base.html" %}

{% blcok content %}
<p>Learning Log helps you keep track of your learning, for any topic you're learning about.</p>
{% endblock %}
父模板 

        在父模板中,可用{% block 块名 %}定义块。块中也有父模板的具体实现,也可不实现。

子模板

        子模板首行应继承父模板,{% entends “父模板名” %}。

        模板的文件名依赖于模板加载器。例如 FileSystemLoader 允许你用文件名访 问其它模板。你可以使用斜线访问子目录中的模板:

{% extends "layout/default.html" %}

        这种行为也可能依赖于应用内嵌的 Jinja 。

         子模板并非并非必须定义父模板中的每个块,因此在父模板中,可使用任意多个块来预留空间,而子模板可根据需要定义相应数量的块。子模板中未定义的块,会使用父模板中的值。

        不能在一个模板中定义多个同名的块。如果想多次打印一个块,可使用self变量并调用与块同名的函数(此函数是自动生成的)。如下所示。

<title>{% block title %}{% endblock %}</title>
<h1>{{ self.title() }}</h1>
{% block body %}{% endblock %}

        在子模板中,可通过调用super()来获得父模板中块的内容。

命名块结束标签

        可在块结束标签{% endblock %}中添加块名({% endblock 块名 %}),以增强可读性。并非必须指定块名,但指定块名有助于确定结束的是哪个块。

嵌套块和作用域

        默认的块不允许访问块外作用域中的变量。见下例。

{% for item in seq %}
    <li>{% block loop_item %}{{ item }}{% endblock %}</li>
{% endfor %}

       模板中定义”list”块并访问循环中的”item”变量。

        这个例子会输出空的<li>项,因为item在块中不可用。要使其在块中可用,可在块声明中添加scope,就把块设定到了作用域中。

{% for item in seq %}
    <li>{% block loop_item scoped %}{{ item }}{% endblock %}</li>
{% endfor %}

        当覆盖一个块时,不需要提供 scoped 修饰。

模板对象

        可通过上下文传递一个模板对象到模板,而模板可以继承这个模板对象,通过以下语句。

{% extends layout_template %}

        应当注意,layout_template 变量一定是布局模板文件名的字符串。 

HTML转义

        从模板生成HTML时,变量可能包含影响已生成HTML的字符。要解决这个问题,可使用手动转义和自动转义。

手动转义

        应当转义 可能 包含 > 、 < 、 & 或 " 字符的变量,除非变量中的 HTML 有可信的良好格式。转义通过用管道传递到过滤器 |e 来实现: {{ user.username|e }} 。

自动转义

        自动转义会转义除被标记为安全的变量外所有的变量。可以在应用中 标记,也可以在模板中使用 |safe 过滤器标记。

        返回模板数据(宏、 super 、 self.BLOCKNAME )的函数,其返回值总是被标记 为安全的。模板中的字符串字面量在自动转义中被也被视为是不安全的。

控制结构
for

举例如下:

<ul>
{% for user in users %}
    <li>{{ user.username|e }}</li>
{% else %}
    <li><em>no users found</em></li>
{% endfor %}
</ul>

        与python不同,模板中的循环不可使用break或continue。

        在 for 循环中,可以使用特殊的 loop.cycle 辅助函数,伴随循环在一个字符串/变 量列表中周期取值:

{% for row in rows %}
    <li class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li>
{% endfor %}

        循环递归?

 if

        与python中的if相似。

        与函数类似。举例如下:

##宏定义
{% macro input(name, value='', type='text', size=20) -%}
    <input type="{{ type }}" name="{{ name }}" value="{{
        value|e }}" size="{{ size }}">
{%- endmacro %}

##调用宏
<p>{{ input('username') }}</p>
<p>{{ input('password', type='password') }}</p>

        如果调用时宏并非在当前模板定义,应使用import。

        在宏内部,有三个可以访问的内部变量。

varargs
如果有多于宏接受的参数个数的位置参数被传入,它们会作为列表的值保存在 varargs 变量上。
kwargs
同 varargs ,但只针对关键字参数。所有未使用的关键字参数会存储在 这个特殊变量中。
caller(?)
如果宏通过 call 标签调用,调用者会作为可调用的宏被存储在这个 变量中。

        此外,以下宏属性可访问。

name
宏的名称。 {{ input.name }} 会打印 input 。
arguments
一个宏接受的参数名的元组。
defaults
默认值的元组。
catch_kwargs
如果宏接受额外的关键字参数(也就是访问特殊的 kwargs 变量),为 true 。
catch_varargs
如果宏接受额外的位置参数(也就是访问特殊的 varargs 变量),为 true 。
caller
如果宏访问特殊的 caller 变量且由 call 标签调用,为 true 。

         如果一个宏的名称以下划线开始,它不是导出的且不能被导入,参考python中的函数。

调用

        宏可以访问调用者语句块的内容,换句话说,宏的”{{ caller( ) }}”部分会被调用者”{% call %}”语句块内部的内容替代。看下面一个例子。

        在templates/_list_user.html创建宏”list_users”:


{% macro list_users(users) -%}
 
  <table>
 
    <tr><th>Name</th><th>Action</th></tr>
 
    {%- for user in users %}
 
      <tr><td>{{ user.name |e }}</td>{{ caller() }}</tr>
 
    {%- endfor %}
 
  </table>
 
{%- endmacro %}
————————————————                        
原文链接:https://blog.csdn.net/gh254172840/article/details/81745338

        宏的作用就是将用户列表显示在表格里,表格每一行用户名称后面调用了”{{ caller( ) }}”方法。

        然后在templates/user.html编写调用者的代码:

{% from "_list_user.html" import list_users with context %}
 
{% set users=[{'name':'Tom','gender':'M','age':20},
 
              {'name':'John','gender':'M','age':18},
 
              {'name':'Mary','gender':'F','age':24}]
 
%}
 
 
 
{% call list_users(users) %}
 
    <td><input name="delete" type="button" value="Delete"></td>
 
{% endcall %}
————————————————                        
原文链接:https://blog.csdn.net/gh254172840/article/details/81745338

        这里使用了{% call %}语句来调用宏,语句块中包括了一段生成”Delete”按钮的代码。运行后发现每个用户名后面都出现了”Delete”按钮,也就是”{{ caller( ) }}”部分被调用者”{% call %}”语句块内部的内容替代了。

        Jinja2的宏不但能访问调用者语句块的内容,还能给调用者传递参数。

        在templates/_list_user.html中,将表格增加一列性别,并在宏里调用”caller()”方法时,传入一个变量”user.gender”,如下所示。

{% macro list_users(users) -%}
  <table>
    <tr><th>Name</th><th>Gender</th><th>Action</th></tr>
    {%- for user in users %}
      <tr><td>{{ user.name |e }}</td>{{ caller(user.gender) }}</tr>
    {%- endfor %}
  </table>
{%- endmacro %}
———————————————— 
原文链接:https://blog.csdn.net/gh254172840/article/details/81745338

        修改templates/user.html中调用者语句块,如下所示。


{% from "_list_user.html" import list_users with context %}
 
{% call(gender) list_users(users) %}
    <td>
    {% if gender == 'M' %}
    <img src="{{ url_for('static', filename='img/male.png') }}" width="20px">
    {% else %}
    <img src="{{ url_for('static', filename='img/female.png') }}" width="20px">
    {% endif %}
    </td>
    <td><input name="delete" type="button" value="Delete"></td>
{% endcall %}
————————————————                        
原文链接:https://blog.csdn.net/gh254172840/article/details/81745338

我们在使用”{% call %}”语句时,将其改为了”{% call(gender) … %}”,这个括号中的”gender”就是用来接受宏里传来的”user.gender”变量。因此我们就可以在”{% call %}”语句中使用这个”gender”变量来判断用户性别。这样宏就成功地向调用者传递了参数。
————————————————
原文链接:https://blog.csdn.net/gh254172840/article/details/81745338

过滤器

        将数据用filter块包裹起来,即可对其应用jinja2过滤器。举例如下。

{% filter upper %}
    This text becomes uppercase
{% endfilter %}
 赋值

        使用set标签,可为多个变量赋值。在顶层的(块、宏、循环之外)赋值是可导出的。当前模板也可以从别的模板中导入赋值。举例如下:

{% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %}
{% set key, value = call_something() %}
继承

        你可以在一个文件中使用多次继承,但是 只会执行其中的一个。

        这与extends的特性有关——Jinja2 支持动态继承并且只要没有 extends 标签被访问过,就不分辨父模板和子模 板。而这会导致令人惊讶的行为:首个 extends 标签前的包括空白字符的所有东西 会被打印出来而不是被忽略(见jinja2文档“null-master退回”部分)。通常情况下,extends应当放于文件的首行。但有时,我们可以利用这一特性。见下面这个例子。

{% if not standalone %}{% extends 'master.html' %}{% endif -%}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<title>{% block title %}The Page Title{% endblock %}</title>
<link rel="stylesheet" href="style.css" type="text/css">
{% block body %}
  <p>This is the page body.</p>
{% endblock %}

         在这个例子中,将extends标签置于if标签中。如果变量standalone为false,就将执行extends标签,继承‘master.html’。

包含

        有很多页面的某些内容是一样的,比如“页眉”、“页脚”。开发的时候可以将相同的部分放在独立的模板中,编写时将其“包含”进来即可。举例如下。

##header.html

<style>
    .nav ul{
        overflow: hidden;
    }
    .nav ul li{
        float: left;
        margin: 0 20px;
    }
</style>

<nav class="nav">
    <ul>
        <li>首页</li>
        <li>课程详情</li>
        <li>教程视频</li>
        <li>关于我们</li>
    </ul>
</nav>
#footer.html

<h1>footer</h1>

        编写页面时,如果需要含有“页眉”、“页脚”,将其“包含”进来即可。如下所示。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>include tag demo </title>
</head>
<body>
	<!-- 导入header.html -->
    {% include 'header.html' %}
    <div class="content">
        中间内容
    </div>
    <!-- 导入footer.html -->
    {% include 'footer.html' %}
</body>
</html>

         如果被包含的模板不存在,会抛出一个异常。可以把一句 include 用 ignore missing 标记,这样如果模板不存在,Jinja 会忽略这条语句。如下所示。

{% include "sidebar.html" ignore missing %}

         你也可以提供一个模板列表,它会在包含前被检查是否存在。第一个存在的模板会 被包含进来。如果给出了 ignore missing ,且所有这些模板都不存在,会退化 至不做任何渲染,否则将会抛出一个异常。如下所示。

{% include ['page_detailed.html', 'page.html'] %}
{% include ['special_sidebar.html', 'sidebar.html'] ignore missing %}

        当与 with 或 without context 语句联合使用时,ignore misssing必须被放在上下文可见性语句(with context或without context)之前 。举例如下。

{% include "sidebar.html" ignore missing %}
{% include "sidebar.html" ignore missing with context %}
{% include "sidebar.html" ignore missing without context %}

         without context语句让被包含的模板不可以使用视图(就是那个.py文件)传递过来的对象(默认情况下,被包含的模板能够使用视图传递过来的对象)。

        Changed in version 2.4: 如果传递一个模板对象到模板上下文,你可以用 include 包含这个对 象。 

导入

        和python的导入(import)部分极其相似。

        导入有两种方式:导入整个模块或导入特定的宏(可视为python中的函数)。

         被导入的模块如下。

{% macro input(name, value='', type='text') -%}
    <input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
{%- endmacro %}

{%- macro textarea(name, value='', rows=10, cols=40) -%}
    <textarea name="{{ name }}" rows="{{ rows }}" cols="{{ cols
        }}">{{ value|e }}</textarea>
{%- endmacro %}

        导入整个模块的方式如下。

{% import 'forms.html' as forms %}
<dl>
    <dt>Username</dt>
    <dd>{{ forms.input('username') }}</dd>
    <dt>Password</dt>
    <dd>{{ forms.input('password', type='password') }}</dd>
</dl>
<p>{{ forms.textarea('comment') }}</p>

         导入被导入模块中特定的宏的方式如下。

{% from 'forms.html' import input as input_field, textarea %}
<dl>
    <dt>Username</dt>
    <dd>{{ input_field('username') }}</dd>
    <dt>Password</dt>
    <dd>{{ input_field('password', type='password') }}</dd>
</dl>
<p>{{ textarea('comment') }}</p>

        给被导入的模板或宏命名,访问被导入的宏的方法与python相似,可参考python。

导入上下文行为

        被导入的模板和被包含的模板是不同的:被导入的模板经常只作为容纳宏的模块,不会被缓存,也就无法访问当前模板的上下文(.py视图文件传给它的);而被包含的模板会被缓存,默认可以访问当前模板的上下文。

        这可显式更改。

        with context:将当前模板的上下文传递到模板,并且允许缓存;

        without context:模板无法访问当前模板的上下文,自动禁用缓存。

        举例如下。

{% from 'forms.html' import input with context %}
{% include 'header.html' without context %}

        值得注意的是:在 Jinja 2.0 中,传递给模板的当前模板的上下文不包含当前模板中定义的变量;而从 Jinja 2.1 开始,传递给模板的当前模板的上下文包含当前模板中定义的变量。

表达式
字面量

        字符串、整数、浮点数、列表、元组、字典、true、false均与python中的相同。

        注意:如果元组中只有一个项,你需要以逗号 结尾它。

                   true、false和none应当使用小写的版本。

算术

        与python相似。

比较

        与python相似。

逻辑

        与python相似。

        注意:is 和 in 运算符同样支持使用中缀记法: foo is not bar 和 foo not in bar 而不是 not foo is bar 和 not foo in bar 。所有的 其它表达式需要前缀记法 not (foo and bar) 。

其它运算符

in:运行序列/映射包含检查。如果左操作数包含于右操作数,返回 true 。比如 {{ 1 in [1,2,3] }} 会返回 true 。

is:运行一个测试 。

|:应用一个过滤器。

~:把所有的操作数转换为字符串,并且连接它们。 {{ "Hello " ~ name ~ "!" }} 会返回(假设 name 值为 ''John' ) Hello John! 。("+"也可以实现连接字符串,但你应当首选“~”运算符达成这一目的)。

():调用一个可调用量:{{ post.render() }} 。在圆括号中,你可以像在 python 中一样使用位置参数和关键字参数: {{ post.render(user, full=true) }} 。

. / []:获取一个对象的属性。(见“变量”)

内联的if表达式

        语法是 <do something> if <something is true> else <do something else> 。举例如下:

{% extends layout_template if layout_template is defined else 'master.html' %}

        在一个 变量定义的情况下才继承一个模板,否则继承默认的布局模板。

        else 部分是可选的。如果没有显式地提供 else 块,会求值一个未定义对象。

内置过滤器清单

        略

内置测试清单

        略

全局函数清单

        略

扩展
i18n(?)

        {% trans %}

        {% endtrans %}

表达式语句

        如果加载了表达式语句扩展,一个名为 do 的扩展即可用。它工作几乎如同常规的变量 表达式( {{ ... }} ),只是它不打印任何东西(不输出表达式)。这可以用于修改列表:

{% do navigation.append('a string') %}
循环控制

        如果应用启用循环控制,则可以在循环中使用 break ({% break %})和 continue({% continue %})语句 。举例如下。

        这个循环每两项跳过一次:

{% for user in users %}
    {%- if loop.index is even %}{% continue %}{% endif %}
    ...
{% endfor %}

        这个循环10次迭代后会终止处理。

{% for user in users %}
    {%- if loop.index >= 10 %}{% break %}{% endif %}
{%- endfor %}
with语句

        如果应用启用了 With 语句 ,将允许在模板中使用 with 关键 字。这使得创建一个新的内作用域。这个作用域中的变量在外部是不可见的。举例如下。

{% with foo = 42 %}
    {{ foo }}
{% endwith %}

{% with %}
    {% set foo = 42 %}
    {{ foo }}
{% endwith %}

         以上两种写法是等价的。

自动转义扩展

        如果你的应用程序设置了自动转义扩展,你就可以在模版中开启或者关闭自动转义。举例如下。

{% autoescape true %}
自动转义在这块文本中是开启的。
{% endautoescape %}

{% autoescape false %}
自动转义在这块文本中是关闭的。
{% endautoescape %}

        在 endautoescape 标签之后,自动转义的行为将回到与之前相同的状态。 

        

        

        

;