3

基础配置篇:博客模板的格式语法和后端如何传递数据到模板逻辑

前面的章节中,我们选择了使用iris.Django作为我们前端使用的模板引擎,因此我们这里只介绍它的相关语法。

在网络上,关于Django模板的标签和语法教程少之又少,并且很多都是不全面的,要么就是抄来抄去的无用文章,要么就是简单寥寥几个标签,很多时候,都不能满足使用。比如include引入模板后,如何传递变量、如何在页面声明一个临时变量等问题。为了解决网络上缺少介绍内容的问题,我特意翻读了iris.Django的源码,并将大部分常用到的标签,都整理出来,供参考和使用。

iris.Django模板语法和使用

iris.Django模板引擎的模板解析器是pongo2,它是一个类似于 Django 模板语法的模板引擎。Django 是一个开放源代码Python编写的Web应用框架。它的模板引擎语法相对简单,清晰,使用起来也非常方便。因此我们就使用它做为我们的博客的前端模板引擎了。

模板的嵌套引用 include

往往制作模板的时候,我们会将一些公共部分,比如header、footer、aside等部分,抽离出来独立存放,不需要在每一个页面都重复编写,只需要在每一个页面引入它们即可。这个时候,我们可以使用include标签。

{% include "partial/header.html" %}
{% include "partial/footer.html" %}

include可以将一个拆分出来的代码片段(fragment)嵌入到完整的文档中。使用形式是{% include "模板文件" %}

如果需要引入的模板不存在的话,它会报错,如我我们不知道引入的模板是否存在,则需要增加if_exists判断。

{% include "partial/header.html" if_exists %}

这样如果header.html模板存在的话,则会引入,即使不存在,也不会报错,只是被忽略掉了。

默认情况下,include引入的模板,它会继承当前模板的所有变量,如果想给include引入的模板增加另外的变量,可以使用with来增加。如:

{% include "partial/header.html" with title="这是声明给header使用的title" %}

这样就给include引入的模板定义了title变量,当前模板的其他变量它同样也可以继续使用了。

如果需要声明多个变量给include引入的模板使用,可以连续使用key=value的形式增加,它们之间使用空格隔开,如:

{% include "partial/header.html" with title="这是声明给header使用的title" keywords="这是声明给header使用的keywords" %}

如果只想让include引入的模板使用指定的几个变量,而不是当前模板的所有变量,可以使用only来做限制:

{% include "partial/header.html" with title="这是声明给header使用的title" keywords="这是声明给header使用的keywords" only %}

然后在header.html中使用:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{title}}</title>
    <meta name="keywords" content="{{keywords}}">
</head>

模板代码片段宏函数macro

iris.Django模板引擎可以很简便的定义一些宏函数代码片段。宏代码片段相当于一个函数,它只能调用从参数传入的变量。类似于使用include。不过macro有限定的作用域。如文章我们给文章列表的文章item使用macro

定义一个宏函数
{% macro article_detail(article) %}
<li class="item">
    <a href="/article/{{article.Id}}" class="link">
        <h5 class="title">{{article.Title}}</h5>
    </a>
</li>
{% endmacro %}
使用定义的宏函数
{% for item in articles %}
    {{ article_detail(item) }}
{% endfor %}

同时宏函数还可以保存到独立的文件中,然后通过import来嵌套进来。当一个文件中包含多个宏函数,可以使用,将隔开连续引入多个宏函数。还可以使用as来设置别名:

保存宏函数到 article.helper

{% macro article_detail(article) %}
<li class="item">
    <a href="/article/{{article.Id}}" class="link">
        <h5 class="title">{{article.Title}}</h5>
    </a>
</li>
{% endmacro %}
{% macro article_detail2(article) %}
<li class="item">
    <a href="/article/{{article.Id}}" class="link">
        <h5 class="title">{{article.Title}}</h5>
    </a>
</li>
{% endmacro %}

在index.html中引入:

用import引入:
{% import "article.helper" article_detail, article_detail2 as article_detail_new, article_detail as new_item %}
调用:
{% for item in articles %}
    {{ article_detail(item) }}
    {{ article_detail_new(item) }}
    {{ new_item(item) }}
{% endfor %}

模板的继承 extends

