目录
模版是纯文本文件,可以生成任何基于文本的文件格式,比如HTML,XML,CSV等。Django模版语言致力于在性能和简单性上取得平衡。Django的模版系统并不是简单的将Python嵌入到HTML中。
下面是一个小模版,它展示了一些基本的元素。
{% extends "base_generic.html" %}{% block title %}{{ section.title }}{% endblock %}{% block content %}<h1>{{ section.title }}</h1>{% for story in story_list %}<h2> <a href="{{ story.get_absolute_url }}"> {{ story.headline|upper }} </a></h2><p>{{ story.tease|truncatewords:"100" }}</p>{% endfor %}{% endblock %}注意: 调用对象里面的方法的时候,不需要写括号来执行,并且只能执行不需要传参数的方法,如果你的这个方法需要传参数,那么模板语言不支持,不能帮你渲染
每一个Web框架都需要一种很便利的方法用于动态生成HTML页面。 最常见的做法是使用模板。模板包含所需HTML页面的静态部分,以及一些特殊的模版语法,用于将动态内容插入静态部分。
Django可以配置一个或多个模板引擎(语言),也可以不用引擎。Django自带一个称为DTL(Django Template Language )的模板语言,以及另外一种流行的Jinja2语言(需要安装,pip install Jinja2)。
Django为加载和渲染模板定义了一套标准的API,与具体的后台无关。加载指的是,根据给定的模版名称找到的模板然后预处理,通常会将它编译好放在内存中。渲染则表示,使用Context数据对模板插值并返回生成的字符串。
变量相关的用{{}},逻辑相关的用{%%}。模板渲染的官方文档:(https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#std:templatetag-for)本文参考官方文档,即用的是DTL引擎。
Django模板语言的语法包括四种结构:变量、标签、过滤器、注释。
变量的值来自context中的数据字典, 类似于字典对象的keys到values的映射关系。
在Django的模板语言中按此语法使用:{{ 变量名 }}。当模版引擎遇到一个变量,它将从上下文context中获取这个变量的值,然后用值替换掉它本身。 变量的命名包括任何字母数字以及下划线的组合。变量名称中不能有空格或标点符号。
深度查询据点符(.)在模板语言中有特殊的含义。当模版系统遇到点("."),它将以这样的顺序查询:
注意事项:
{{ foo.bar }}
这种模版表达式中的“bar”,如果在模版上下文中存在,将解释为一个字面意义的字符串而不是使用变量bar的值 。模版语言中的标签类似Python中的函数,可以输出内容、控制结构,甚至可以访问其他的模板标签。
{% csrf_token %} # csrf令牌标签,用于POST提交。
部分标签需要使用起始和闭合标签。
循环对象中每个元素。需要结束标签{% endfor %}
。
显示athlete_list中提供的运动员列表:<ul>{% for athlete in athlete_list %} <li>{{ athlete.name }}</li>{% endfor %}</ul>循环对象points的每个元素都是(x,y)这样的二元元组,并返回:{% for x, y in points %} There is a point at {{ x }},{{ y }}{% endfor %}访问一个字典中的键值:{% for key, value in data.items %} {{ key }}: {{ value }}{% endfor %}
可以使用{% for obj in list reversed %}
进行反向循环。
下面是Django为for标签内置的一些属性,可以当作变量一样使用{{ }}
在模版中使用。
forloop.counter:循环的当前索引值,从1开始计数;常用于生成一个表格或者列表的序号forloop.counter0:循环的当前索引值,从0开始计数;forloop.revcounter: 当前循环的倒序索引值(最后一个为1)forloop.revcounter0 当前循环的倒序索引值(最后一个为0)forloop.first:判断当前是否循环的第一次,是的话,该变量的值为True。forloop.last:如果这是最后一次循环,则为真forloop.parentloop:对于嵌套循环,返回父循环所在的循环次数。
for标签带有一个可选的{% empty %}
从句,以便在循环对象是空的或者没有被找到时,可以有所操作和提示。
<ul>{% for athlete in athlete_list %} <li>{{ athlete.name }}</li>{% empty %} # 若列表为空,则执行。 <li>Sorry, no athletes in this list.</li>{% endfor %}</ul>
需要{% endif %}
结束标签。
{% if athlete_list %} Number of athletes: {{ athlete_list|length }}{% elif athlete_in_locker_room_list %} Athletes should be out of the locker room soon!{% else %} No athletes.{% endif %}
还可以在if标签支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not
判断等多种运算符,注意条件两边都有空格。也可使用过滤器。
{% if somevar == "x" %} This appears if variable somevar equals the string "x"{% endif %}{% if athlete_list|length > 1 %} Team: {% for athlete in athlete_list %} ... {% endfor %}{% else %} Athlete: {{ athlete_list.0.name }}{% endif %}# 注意,大多数模版过滤器都返回字符串类型,所以使用过滤器做整数类型的比较通常是错误的,但length是一个例外。
操作符都可以组合以形成复杂表达式。操作符的优先级从低至高如下:
orandnotin==,!=,<,>,<= ,>=与Python的规则是一样的。
如果想要不同的优先级,那么需要使用嵌套的if标签,而不能使用圆括号。比较运算符不能像Python或数学符号中那样“链接”。
{% if a > b > c %} (错误的用法){% if a > b and b > c %} (正确的用法){% if athlete_list and coach_list %} Both athletes and coaches are available.{% endif %}{% if not athlete_list %} There are no athletes.{% endif %}{% if athlete_list or coach_list %} There are some athletes or some coaches.{% endif %}{% if not athlete_list or coach_list %} There are no athletes or there are some coaches.{% endif %}{% if athlete_list and not coach_list %} There are some athletes and absolutely no coaches.{% endif %}
使用一个简单地名字缓存一个复杂的变量,多用于给一个复杂的变量起别名。当需要使用一个代价较大的方法(比如访问数据库)很多次的时候这是非常有用的。
像这样:
{% with total=business.employees.count %} {{ total }} <!--只能在with语句体内用-->{% endwith %}或:{% with business.employees.count as total %} {{ total }}{% endwith %}
可以分配多个变量:
{% with alpha=1 beta=2 %} ...{% endwith %}
注意等号左右不要加空格。
若不使用此标签以post方式提交表单时,会报错。如果在settings里面的中间件配置里把csrf的防御机制给注销,则不会报错,但不安全。这个标签用于跨站请求伪造保护。
在页面的form表单里面任何位置写上{% csrf_token %},在模板渲染的时将被替换成类似于下方的input标签:<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">这个标签的值是个随机字符串,提交的时候,值也被提交了,首先这个标签是后端渲染给页面加上的,那么当通过form表单提交数据时候,后台django有相同的一个值,可以做对应验证是不是我给你的token,如果用户没有按照这个正常的页面来post提交表单数据,那么就能知道这个请求是非法的,反爬虫或者恶意攻击网站
注释可以包含任何模版内的代码,有效的或者无效的都可以。当要注释掉一些代码时,可以用此来记录代码被注释掉的原因。单行注释语法:{# #}
{# this won't be rendered #} # 单行注释
{% comment %}
标签提供多行注释功能。
在{% comment %}
和{% endcomment %}
之间的内容会被忽略,作为注释。例如:
<p>Rendered text with {{ pub_date|date:"c" }}</p>{% comment "Optional note" %} <p>Commented out text with {{ create_date|date:"c" }}</p>{% endcomment %}
comment标签不能嵌套使用。
继承和复写模版。类似Python的类继承和重写机制。
extends标签表示当前模板继承自一个父模板。
这个标签可以有两种用法:
Django模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承允许你创建一个包含基本“骨架”的父亲模版,它包含站点中的共有元素,并且可以定义能够被子模版覆盖的blocks。通过下面这个例子,理解模版继承的概念:
<!DOCTYPE html><html lang="en"><head> <link rel="stylesheet" href="style.css" /> <title>{% block title %}My amazing site{% endblock %} </title>#注意此处,block标签。</head><body> <div id="sidebar"> {% block sidebar %} #注意此处 <ul> <li><a href="/">Home</a></li> <li><a href="/blog/">Blog</a></li> </ul> {% endblock %} #结束标签 </div> <div id="content"> {% block content %} {% endblock %} #注意此处 </div></body></html>
这个模版,通常被命名为base.html
,它定义了一个可以用于两列排版页面的简单HTML骨架。
“子模版”需要做的是先继承父模板base.html
,然后复写、填充,或者说实现其中的blocks。
block是在子模版中可能会被覆盖掉的位置。在上面的例子中,block标签定义了三个可以被子模版内容填充的block,分别是title、content和siderbar。
子模版可能看起来是这样的:
{% extends "base.html" %} #extends标签是这里的关键。它告诉模版引擎,这个模版“继承”了另一个模版。当模版系统处理这个模版时,首先会去加载父模版,也就是“base.html”。{% block title %}My blog{% endblock %} #修改base里title标签里的内容。{% block content %}{% for entry in blog_entries %} <h2>{{ entry.title }}</h2> <p>{{ entry.body }}</p>{% endfor %}{% endblock %}# 加载过程中,模版引擎将注意到base.html中的三个block标签,并用子模版中的内容来替换这些block。
请注意,上面例子中的子模版并没有定义sidebar block
,这种情况下,将使用父模版中的内容。父模版的{% block %}
标签中的内容总是被用作默认内容。
Django多级继承常用方式类似下面的三级结构:
base.html
模版,用来控制整个站点的主要视觉和体验。base_SECTIONNAME.html
模版。 例如base_news.html
,base_sports.html
。这些模版都继承base.html
,并且包含了各自特有的样式和设计。上面的方式可以使代码得到最大程度的复用,并且使得添加内容到共享的内容区域更加简单,例如app范围内的导航条。
使用继承的一些相关说明:
如果在模版中使用{% extends %}
标签,它必须是模版中的第一个标签,必须放在文件首行。
在base模版中设置越多的{% block %}
标签越好。子模版不必定义全部父模版中的blocks,所以可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
如果发现自己在复制大量重复的模版内容,那意味着应该把重复的内容移动到父模版中的一个{% block %}
中。
如果需要获取父模板中的block的内容,想要在父block中新增内容而不是完全覆盖它,可以使用{{ block.super }}
变量。使用{{ block.super }}
插入的数据不会被自动转义,因为父模板中的内容已经被转义。
在{% block %}
之外创建的变量使用模板标签的as
语法,不能在块内使用。
例如,下面的模板不会显示任何内容:
{% trans "Title" as title %}{% block content %}{{ title }}{% endblock %}
为了更好的可读性,可以给{% endblock %}
标签一个取名字,如:{% block content %}
。在大型模版中,这有助于你清楚的看到哪一个{% block %}
标签被关闭了。
不能在一个模版中定义多个相同名字的block标签。
Django1.10中添加了使用相对路径的能力。通常模板名称是相对于模板加载器的根目录。字符串参数也可以是以./
或../
开头的相对路径。 例如,假设有以下目录结构:
dir1/ template.html base2.html my/ base3.htmlbase1.html
在template.html中,以下路径将有效:
{% extends "./base2.html" %}{% extends "../base1.html" %}{% extends "./my/base3.html" %}
于url的反向解析。返回与给定视图和可选参数匹配的绝对路径引用(不带域名的URL)。在解析后返回的结果路径字符串中,每个特殊字符将使用iri_to_uri()
编码。这可以避免在模板中硬编码超级链接路径。
{% url 'some-url-name' v1 v2 %}
第一个参数是url()
的名字。 它可以是一个被引号引起来的字符串或者其他的上下文变量。其他参数是可选的并且以空格隔开,这些值会在URL中以参数的形式传递。上面的例子展示了如何传递位置参数,也可以使用关键字参数。
{% url 'some-url-name' arg1=v1 arg2=v2 %}
不要把位置参数和关键字参数混在一起使用。URLconf所需的所有参数都应该提供。
例如,假设有一个视图app_views.client
,其URLconf接受客户端ID,并如下所示:
('^client/([0-9]+)/$', app_views.client, name='app-views-client')
如果你的应用中的URLconf已经被包含到项目URLconf中,比如下面这样
('^clients/', include('project_name.app_name.urls'))
然后,在模板中,你可以创建一个此视图的链接,如下所示:
{% url 'app-views-client' client.id %}
模板标签会输出字符串:/clients/client/123/
如果希望在不显示网址的情况下检索网址,可以使用略有不同的调用:
{% url 'some-url-name' arg arg2 as the_url %}<a href="{{ the_url }}">I'm linking to {{ the_url }}</a>
如果视图不存在,{% url ... as var %}
语法不会导致错误。
{% url 'some-url-name' as the_url %}{% if the_url %} <a href="{{ the_url }}">Link to optional stuff</a>{% endif %}
如果使用urlconf的名称空间网址,通过冒号指定完全名称,如下所示:
{% url 'myapp:view-name' %}
加载指定的模板并以标签内的参数渲染。这是一种引入别的模板的方法,要将include和extend区分开,include类似Python的import。
{% include "foo/bar.html" %}也可以使用变量名:{% include template_name %}
下面这个示例生成输出“Hello, John!”:
context:变量greeting="Hello",变量person="John"。
模板:
{% include "name_snippet.html" %}
name_snippet.html模板:
{{ greeting }}, {{ person|default:"friend" }}!
可以使用关键字参数将额外的上下文传递到模板:
{% include "name_snippet.html" with person="Jane" greeting="Hello" %}
如果仅使用提供的变量来渲染上下文,添加only选项。
{% include "name_snippet.html" with greeting="Hi" only %}
将子模版渲染并嵌入当前HTML中的变种方法,不是解析子模版并在被父模版包含的情况下展现其被父模版定义的内容。这意味着在不同的被包含的子模版之间并不共享父模版的状态,每一个子模板包含都是完全独立的渲染过程。
加载自定义模板标签。
下面的模板将会从somelibrary和package包中的otherlibrary中载入所有已经注册的标签和过滤器。
{% load somelibrary package.otherlibrary %}
还可以使用from参数从库中选择性加载单个过滤器或标记。
{% load foo bar from somelibrary %}
可以查询下表来总览Django的内置标签:
标签
说明
autoescape
自动转义开关
block
块引用
comment
注释
csrf_token
CSRF令牌
cycle
循环对象的值
debug
调试模式
extends
继承模版
filter
过滤功能
firstof
输出第一个不为False的参数
for
循环对象
for … empty
带empty说明的循环
if
条件判断
ifequal
如果等于
ifnotequal
如果不等于
ifchanged
如果有变化,则..
include
导入子模版的内容
load
加载标签和过滤器
lorem
生成无用的废话
now
当前时间
regroup
根据对象重组集合
resetcycle
重置循环
spaceless
去除空白
templatetag
转义模版标签符号
url
获取url字符串
verbatim
禁用模版引擎
widthratio
宽度比例
with
上下文变量管理器
控制自动转义是否可用。参数是on或off。 该标签会以一个endautoescape作为结束标签.
例如:
{% autoescape on %} {{ body }}{% endautoescape %}
每当这个标签被访问,返回它的下一个元素。第一次访问返回第一个元素,第二次访问返回第二个参数,以此类推. 一旦所有的变量都被访问过了,就会回到最开始的地方,重复下去。在循环中特别有用:
{% for o in some_list %} <tr class="{% cycle 'row1' 'row2'%}"> ... </tr>{% endfor %}
cycle的本质是根据某个规律,提供某种特性,比如想循环给表格的行添加底色等等。
也可以使用变量, 例如,有两个模版变量:rowvalue1和rowvalue2, 可以让他们的值像这样替换:
{% for o in some_list %} <tr class="{% cycle rowvalue1 rowvalue2 %}"> ... </tr>{% endfor %}
被包含在cycle中的变量将会被转义。 可以禁止自动转义:
{% for o in some_list %} <tr class="{% autoescape off %}{% cycle rowvalue1 rowvalue2 %}{% endautoescape %}"> ... </tr>{% endfor %}
可以混合使用变量和字符串:
{% for o in some_list %} <tr class="{% cycle 'row1' rowvalue2 'row3' %}"> ... </tr>{% endfor %}
在某些情况下,可能需要连续引用一个当前循环的值,而不前进到下一个循环值。要达到这个目的,只需使用as
来给{% cycle %}
取一个别名,就像这样:
{% cycle 'row1' 'row2' as rowcolors %}
设置别名后,就可以将别名当作一个模板变量进行引用,从而随意在模板中插入当前循环的值。 如果要将循环值移动到原始cycle标记的下一个值,可以使用另一个cycle标记并指定变量的名称。看下面的例子:
<tr> <td class="{% cycle 'row1' 'row2' as rowcolors %}">...</td> <td class="{{ rowcolors }}">...</td></tr><tr> <td class="{% cycle rowcolors %}">...</td> <td class="{{ rowcolors }}">...</td></tr>
将输出:
<tr> <td class="row1">...</td> <td class="row1">...</td></tr><tr> <td class="row2">...</td> <td class="row2">...</td></tr>
cycle 标签中,通过空格分割,可以使用任意数量的值。被包含在单引号(')或者双引号(")中的值被认为是可迭代字符串,相反,没有被引号包围的值被当作模版变量。
输出整个调试信息,包括当前上下文和导入的模块。
通过一个或多个过滤器对内容过滤。需要结束标签endfilter。
例如:
{% filter force_escape|lower %} This text will be HTML-escaped, and will appear in all lowercase.{% endfilter %}
输出第一个不为False参数。 如果传入的所有变量都为False,就什么也不输出。
例如:
{% firstof var1 var2 var3 %}它等价于:{% if var1 %} {{ var1 }}{% elif var2 %} {{ var2 }}{% elif var3 %} {{ var3 }}{% endif %}
可以用一个默认字符串作为输出以防止传入的所有变量都是False:
{% firstof var1 var2 var3 "fallback value" %}
检查一个值是否在上一次的迭代中被改变了。
{% ifchanged %}
标签通常用在循环里。它有两个用处:
检查已经渲染过的内容的当前状态。并且只会显示发生改变的内容。例如,以下的代码是输出days的列表项,不过它只会输出被修改过月份的项:
<h1>Archive for {{ year }}</h1>{% for date in days %} {% ifchanged %}<h3>{{ date|date:"F" }}</h3>{% endifchanged %} <a href="{{ date|date:"M/d"|lower }}/">{{ date|date:"j" }}</a>{% endfor %}
如果标签内有多个值时,则会比较每一个值是否与上一次不同。例如,以下显示每次更改时的日期,如果小时或日期已更改,则显示小时:
{% for date in days %} {% ifchanged date.date %} {{ date.date }} {% endifchanged %} {% ifchanged date.hour date.date %} {{ date.hour }} {% endifchanged %}{% endfor %}
ifchanged标记也可以采用可选的{% else %}
将显示值没有改变的情况:
{% for match in matches %} <div style="background-color: {% ifchanged match.ballot_id %} {% cycle "red" "blue" %} {% else %} gray {% endifchanged %} ">{{ match }}</div>{% endfor %}
用来在模版中提供文字样本以供测试用的。使用这个方法,可以帮你自动填充一些可以阅读的内容。
{% lorem [count] [method] [random] %}
可以使用零个,一个,两个或三个参数。 这些参数是:
count :一个数字(或变量),其中包含要生成的段落或字数(默认值为1)。
method:HTML中使用p标签、还是w标签、还是b标签,决定文本格式。默认是“b”。
random:如果给出的话,random这个词在生成文本时不会使用公共段落。 例子:
{% lorem %} # 将输出常见的“lorem ipsum”段落。{% lorem 3 p %} # 输出常用的“lorem ipsum”段落和两个随机段落,每段包裹在
标签中。{% lorem 2 w random %} # 将输出两个随机拉丁字。
显示当前的日期或时间。可以指定显示的格式。 如:
It is {% now "jS F Y H:i" %}
下面的例子中,“o”和“f”都被反斜杠转义:
It is the {% now "jS \o\f F" %}# 这将显示为“It is the 4th of September”。
还可以使用语法{% now “Y” as current_year %}
将输出存储在变量中。
{% now "Y" as current_year %}{% blocktrans %}Copyright {{ current_year }}{% endblocktrans %}
用对象间共有的属性重组列表。
对于下面的数据:
cities = [ {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'}, {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'}, {'name': 'New York', 'population': '20,000,000', 'country': 'USA'}, {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'}, {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},]
如果你想显示按国家/地区排序的分层列表,如下所示:
India Mumbai: 19,000,000 Calcutta: 15,000,000USA New York: 20,000,000 Chicago: 7,000,000Japan Tokyo: 33,000,000
可以使用{% regroup %}
标签来给每个国家的城市分组:
{% regroup cities by country as country_list %}<ul>{% for country in country_list %} <li>{{ country.grouper }} <ul> {% for city in country.list %} <li>{{ city.name }}: {{ city.population }}</li> {% endfor %} </ul> </li>{% endfor %}</ul>
{% regroup %}
有三个参数: 要重组的列表、用来分组的属性、结果列表的名字。在这里,我们通过country
属性重新分组cities列表,并将结果保存在country_list
中。
country_list
的每个元素是具有两个字段的namedtuple()
的实例:
重置先前的循环,以便在下一次循环时从其第一个项目重新启动。如果没有参数,{% resetcycle %}
将重置最后一个{% cycle %}
。例:
{% for coach in coach_list %} <h1>{{ coach.name }}</h1> {% for athlete in coach.athlete_set.all %} <p class="{% cycle 'odd' 'even' %}">{{ athlete.name }}</p> {% endfor %} {% resetcycle %}{% endfor %}
这个示例将返回下面的HTML:
<h1>José Mourinho</h1><p class="odd">Thibaut Courtois</p><p class="even">John Terry</p><p class="odd">Eden Hazard</p><h1>Carlo Ancelotti</h1><p class="odd">Manuel Neuer</p> # 第一个块以class="odd"结束,新的以class="odd"开头。没有`{% resetcycle %}`标签,第二个块将以class="even"开始。<p class="even">Thomas Müller</p>
还可以重置循环标签:
{% for item in list %} <p class="{% cycle 'odd' 'even' as stripe %} {% cycle 'major' 'minor' 'minor' 'minor' 'minor' as tick %}"> {{ item.data }} </p> {% ifchanged item.category %} <h1>{{ item.category }}</h1> {% if not forloop.first %}{% resetcycle tick %}{% endif %} {% endifchanged %}{% endfor %}
在这个例子中,交替的奇数/偶数行和每五行出现一次的‘major’行。当类别更改时,只有五行周期被重置。
删除HTML标签之间的空白,包括制表符和换行。例:
{% spaceless %} <p> <a href="foo/">Foo</a> </p>{% endspaceless %}# 将返回下面的HTML:<p><a href="foo/">Foo</a></p>
仅会删除tags之间的空格,不会删除标签和文本之间的。例:
{% spaceless %} <strong> Hello # Hello周围的空格不会被删除 </strong>{% endspaceless %}
输出用于构成模板标签的语法字符。
由于模板系统没有“转义”的概念,无法在HTML中使用‘\’转义出类似{%
的字符。为了显示模板标签本身,必须使用{% templatetag %}
标签,并添加相应的参数:
{%
%}
{{
}}
{
}
{#
#}
例如:
{% templatetag openblock %} url 'entry_list' {% templatetag closeblock %}
禁止模版引擎在该标签中进行渲染工作。
常见的用法是允许与Django语法冲突的JavaScript模板图层工作。 像这样:
{% verbatim %} {{if dying}}Still alive.{{/if}}{% endverbatim %}
为了创建柱状形图,此标签计算给定值与最大值的比率,然后将该比率应用于常量。
如:
<img src="bar.png" alt="Bar" height="10" width="{% widthratio this_value max_value max_width %}" />
如果this_value
是175,max_value
是200,并且max_width
是100,则上述示例中的图像将是88像素宽(因为175 / 200 = .875; .875 * 100 = 87.5,四舍五入入为88)。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章