模板的继承有点像ppt中的母版一样,我们定义好一个骨架,将一个页面都写好,大部分不用变动,需要变动的部分使用block标签包裹起来:

{% block title %}
    <title>base</title>  <!-- 如果扩写了就是扩写的,不扩写就还是用base -->
{% endblock %}

这样定义的好处是,可以在继承它的模板中,重写这个block,不重写就按母版来显示。
比如我们定义了一个base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% block title %}
        <title>base</title>  <!-- 如果扩写了就是扩写的,不扩写就还是用base -->
    {% endblock %}
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
          integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        .header {
            width: 100%;
            height: 50px;
            background-color: #369;
        }
    </style>
</head>
<body>

<div class="header"></div>

<div class="container">
    <div class="row">
        <div class="col-md-3">
            {% include 'aside.html' %}
        </div>
        <div class="col-md-9">
            {% block content %}
                <h4>content</h4>
            {% endblock %}
        </div>
    </div>
</div>
</body>
</html>

然后在index.html中继承这个base.html

{% extends 'base.html' %}

{% block title %}
    <title>index</title>
{% endblock %}


{% block content %}
    <div class="col-md-9">
        <h3>index</h3>
        <p>index content</p>
    </div>

{% endblock %}

这样就是使用base.html作为母版,并在index.html 中重写了title、content两个部分。

注意:如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。

在使用继承的情况下,尽可能将可能会变动的数据,都包裹在block中,因为block即使在后续的页面不重写,也不影响模板的解析,而需要重写的时候就更方便。

同样地,如果后续写到某一块,发现多个页面都需要使用到,那么这时候,就把添加到base.html中去,让它成为母版的一部分。

变量的输出

Django 模板中遍历复杂数据结构的关键是句点字符.,变量输出边界定义是双大括号。有一个对象是people,它有Name、Gender、Level属性,在模板中输出就是:

<ul>
  <li>网站:{{siteName}}</li>
  <li>名字:{{people.Name}}</li>
  <li>性别:{{people.Gender}}</li>
  <li>等级:{{people.Level}}</li>
</ul>

变量的过滤

同时,输出变量的时候,还支持使用过滤器,来对数据进行初级过滤,格式是:

{{obj|filter__name:param}}

比如一个变量,当它有值的时候,就输出当前值,没有值的时候,就输出默认值:
使用default设置默认值:

{{ userName|default:"大侠匿名"}}

default只要是空都会认为没有。我们还可以使用default_if_none来进行处理

{{ userName|default_if_none:"大侠匿名"}}
{{ ""|default_if_none:"n/a" }}
{{ nil|default_if_none:"n/a" }}

get_digit 可以获取变量中的数字,指定get_digit的值的话,可以获取倒数第几个数字。如:

{{ 1234567890|get_digit:0 }}
{{ 1234567890|get_digit }}
{{ 1234567890|get_digit:2 }}
{{ 1234567890|get_digit:"4" }}
{{ 1234567890|get_digit:10 }}
{{ 1234567890|get_digit:15 }}

使用length输出长度:

{{ value|length }}

如果 value 是 ['a', 'b', 'c', 'd'],那么输出是 4。

divisibleby 可以判断一个变量是否可以被整除,如:

{{ 21|divisibleby:3 }}
{{ 21|divisibleby:"3" }}
{{ 21|float|divisibleby:"3" }}
{{ 22|divisibleby:"3" }}
{{ 85|divisibleby:simple.number }}
{{ 84|divisibleby:simple.number }}

date 可以格式化时间:

{{ value|date:``"2006-01-02 15:04"}}

注意,这个value必须是time.Time类型,不是时间戳,如果是时间戳它会报错的。时间戳要么在控制器将它转成time.Time类型,要么就使用我们自定义的模板函数:

{{stampToDate(nowStamp, "2006-01-02 15:04")}}

truncatecharstruncatewords 字符串字符、单词多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾:

{{ value|truncatechars:9}}
{{ value|truncatewords:9}}

截断除了字符串截断truncatechars,还支持按单词截断truncatewords

truncatechars_htmltruncatewords_html 功能类似truncatecharstruncatewords。但是这这2个标签用来处理截取html中的字符串,它不会破坏html结构。一个是按字符截取,一个是按单词截取。截断的字符串将以可翻译的省略号序列(“...”)结尾:

{{ "This is a long test which will be cutted after some chars."|truncatechars_html:25 }}
{{ "This is a long test which will be cutted after some words."|truncatewords_html:5|safe }}

upperlower 可以对单字进行大小写转换:

{{ value|upper}}
{{ value|lower}}

capfirst 可以实现句子首字母大写效果,如:

{{ "hello there!"|capfirst }}

cut 可实现删除变量中特定的字符。如:

{{ 15|cut:"5" }}
{{ "Hello world"|cut: " " }}

add 可以对要输出的内容进行追加。相当于golang中的+,数字则会相加后输出结果,字符串则会拼接在一起。如:

{{ 5|add:6 }}
{{ 5|add:nothing }}
{{ 5|add:"test" }}
{{ "hello "|add:"john doe" }}

addslashes 则会在指定的预定义字符前添加反斜杠。这些字符是单引号(')、双引号(")、反斜线(\)与NUL(NULL字符)。如:

{{ "plain' text"|addslashes }}
{{ "plain' text"|addslashes|safe }}

title 标签可以实现句子中每一个单词的首字母都变成大写,并将其余部分变成小写,用于格式化标题的输出。如:

{{ "hello there!"|title }}
{{ "HELLO THERE!"|title }}
{{ "HELLO tHERE!"|title }}

yesno yesno用于验证一个变量是否有效,它可以定义三种结果,三种结果分别用英文逗号,隔开,有效值、无效值、不知道类型。如果不定义,也可以留空。如:

{{ article.Status|yesno}}
{{ article.Status|yesno:"validated,not validated,unknown validation status"}}

striptags striptags 类似PHP的strip_tags函数,可以剥去字符串中的 HTML、XML 以及 PHP 的标签。该标签始终会剥离 HTML 注释。如:

{{"<title>Hello World</title>"|striptags}}
{{"<title>Hello World</title>"|striptags|safe}}

removetags 标签可以删除指定的html标签。如:

{{ "<strong><i>Hello!</i></strong>"|removetags:"i"|safe }}

pluralize 标签可以判断一个变量是否是复数。如:

customer{{ 0|pluralize }}
customer{{ 1|pluralize }}
customer{{ 2|pluralize }}
cherr{{ 0|pluralize:"y,ies" }}
cherr{{ 1|pluralize:"y,ies" }}
cherr{{ 2|pluralize:"y,ies" }}
walrus{{ 0|pluralize:"es" }}
walrus{{ 1|pluralize:"es" }}
walrus{{ simple.number|pluralize:"es" }}

random 可以随机输出集合中的一个值。如:

<p>{{ intList|random }}</p>

firstlast 可以用于输出变量中的最开始一个字符和最后一个字符。如:

{{ "Test"|first }}
{{ "Test"|last }}

urlencode urlencode标签可以对变量进行url百分号编码。如:

{{ "https://www.kandaoni.com/?category_id=1"|urlencode }}

linebreaksbrlinebreaks 两个标签都可以将变量的值中的换行符变成<br/>,相当于PHP的nl2br函数。如:

{{ article.Description|linebreaksbr }}
{{ article.Description|linebreaks }}
{{ article.Description|linebreaksbr|safe }}
{{ article.Description|linebreaks|safe }}

length_is length_is可以判断变量的值的长度。只能判断字符串,数字是不行的。如:

{{ "hello"|length_is:5 }}

integerfloat 标签可以将变量的值转换成整数、浮点数。如:

{{ "foobar"|integer }}
{{ "5.4"|float|integer }}
{{ "foobar"|float }}
{{ "5.5"|float }}
{{ "5.6"|integer|float }}

floatformat 标签可以将变量的值按浮点数格式保留指定小数点,默认只保留以为,如果末位是0,则不保留小数点。如果指定小数点后位数,则按指定位数显示。如:

{{ 34.23234|floatformat }}
{{ 34.00000|floatformat }}
{{ 34.23234|floatformat:3 }}
{{ 34.00000|floatformat:3 }}
{{ "34.23234"|floatformat }}
{{ "34.00000"|floatformat }}
{{ "34.23234"|floatformat:3 }}
{{ "34.00000"|floatformat:3 }}

join 可以将一个数组按给定的分隔符合并在一起成为字符串。如:

{{intList|join:", "}}

split 刚好和join相反,它可以将一个字符串按给定的分隔符将一个字符串转换成数组。如:

{{ "Hello, 99, 3.140000, good"|split:", "|join:", " }}

stringformat 可以将数字、字符串格式化成指定的格式输出。相当于fmt.Sprintf()。如:

{{ 0.55555|stringformat:"%.2f" }}
{{ 888|stringformat:"Test: %d" }}
{{ "你好"|stringformat:"Chinese: %s" }}

make_list 可以将字符串按字符拆分成数组,相当于[]rune("你好啊")。如:

{{ "你好啊"|make_list|join:", " }}
{% for char in "你好啊"|make_list %}{{ char }},{% endfor %}

center 这个标签比较有意思,可以将字符串格式化成指定长度,并将字符串放在中间,旁边使用空格填充。如果给定的长度小于字符串长度,则不会做改变。如:

'{{ "test"|center:3 }}'
'{{ "test"|center:20 }}'
{{ "test"|center:20|length }}

ljustrjust 这两个标签和center差不多,都是给字符串填充到指定长度,但是填充方向不同。ljust会在右边填充空格,即让字符串靠左。rjust会在左边填充空格,即让字符串靠右。如:

'{{ "test"|ljust:"20" }}'
{{ "test"|ljust:"20"|length }}
'{{ "test"|rjust:"20" }}'
{{ "test"|rjust:"20"|length }}

wordcount 用来统计字符串的长度。它有2种使用方式,一种是在字符串后面,另一种是使用 filter 标签。如:

{{ ""|wordcount }}
{% filter wordcount %}{% lorem 25 w %}{% endfilter %}

wordwrap 可以将字符串按给定的长度换行。如:

{{ "hello world"|wordwrap:2 }}
<pre>{% filter wordwrap:5 %}{% lorem 26 w %}{% endfilter %}</pre>
{{ "Lorem ipsum dolor sit amet, consectetur adipisici elit."|wordwrap:2|linebreaksbr|safe }}

urlize 会自动给url、邮箱添加上a标签,并自动增加nofollow的rel。这个用来处理文章正文比较合适。urlize还支持设置true和false,用来说明显示的连接内容是否转义。如:

<p>{{ "https://www.kandaoni.com"|urlize|safe }}</p>
<p>{{ "www.kandaoni.com"|urlize|safe }}</p>
<p>{{ "kandaoni.com"|urlize|safe }}</p>
<p>{% filter urlize:true|safe %}</p>
<p>Please mail me at demo@example.com or visit mit on:</p>
<p>- lorem ipsum http://www.kandaoni.com lorem ipsum</p>
<p>- lorem ipsum https://www.kandaoni.com lorem ipsum</p>
<p>- lorem ipsum https://www.kandaoni.com lorem ipsum</p>
<p>- lorem ipsum www.kandaoni.com lorem ipsum</p>
<p>- lorem ipsum www.kandaoni.com/test="test" lorem ipsum</p>
<p>{% endfilter %}</p>
<p>{% filter urlize:false|safe %}</p>
<p>- lorem ipsum www.kandaoni.com/test="test" lorem ipsum</p>
<p>{% endfilter %}</p>

urlizetrunc 的作用和urlize差不多,都是自动给url、邮箱添加上a标签,但是可以设置截取显示部分url内容,超过指定长度部分使用...代替。如:

<p>{% filter urlizetrunc:15|safe %}</p>
<p>Please mail me at demo@example.com or visit mit on:</p>
<p>- lorem ipsum http://www.kandaoni.com lorem ipsum</p>
<p>- lorem ipsum https://www.kandaoni.com lorem ipsum</p>
<p>- lorem ipsum https://www.kandaoni.com lorem ipsum</p>
<p>- lorem ipsum www.kandaoni.com lorem ipsum</p>
<p>- lorem ipsum www.kandaoni.com/test="test" lorem ipsum</p>
<p>{% endfilter %}</p>

escapejs 会将字符串按\uxxxx编码预设的部分字符。如:

{{ "<p>aaa</p><script>alert('xss');</script><p>bbbb</p>"|escapejs|safe }}

slice 可以对字符串、数组进行截取指定长度的数据。如:

{{ "Test"|slice:"1:" }}
{{ "Test"|slice:":3" }}
{{ "Test"|slice:"1:3"|join:"," }}
{{ intList|slice:"1:5"|join:"," }}

safe Django的模板中会对HTML标签和JS等语法标签进行自动转义,这样是为了安全,防止xss攻击。

如果不想用转义,就使用safe来声明要输出的内容是安全的,它就不会自动转义,也可以使用autoescape标签来控制开启和关闭自动转义:

用safe关闭自动转义
{{ "<script>alert('xss');</script>"|safe}}
强制开启自动转义
{% autoescape on %}
{{ "<script>alert('xss');</script>" }}
{% endautoescape %}
强制关闭自动转义,相当于使用了safe
{% autoescape off %}
{{ "<script>alert('xss');</script>" }}
{% endautoescape %}

escape escape 还可以进行声明转义。由于默认已经会自动转义,因此在此使用escape的话,会形成转义2次。因此使用autoescape off关闭转义后,再使用escape就等于直接输出。如:

{{ "<script>alert('xss');</script>" }}
相当于
{% autoescape off %}
{{ "<script>alert('xss');</script>"|escape }}
{% endautoescape %}

上面所有的filter 标签,都可以使用{% filter 标签名 %}内容{% endfilter %} 来使用。比如:

{% filter lower %}This is a nice test; let's see whether it works. Foobar. {{ simple.xss }}{% endfilter %}

{% filter truncatechars:10|lower|length %}This is a nice test; let's see whether it works. Foobar. {{ simple.number }}{% endfilter %}

<p>{% filter urlize:false|safe %}</p>
<p>- lorem ipsum www.kandaoni.com/test="test" lorem ipsum</p>
<p>{% endfilter %}</p>

for 遍历数组、slice等对象

for用于循环访问数组中的每个项目,从而使该项目在上下文变量中可用。 例如,要显示articleList中提供的文章列表:

{% for item in articles %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <h5 class="title">{{item.Title}}</h5>
    </a>
</li>
{% endfor %}

还可以输出for循环的计数,以及剩余数量,还可以使用pluralize判断数量是否是复数。如:

{% for item in articles %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <h5 class="title">第{{ forloop.Counter }}篇,剩余{{ forloop.Revcounter}}篇,{{ forloop.Revcounter|pluralize:"多于1篇" }}:{{item.Title}}</h5>
    </a>
</li>
{% endfor %}

for 还可以使用reversed翻转数组,sorted按int排序数组。如:

{% for item in articles reversed %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <h5 class="title">{{item.Title}}</h5>
    </a>
</li>
{% endfor %}
{% for item in articles sorted %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <h5 class="title">{{item.Title}}</h5>
    </a>
</li>
{% endfor %}
{% for item in articles reversed sorted %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <h5 class="title">{{item.Title}}</h5>
    </a>
</li>
{% endfor %}

for还支持判断是否为空数组或者nil等,使用empty来输出不存在的情况。如:

{% for item in articles %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <h5 class="title">{{item.Title}}</h5>
    </a>
</li>
{% empty %}
<div>没有内容</div>
{% endfor %}

它等价于使用if判断,但是这样写可以更简洁:

{% if articles %}
{% for item in articles %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <h5 class="title">{{item.Title}}</h5>
    </a>
</li>
{% endfor %}
{% else %}
<div>没有内容</div>
{% endif %}

cycle 标签。在for循环中,我们还可以使用cycle标签,来循环逐个输出定义中的变量。

每次遇到此cycle标签时,都会产生其参数之一。 第一个参数在第一次遇到时产生,第二个参数在第二次遇到时产生,依此类推。 一旦所有参数用尽,标记将循环到第一个参数并再次产生它。

此标记在循环中特别有用。如:

{% for item in articles %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <h5 class="title">Title,Id 逐个出现:{% cycle item.Title item.Id %}</h5>
    </a>
</li>
{% endfor %}

或者使用as 来定义别名,再通过别名输出:

{% for item in articles %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        {% cycle item.Title item.Id as cycleitem %}
        <h5 class="title">Title,Id 逐个出现:{{ cycleitem }}</h5>
    </a>
</li>
{% endfor %}

在模板中使用数学算术计算

整数和复数表达式 integers and complex expressions
{{ 10-100 }}
{{ -(10-100) }}
{{ -(-(10-100)) }}
{{ -1 * (-(-(10-100))) }}
{{ -1 * (-(-(10-100)) ^ 2) ^ 3 + 3 * (5 - 17) + 1 + 2 }}

浮点数 floats
{{ 5.5 }}
{{ 5.172841 }}
{{ 5.5 - 1.5 == 4 }}
{{ 5.5 - 1.5 == 4.0 }}

乘法、除法、整除 mul/div
{{ 2 * 5 }}
{{ 2 * 5.0 }}
{{ 2 * 0 }}
{{ 2.5 * 5.3 }}
{{ 1/2 }}
{{ 1/2.0 }}
{{ 1/0.000001 }}

逻辑表达式 logic expressions
{{ !true }}
{{ !(true || false) }}
{{ true || false }}
{{ true or false }}
{{ false or false }}
{{ false || false }}
{{ true && (true && (true && (true && (1 == 1 || false)))) }}

浮点数比较 float comparison
{{ 5.5 <= 5.5 }}
{{ 5.5 < 5.5 }}
{{ 5.5 > 5.5 }}
{{ 5.5 >= 5.5 }}

取模、取余 remainders
{{ (simple.number+7)%7 }}
{{ (simple.number+7)%7 == 0 }}
{{ (simple.number+7)%6 }}

判断一个变量是否在另一个结果集中 in/not in
{{ 5 in simple.intmap }}
{{ 2 in simple.intmap }}
{{ 7 in simple.intmap }}
{{ !(5 in simple.intmap) }}
{{ not(7 in simple.intmap) }}
{{ 1 in simple.multiple_item_list }}
{{ 4 in simple.multiple_item_list }}
{{ !(4 in simple.multiple_item_list) }}
{{ "Hello" in simple.misc_list }}
{{ "Hello2" in simple.misc_list }}
{{ 99 in simple.misc_list }}
{{ False in simple.misc_list }}

associativity for infix operators
{{ 34/3*3 }}
{{ 10 + 24 / 6 / 2 }}
{{ 6 - 4 - 2 }}

int const与uint比较 uint comparison with int const
{{ simple.uint }}
{{ simple.uint == 8 }}
{{ simple.uint == 9 }}
{{ simple.uint >= 8 }}
{{ simple.uint <= 8 }}
{{ simple.uint < 8 }}
{{ simple.uint > 8 }}

移除模板逻辑标签占用的行

这个需求很多时候会用到,比如在if-elseif 中 或者是for循环中,它会连if-else标签部分的行的空行也输出。如果想清理这一行空行,可以在标签里面的前方或后方使用-来实现过滤,如:

{%- if false %}
1st choice
{%- elif false %}
2nd choice
{%- elif true %}
3rd choice
{%- endif %}
正常下
{% for item in articles %}
{{ item.Id }}
{% endfor %}
紧凑:
{% for item in articles %}
{{- item.Id }}
{% endfor %}
不带换行
{% for item in articles -%}
{{ item.Id }}
{%- endfor %}

在模板中使用struct结构体内置方法

比如在article列表中,article的结构体中,定义了内置函数func (article *Article) GetThumb(),那么在模板中,是可以直接调用的。如:

{% for item in articles %}
<li class="item">
    <a href="/article/{{item.Id}}" class="link">
        <img src="{{item.GetThumb()}}" alt="{{item.Title}}" />
        <h5 class="title">{{item.Title}}</h5>
    </a>
</li>
{% endfor %}

模板可以直接使用{{item.GetThumb()}}来调用内置的article.GetThumb()方法。

在模板中定义变量并赋值

iris.Django模板引擎的模板解析器提供了可以在模板中声明变量并使用的方法with。通过with我们可以临时声明单个或多个变量,提供后续使用。多数情况下,我们会将它配合include标签使用。如:

{% with title="这是声明给header使用的title" keywords="这是声明给header使用的keywords" %} %}标题:{{title}},关键词:{{keywords}}。{% endwith %}
{% include "partial/header.html" with title="这是声明给header使用的title" keywords="这是声明给header使用的keywords" %}

with定义的变量需要使用endwith来包裹。

另外iris.Django还提供set的方式来声明变量,这个变量可以在当前模板使用。如:

{% set new_var = "hello" %}{{ new_var }}
{% block content %}{% set new_var = "world" %}{{ new_var }}{% endblock %}
{{ new_var }}{% for item in simple.misc_list %}
{% set new_var = item %}{{ new_var }}{% endfor %}
{{ new_var }}
{% set car=someUndefinedVar %}{{ car.Drive }}No Panic

在模板中输出当前时间

now标签提供在模板中输出当前时间。now格式化时间的参数遵循golang的时间格式化规则。如果增加fake 参数,则会输出一个特定的加时间代替当前时间。如:

{% now "Mon Jan 2 15:04:05 -0700 MST 2006" fake %}
{% now "2006-01-02 15:04" %}

lorem 随机生成拉丁文样本数据

显示随机的“ lorem ipsum”拉丁文本。 这对于在模板中提供样本数据很有用。也就是占位内容。在开发模板没有真实数据的时候,使用这个标签可以快速填充足够多的随机数据。如:

-----
{% lorem %}
-----
{% lorem 10 %}
-----
{% lorem 3 p %}
-----
{% lorem 100 w %}
-----

模板的注释

iris.Django的注释我们使用大括号+#来实现注释:{# 注释内容 #}

单行注释使用 {# 这只能注释单行 #},多行注释使用 {% comment %}这里注释很多行{% endcomment %}

示例:

空单行注释

{# #}

单行注释

{# testing single line comment #}

用有效标签填充单行注释

{# testing single line comment {% if thing %}{% endif %} #}

用无效标签填充单行注释

{# testing single line comment {% if thing %} #}

用无效语法填充单行注释

{# testing single line comment {% if thing('') %}wow{% endif %} #}

空块注释

{% comment %}{% endcomment %}

填充文本单行块注释

{% comment %}filled block comment {% endcomment %}

空多行块注释

{% comment %}


{% endcomment %}

阻止带有其他标签的注释

{% comment %}
  {{ thing_goes_here }}
  {% if stuff %}do stuff{% endif %}
{% endcomment %}

阻止其中带有无效标签的注释

{% comment %}
  {% if thing %}
{% endcomment %}

使用无效语法阻止注释

{% comment %}
  {% thing('') %}
{% endcomment %}

注释之间的常规标签,以确保其在词法分析器中不会中断

{% if hello %}
{% endif %}
after if
{% comment %}All done{% endcomment %}

后端传递变量到模板

实际网站开发中,我们在控制器中的变量,需要使用特定的函数ctx.ViewData("article", article)注入到view中,才能在模板中使用这个变量,比如,我们在IndexPage()控制器中定义一个article,然后将它传递到模板中,用来输出。

我们先在index.go 中的 IndexPage() 函数中添加如下代码

func IndexPage(ctx iris.Context) {
    nowStamp := time.Now().Unix()
    ctx.ViewData("nowStamp", nowStamp)

    article := model.Article{
        Id:          1,
        Title:       "这是一篇文章",
        Keywords:    "这是关键词",
        Description: "这是描述",
        CategoryId:  1,
        Views:       1,
        Category:    model.Category{
            Title: "这是分类名称",
        },
        ArticleData: model.ArticleData{
            ArticleId: 1,
            Content: "<div>内容在此</div>",
        },
    }
    ctx.ViewData("article", article)
    ctx.View("index.html")
}

然后在index.html模板中输出:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Hello World</title>
</head>
<body>
Hello World!<br>
{{stampToDate(nowStamp, "2006-01-02 15:04:05")}}<br>
<div>文章标题:{{article.Title}}</div>
<div>文章分类:{{article.Category.Title}}</div>
<div>文章Id:{{article.Id}}</div>
<div>发布时间:{{stampToDate(article.CreatedTime)}}</div>
<div>文章关键词:{{article.Keywords}}</div>
<div>文章描述:{{article.Description}}</div>
<div>文章内容:{{article.ArticleData.Content|safe}}</div>
</body>
</html>

这样,就模板就获得了article变量,然后通过模板语法,将article的成员都输出了。

完整的项目示例代码托管在GitHub上,需要查看完整的项目代码可以到github.com/fesiong/goblog 上查看,也可以直接fork一份来在上面做修改。


开发小程序的之朴
13 声望3 粉丝