Django模板学习(二)
官网文档:https://docs.djangoproject.com/en/2.0/ref/templates/
一、Django官方文档学习模板
1.1 Django模板语言
模板
模板只是一个文本文件。 它可以生成任何基于文本的格式(HTML,XML,CSV等)。模板包含变量,在模板被评估时被替换为值,以及控制模板逻辑的标签。
下面是一个简单的基本模板。 每个元素将在本文后面解释:
{% 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 %}
变量
变量如下所示:{{variable}}。 当模板引擎遇到变量时,它会评估该变量并将其替换为结果。 变量名称由字母数字字符和下划线(“_”)的任意组合组成。 点(“.”)也出现在变量部分,但具有特殊含义,如下所示。 重要的是,变量名中不能包含空格或标点符号。使用点(.)来访问变量的属性。
从技术上讲,当模板系统遇到点时,会按以下顺序尝试以下查找:
字典查找 属性或方法查找 数字索引查找
如果结果值是可调用的,则不带参数调用它。 该调用的结果成为模板值。此查找顺序可能会导致一些意外行为,其中的对象会覆盖字典查找。 例如,考虑下面的代码片段,它试图遍历一个collections.defaultdict:
{% for k, v in defaultdict.items %} Do something with k and v here... {% endfor %}
#由于字典查找首先发生,该行为将启动并提供默认值,而不是使用预期的.items()方法。 在这种情况下,请考虑首先转换为字典。
在上面的例子中,{{section.title}}将被替换为section对象的title属性。如果您使用不存在的变量,则模板系统将插入string_if_invalid选项的值,该选项默认设置为“'(空字符串)。请注意,模板表达式{{foo.bar}}中的“bar”将被解释为文字字符串,并且不会使用变量“bar”的值(如果存在于模板上下文中)。
过滤器
可以使用过滤器修改显示的变量。过滤器如下所示:{{name | lower}}。 这将显示{{name}}变量在通过较低过滤器过滤后的值,该过滤器将文本转换为小写。 使用管道(|)应用过滤器。过滤器可以“链接”。一个过滤器的输出应用于下一个过滤器。 {{text | escape | linebreaks}}是转义文本内容的常用方式,然后将换行符转换为<p>标签。有些过滤器需要参数。 过滤器参数如下所示:{{bio | truncatewords:30}}。 这将显示生物变量的前30个单词。必须引用包含空格的过滤器参数; 例如,要使用{{list | join:“,”}}加入包含逗号和空格的列表。
Django提供了大约60个内置模板过滤器。 可以在内置的过滤器参考中阅读所有关于它们的内容。 为了让您了解可用的功能,以下是一些更常用的模板过滤器:
default:
如果变量为假或空,则使用给定的默认值。 否则,使用变量的值。 例如:
{{ value|default:"nothing" }}
#如果未提供value或为空,则上面将显示“nothing”。
length :
返回值的长度。 这适用于字符串和列表。 例如:
{{ value|length }}
#如果值为['a','b','c','d'],则输出为4。
filesizeformat:
将该值格式化为“人可读”文件大小(即“13 KB”,“4.1 MB”,“102字节”等)。 例如:
{{ value|filesizeformat }}
#如果值是123456789,那么输出将是117.7 MB。
再次,这些只是几个例子; 请参阅完整列表的内置过滤器参考(https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#ref-templates-builtins-filters)。
可以创建自己的自定义模板过滤器; 请参阅定制模板标签和过滤器(https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/)。
标签
标签看起来像这样:{%tag%}。 标签比变量更复杂:一些在输出中创建文本,一些通过执行循环或逻辑进行控制流程,还有一些将外部信息加载到模板中供以后的变量使用。一些标签需要开始和结束标签(即{% tag %} ... tag contents ... {% endtag %})。Django附带大约二十个内置模板标签。 可以在内置标签参考中阅读所有关于它们的内容。 为了让了解可用的功能,以下是一些更常用的标签:
for:
循环播放数组中的每个项目。 例如,要显示运动员列表中提供的 athlete_list:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
if, elif, and else
评估一个变量,如果该变量为“true”,则显示该块的内容:
{% 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 %}
#在上面,如果athlete_list不是空的,运动员的数量将由{{athlete_list | length}}变量显示。 否则,如果athlete_in_locker_room_list不为空,则会显示“Athletes should be out…”消息。 如果两个列表都是空的,则显示“No athletes.”。您也可以在if标记中使用过滤器和各种运算符:
{% if athlete_list|length > 1 %} Team: {% for athlete in athlete_list %} ... {% endfor %} {% else %} Athlete: {{ athlete_list.0.name }} {% endif %}
尽管上述示例有效,但请注意,大多数模板过滤器都会返回字符串,因此使用过滤器进行数学比较通常不会像您期望的那样正常工作。 length是一个例外。
block and extends:
设置模板继承,这是减少模板中“boilerplate”的强大方法。
注释:
要在模板中注释部分行,请使用注释语法:{##}。
例如,这个模板会呈现为'hello':
{# greeting #}hello
评论可以包含任何模板代码,无论与否。 例如:
{# {% if foo %}bar{% else %} #}
#此语法只能用于单行注释({#和#}分隔符之间不允许换行符)。 如果您需要注释模板的多行部分,请参阅评论标签(https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#std:templatetag-comment)。
模板继承:
Django模板引擎中最强大,也是最复杂的部分是模板继承。 模板继承允许您构建一个基本“skeleton(骨架)”模板,其中包含您网站的所有常见元素,并定义子模板可以覆盖的块。
从一个例子开始,理解模板继承是最容易的:
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css" /> <title>{% block title %}My amazing site{% endblock %}</title> </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骨架文档,您可以将它用于简单的两列页面。 这是“child”模板的工作来填充内容的空白块。在这个例子中,块标签定义了三个可以填充子模板的块。所有块标签的作用是告诉模板引擎一个子模板可以覆盖模板的那些部分。
子模板可能如下所示:
{% extends "base.html" %} {% block title %}My amazing blog{% endblock %} {% block content %} {% for entry in blog_entries %} <h2>{{ entry.title }}</h2> <p>{{ entry.body }}</p> {% endfor %} {% endblock %}
扩展标签是这里的关键。 它告诉模板引擎该模板“extends”了另一个模板。 当模板系统评估此模板时,首先找到父模板 - 在本例中为“base.html”。此时,模板引擎会注意到base.html中的三个块标签,并将这些块替换为子模板的内容。 根据blog_entries的值,输出可能如下所示:
<!DOCTYPE html> <html> <head> <link rel="stylesheet" href="style.css" /> <title>My amazing blog</title> </head> <body> <div id="sidebar"> <ul> <li><a href="/">Home</a></li> <li><a href="/blog/">Blog</a></li> </ul> </div> <div id="content"> <h2>Entry one</h2> <p>This is my first entry.</p> <h2>Entry two</h2> <p>This is my second entry.</p> </div> </body> </html>
请注意,由于子模板未定义边栏模块,因此将使用父模板的值。 父模板中{%block%}标记中的内容始终用作后备。您可以根据需要使用尽可能多的继承级别。 使用继承的一种常见方式是以下三层方法:
创建一个base.html模板,该模板包含您网站的主要外观。 为您网站的每个“section”创建一个base_SECTIONNAME.html模板。 例如,base_news.html,base_sports.html。 这些模板全部扩展base.html并包含特定部分的样式/设计。 为每种类型的页面创建单独的模板,例如新闻文章或博客条目。 这些模板扩展了适当的部分模板。
此方法可最大限度地重复使用代码,并可轻松将项目添加到共享内容区域,例如部分范围的导航。这里有一些使用继承的技巧:
如果您在模板中使用{%extends%},则它必须是该模板中的第一个模板标记。 模板继承将不起作用,否则。 基本模板中的{%block%}标记更多更好。 请记住,子模板不必定义所有父块,因此您可以在多个块中填写合理的默认值,然后仅定义稍后需要的默认值。 最好有更多的钩子而不是更少的钩子。 如果您发现自己在多个模板中复制了内容,则可能意味着您应该将该内容移至父模板中的{%block%}。 如果您需要从父模板获取块的内容,则{{block.super}}变量将执行该操作。 如果你想添加父块的内容而不是完全覆盖父块的内容,这很有用。 使用{{block.super}}插入的数据不会自动转义(请参阅下一节),因为它已经在父模板中被转义(如有必要)。
使用模板标签作为语法在{%block%}之外创建的变量不能在块内使用。 例如,该模板不会呈现任何内容:
{% trans "Title" as title %} {% block content %}{{ title }}{% endblock %}
为了增加可读性,您可以选择为您的{%endblock%}标签指定一个名称。 例如:
{% block content %} ... {% endblock content %}
在较大的模板中,此技术可帮助您查看哪些{%block%}标签正在关闭。最后,请注意,您不能在同一模板中定义多个具有相同名称的块标记。 这种限制的存在是因为块标签在“两个”方向上工作。 也就是说,块标签不仅提供了一个要填充的洞 - 它还定义填充父项中的洞的内容。 如果模板中有两个相似命名的块标记,则该模板的父级不知道要使用哪个块的内容。
自动HTML转义
从模板生成HTML时,总会有变量包含影响最终HTML的字符的风险。 例如,考虑这个模板片段:
Hello, {{ name }}
起初,这似乎是一种无害的方式来显示用户的名字,但考虑如果用户输入他们的名字会发生什么,如下所示:
<script>alert('hello')</script>
使用该名称值,模板将呈现为:
Hello, <script>alert('hello')</script>
这意味着浏览器会弹出一个JavaScript警告框!同样,如果名称包含一个'<'符号会怎样?
<b>username
这会导致一个像这样的渲染模板:
Hello, <b>username
...这反过来会导致网页的其余部分变粗体。
显然,用户提交的数据不应该盲目地被信任,并且直接插入到您的网页中,因为恶意用户可能会使用这种漏洞来做可能不好的事情。 这种类型的安全漏洞被称为跨站点脚本(XSS)攻击。
为了避免这个问题,你有两个选择:
一,你可以确保通过转义过滤器运行每个不受信任的变量(如下所述),将潜在有害的HTML字符转换为无害的字符。 这是Django头几年的默认解决方案,但问题在于它会将责任推给开发人员/模板创作人员,以确保您逃避一切。 忘记逃离数据很容易。 二,你可以利用Django的自动HTML转义。 本节的其余部分将介绍自动转义的工作原理。
默认情况下,在Django中,每个模板都会自动转义每个变量标签的输出。 具体来说,这五个字符是逃脱的:
<转换为&lt; >被转换为&gt; '(单引号)转换为' “(双引号)转换为” &转换为&amp;
#再次强调,这种行为默认是开启的。 如果使用的是Django的模板系统,那么将受到保护。
#关闭它:https://docs.djangoproject.com/en/2.0/ref/templates/language/#how-to-turn-it-off
字符串文字和自动转义
过滤器参数可以是字符串:
{{ data|default:"This is a string literal." }}
插入所有字符串文本而没有任何自动转义到模板中 - 它们的行为就好像它们都通过了安全筛选器。 这背后的原因是模板作者正在控制字符串文字的内容,所以他们可以确保在写入模板时正确地转义文本。这意味着你会写
{{ data|default:"3 < 2" }}
…而不是:
{{ data|default:"3 < 2" }} {# Bad! Don't do this. #}
这不会影响来自变量本身的数据。 如有必要,变量的内容仍然会自动转义,因为它们超出了模板作者的控制范围。
访问方法调用
连接到对象的大多数方法调用也可以在模板中使用。 这意味着模板可以访问的不仅仅是类属性(如字段名称)和从视图传入的变量。 例如,Django ORM提供了“entry_set”语法,用于查找与外键相关的对象集合。 因此,给定一个称为“注释”的模型,并将其与称为“任务”的模型建立外键关系,您可以循环执行给定任务的所有注释,如下所示:
{% for comment in task.comment_set.all %} {{ comment }} {% endfor %}
同样,QuerySets提供了一个count()方法来计算它们包含的对象的数量。 因此,可以通过以下方式获取与当前任务相关的所有注释的计数:
{{ task.comment_set.all.count }}
当然,可以轻松访问您在自己的模型中明确定义的方法,models.py:
class Task(models.Model): def foo(self): return "bar"
template.html:
{{ task.foo }}
由于Django有意限制模板语言中可用的逻辑处理量,因此不可能将参数传递给从模板内访问的方法调用。 数据应该在视图中计算,然后传递给模板进行显示。
自定义标签和过滤器库
某些应用程序提供自定义标签和过滤器库 要在模板中访问它们,请确保应用程序位于INSTALLED_APPS中(我们将为此示例添加'django.contrib.humanize'),然后在模板中使用加载标签:
{% load humanize %} {{ 45000|intcomma }}
在上面,加载标签加载人性化标签库,然后使intcomma过滤器可供使用。 如果您启用了django.contrib.admindocs,则可以查阅管理员的文档区域以查找安装中的自定义库列表。加载标签可以采用多个库名称,用空格分隔。 例:
{% load humanize i18n %}
有关编写自定义模板库(https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/)的信息,请参阅自定义模板标记和过滤器。
自定义库和模板继承
加载自定义标记或过滤器库时,标记/过滤器仅可用于当前模板 - 而不是模板继承路径中的任何父模板或子模板。例如,如果模板foo.html包含{%load humanize%},则子模板(例如,具有{%extends“foo.html”%}“的子模板)将无法访问人性化模板标记和过滤器。 子模板负责自己的{%load humanize%}。这是为了可维护性和完整性的一个特征。
1.2 内置模板标签和过滤器
本文档描述了Django的内置模板标签和过滤器。 建议使用自动文档(如果有的话),因为这还包括安装的任何自定义标签或过滤器的文档
内置标签参考
autoescape
控制当前的自动转义行为。 此标记将on或off作为参数,并确定自动转义是否在块内有效。 该块以endautoescape结尾标记关闭。当自动转义生效时,在将结果放入输出之前(但在应用任何过滤器之后),所有变量内容都应用HTML转义。 这相当于手动将转义过滤器应用于每个变量。唯一的例外是已经标记为“安全”的变量,无论是通过填充变量的代码,还是应用了安全或逃逸过滤器。
示例用法:
{% autoescape on %} {{ body }} {% endautoescape %}
block
定义可以被子模板覆盖的块。 有关更多信息,请参阅模板继承(https://docs.djangoproject.com/en/2.0/ref/templates/language/#template-inheritance)。
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 %}
#评论标签不能嵌套。
csrf_token
此标记用于CSRF保护,如跨站点请求伪造文档中所述(https://docs.djangoproject.com/en/2.0/ref/csrf/)
cycle
每次遇到此标记时都会生成一个参数。 第一个参数是第一次遇到,第二次遇到第二个参数,等等。 一旦所有参数都用完了,标签循环到第一个参数并再次生成它。这个标签在循环中特别有用:
{% for o in some_list %} <tr class="{% cycle 'row1' 'row2' %}"> ... </tr> {% endfor %}
第一次迭代产生的HTML指向类row1,第二次到row2,第三次到row1,等等循环的每次迭代。你也可以使用变量。 例如,如果您有两个模板变量rowvalue1和rowvalue2,则可以在它们的值之间切换,如下所示:
{% for o in some_list %} <tr class="{% cycle rowvalue1 rowvalue2 %}"> ... </tr> {% endfor %}
循环中包含的变量将被转义。 可以禁用自动转义:
{% 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 %}
从此,您可以通过将循环名称作为上下文变量进行引用,从而在您的模板中的任意位置插入循环的当前值。 如果要将循环移动到与原始循环标记无关的下一个值,可以使用另一个循环标记并指定变量的名称。 所以,下面的模板:
<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>
您可以在循环标记中使用任意数量的值,并用空格分隔。 包含在单引号(')或双引号(“)中的值被视为字符串文字,而不带引号的值则被视为模板变量。默认情况下,当您将循环标签使用as关键字时,启动循环的{%cycle%}的使用本身会产生循环中的第一个值。 如果您想要在嵌套循环或包含的模板中使用该值,则可能会出现问题。 如果您只想声明循环但不生成第一个值,则可以添加沉默关键字作为标记中的最后一个关键字。 例如:
{% for obj in some_list %} {% cycle 'row1' 'row2' as rowcolors silent %} <tr class="{{ rowcolors }}">{% include "subtemplate.html" %}</tr> {% endfor %}
这将输出一个<tr>元素列表,其中row1和row2之间交替。 子模板将在其上下文中访问rowcolors,并且该值将与包含它的<tr>的类相匹配。 如果silent关键字被省略,则row1和row2将作为普通文本发送,位于<tr>元素之外。当在循环定义中使用silent关键字时,沉默会自动应用于该特定循环标记的所有后续使用。 即使对{%cycle%}的第二次调用未指定silent,以下模板也不会输出任何内容:
{% cycle 'row1' 'row2' as rowcolors silent %} {% cycle rowcolors %}
可以使用resetcycle标记在下次遇到时从第一个值重新开始{%cycle%}标记。
debug
输出整个调试信息,包括当前上下文和导入的模块。
extends
表示该模板扩展了父模板。这个标签有两种使用方式:
{%extends“base.html”(带引号)使用字面值“base.html”作为父模板的名称来扩展。 {%extends variable%}使用变量的值。 如果变量的计算结果为字符串,Django将使用该字符串作为父模板的名称。 如果变量评估为一个Template对象,Django将使用该对象作为父模板。
通常,模板名称是相对于模板加载程序的根目录。 字符串参数也可以是以./或../开头的相对路径。 例如,假设以下目录结构:
dir1/ template.html base2.html my/ base3.html base1.html
在template.html中,以下路径将是有效的:
{% extends "./base2.html" %} {% extends "../base1.html" %} {% extends "./my/base3.html" %}
filter
通过一个或多个过滤器过滤块的内容。 可以使用管道指定多个过滤器,并且过滤器可以具有参数,就像在可变语法中一样。请注意,该块包含过滤器和endfilter标签之间的所有文本。示例用法:
{% filter force_escape|lower %} This text will be HTML-escaped, and will appear in all lowercase. {% endfilter %}
注意:转义和安全过滤器是不可接受的参数。 相反,使用autoescape标签来管理模板代码块的自动转义。
firstof
输出不是False的第一个参数变量。 如果所有传递的变量都是False,则不输出。示例用法:
{% firstof var1 var2 var3 %}
这相当于:
{% if var1 %} {{ var1 }} {% elif var2 %} {{ var2 }} {% elif var3 %} {{ var3 }} {% endif %}
如果所有传递的变量都是False,您还可以使用文字字符串作为回退值:
{% firstof var1 var2 var3 "fallback value" %}
这个标签自动转义变量值。 您可以禁用自动转义:
{% autoescape off %} {% firstof var1 var2 var3 "<strong>fallback value</strong>" %} {% endautoescape %}
或者如果只有一些变量应该被转义,你可以使用:
{% firstof var1 var2|safe var3 "<strong>fallback value</strong>"|safe %}
可以使用语法{% firstof var1 var2 var3 as value %}将输出存储在变量中。
for
循环播放数组中的每个项目,使项目在上下文变量中可用。 例如,要显示运动员列表中提供的运动员列表:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul>
您可以使用{%for obj in list reversed%}反向循环列表。如果您需要遍历列表列表,可以将每个子列表中的值解压缩为单个变量。 例如,如果您的上下文包含称为点的(x,y)坐标列表,则可以使用以下内容输出点列表:
{% for x, y in points %} There is a point at {{ x }},{{ y }} {% endfor %}
如果您需要访问字典中的项目,这也很有用。 例如,如果您的上下文包含字典数据,则以下内容将显示字典的键和值:
{% for key, value in data.items %} {{ key }}: {{ value }} {% endfor %}
请记住,对于点运算符,字典键查找优先于方法查找。 因此,如果数据字典包含名为'items'的键,data.items将返回data ['items']而不是data.items()。 如果要在模板中使用这些方法(items, values, keys等),请避免添加名称类似于字典方法的键。 在模板变量的文档中详细了解点运算符的查找顺序。
for循环在循环中设置了许多变量:
#变量 #说明 forloop.counter #循环的当前迭代(1索引) forloop.counter0 #循环的当前迭代(0索引) forloop.revcounter #循环结束时的迭代次数(1索引) forloop.revcounter0 #循环结束时的迭代次数(0索引) forloop.first #如果这是第一次通过循环,则为true forloop.last #如果这是通过循环的最后一次,则为真 forloop.parentloop #对于嵌套循环,这是围绕当前循环的循环
for … empty
for标签可以带一个可选的{%empty%}子句,如果给定数组为空或者无法找到,那么它的文本就会显示出来:
<ul> {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% empty %} <li>Sorry, no athletes in this list.</li> {% endfor %} </ul>
以上相当于 - 但更短,更干净,并且可能快于 - 以下内容:
<ul> {% if athlete_list %} {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} {% else %} <li>Sorry, no athletes in this list.</li> {% endif %} </ul>
if
{%if%}标记评估一个变量,如果该变量为“true”(即存在,不为空,且不是假布尔值),则输出该块的内容:
{% 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 %}
在上面,如果运动员列表不是空的,运动员的数量将由{{athlete_list | length}}变量显示。正如你所看到的,if标签可能带有一个或多个{%elif%}子句,以及一个{%else%}子句,如果所有先前的条件都失败,将会显示该子句。 这些条款是可选的。
布尔运算符:and,or后者not。如果标签也可以使用运算符==,!=,<,>,<=,> =,in,not in,is , is not,如下面的例子:
{% if somevar == "x" %} This appears if variable somevar equals the string "x" {% endif %}
Filters
也可以在if表达式中使用过滤器。 例如:
{% if messages|length >= 100 %} You have lots of messages today! {% endif %}
include
加载模板并使用当前上下文进行渲染。 这是在模板中“包含”其他模板的一种方式。模板名称可以是变量,也可以是单引号或双引号的硬编码(带引号)的字符串。此示例包含模板“foo/bar.html”的内容:
{% include "foo/bar.html" %}
通常,模板名称是相对于模板加载程序的根目录。 字符串参数也可以是以./或../开头的相对路径,如扩展标签中所述。此示例包含名称包含在变量template_name中的模板的内容:
{% include template_name %}
load
加载自定义模板标记集。例如,以下模板将加载注册在包软件包中某个库和其他库中的所有标签和过滤器:
{% load somelibrary package.otherlibrary %}
也可以使用from参数选择性地从库中加载单个过滤器或标签。 在本例中,名为foo和bar的模板标签/过滤器将从somelibrary加载:
{% load foo bar from somelibrary %}
lorem
随机显示“lorem ipsum”拉丁文字。 这对于在模板中提供示例数据很有用。用法:
{% lorem [count] [method] [random] %}
now
显示当前日期和/或时间,使用根据给定字符串的格式。 此类字符串可以包含日期过滤器部分中所述的格式说明符字符。例:
It is {% now "jS F Y H:i" %}
请注意,如果要使用“原始”值,则可以反斜杠转义格式字符串。 在这个例子中,“o”和“f”都是反斜线转义的,否则每个都是一个显示年份和时间的格式字符串:
It is the {% now "jS \o\f F" %}
#这将显示为“这是9月4日”。
您还可以使用语法{%now“Y”as current_year%}将输出(作为字符串)存储在变量中。 如果您想在模板标记(如blocktrans)中使用{%now%},这非常有用,例如:
{% now "Y" as current_year %} {% blocktrans %}Copyright {{ current_year }}{% endblocktrans %}
regroup
用一个共同的属性重新组合一个类似对象的列表。举个例子来说明这个复杂的标签:说城市是由包含“名称”,“人口”和“国家”键的字典表示的城市列表:
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'}, ]
resetcycle
重置上一个周期,以便在下次遇到时从第一个项目重新开始。 如果没有参数,{%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> <p class="even">Thomas Müller</p>
spaceless
删除HTML标签之间的空白。 这包括制表符和换行符。用法示例:
{% spaceless %} <p> <a href="foo/">Foo</a> </p> {% endspaceless %}
这个例子会返回这个HTML:
<p><a href="foo/">Foo</a></p>
只有标签之间的空间被移除 - 而不是标签和文本之间的空间。 在这个例子中,Hello周围的空间不会被剥离:
{% spaceless %} <strong> Hello </strong> {% endspaceless %}
templatetag
输出用于组成模板标签的语法字符之一。由于模板系统没有“转义”概念,因此要显示模板标记中使用的某个位,必须使用{%templatetag%}标记。该参数告诉哪个模板位输出:
#参数 #输出 openblock {% closeblock %} openvariable {{ closevariable }} openbrace { closebrace } opencomment {# closecomment #}
示例用法:
{% templatetag openblock %} url 'entry_list' {% templatetag closeblock %}
url
返回与给定视图和可选参数匹配的绝对路径引用(没有域名的URL)。 结果路径中的任何特殊字符都将使用iri_to_uri()进行编码。这是一种通过在模板中硬编码URL来输出链接而不违反DRY原则的方法:
{% url 'some-url-name' v1 v2 %}
verbatim
停止模板引擎渲染此块标记的内容。通常的用法是允许一个与Django语法冲突的JavaScript模板层。 例如:
{% verbatim %} {{if dying}}Still alive.{{/if}} {% endverbatim %}
还可以指定一个特定的结束标记,允许使用{%endverbatim%}作为未呈现内容的一部分:
{% verbatim myblock %} Avoid template rendering via the {% verbatim %}{% endverbatim %} block. {% endverbatim myblock %}
widthratio
为了创建条形图等,该标签计算给定值与最大值的比率,然后将该比率应用于常数。例如:
<img src="bar.png" alt="Bar" height="10" width="{% widthratio this_value max_value max_width %}" />
with
以更简单的名称缓存复杂变量。 当访问多次“昂贵”的方法(例如命中数据库的方法)时,这非常有用。例如:
{% with total=business.employees.count %} {{ total }} employee{{ total|pluralize }} {% endwith %}
填充的变量(在上面的示例中为总数)仅在{%with%}和{%endwith%}标记之间可用。可以分配多个上下文变量:
{% with alpha=1 beta=2 %} ... {% endwith %}
#剩下的内容从:https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#built-in-filter-reference 继续往下看......
过滤器列表:
add:给变量加上相应的值、 addslashes :单引号加上转义号,一般用于输出到javascript中 capfirst :第一个字母大写 {{ "123spam456spam789"|cut:"spam" }}查找删除指定的字符串 {{ l1|slice:":2" }} 列表切边 {{ t|date:'Y-m-d' }} 转换特定时间格式 {{ s|default:'空空如也' }} 值不存在,使用指定值 {{ info|truncatechars:18 }} 渲染指定长度的字符 {{ info1|truncatewords:9 }}渲染指定长度的单词 {{ a|safe }} 声明安全可以渲染 {% if forloop.counter|divisibleby:2 %} 整除
下面是个小例子:
#例子来自:https://www.cnblogs.com/sss4/p/7071183.html
模板modals.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板渲染</title> </head> <body> <p>{{ i|add:200 }}</p> <p>{{ w|addslashes}}</p> <p>{{ f|capfirst }}</p> <p>{{ "123spam456spam789"|cut:"spam" }}</p> <p>{{ t|date:'Y-m-d' }}</p> <p>{{ l1|slice:":2" }}</p> <p>{{ s|default:'空空如也' }}</p> <p>{{ info|truncatechars:18 }}</p> <p>{{ info1|truncatewords:9 }}</p> <p> {% csrf_token %} {% for foo in li %} <li>{{ forloop.counter0 }}----->{{ foo }}</li> {% empty %} <li>没有符合的对象</li> {% endfor %} </p> <p> {% verbatim %} {{ str1 }} {% endverbatim %} </p> <p> {% with total=fhjsaldfhjsdfhlasdfhljsdal %} {{ total }} {% endwith %} </p> <p>{{ a|safe }}</p> </body> </html>
主站的urls.py添加一条视图:
url(r'^fifters/',views.fifters),
主站的views.py配置:
from django.shortcuts import HttpResponse from django.shortcuts import render import datetime def fifters(request): i=10 w="A'B'C'D'E" f='china' t=datetime.datetime.now() s='' l1=[98890,765,9870,7654] info='嘲笑我吧你们这些毫无眼光的人,我必将引来雷霆万钧的力量,摧古拉朽得战胜一切敌人!' info1='You laugh at me without the vision of people, and I will lead to an irresistible force power, corruption must defeat all enemies destroy gura!' li=['a','b','c','d','e','f','g'] str1='{{hello world}}' a='<a href="绿色网址">点击我</a>' fhjsaldfhjsdfhlasdfhljsdal='hellow world' return render(request,'modals.html',locals()) #locals()返回一个包含当前作用域里面的所有变量和它们的值的字典。
下面是页面效果:
#先说第一个210,i的值是10,然后{{ i|add:200 }},就是210了。
#{{ w|addslashes}}、w是"A'B'C'D'E",然后加上转义符就变成了A\'B\'C\'D\'E
#{{ f|capfirst }},然后f是china,然后就是第一个字母大写就是China
#{{ "123spam456spam789"|cut:"spam" }}就是删除spam字段,所以就变成了123456789
#{{ t|date:'Y-m-d' }}就是将时间转换成年-月-日的形式,所以时间就是2018-03-07
#{ l1|slice:":2" }}就是列表切边,就是将[98890,765,9870,7654]就是留下了0,1成了[98890, 765]
#{{ s|default:'空空如也' }} 就是当s值为空的时候输出default后面的内容,这里s是空值所以输出'空空如也'
#{{ info|truncatechars:18 }} 就是将info里面的字符串不管是汉子还是标点符号啥的都算上截取前18位字符
#{{ info1|truncatewords:9 }} 就是取9个单词
#forloop.counter0就是从0开始计数,然后li=['a','b','c','d','e','f','g'],for循环这个列表,然后就是上图的效果。{% empty %} 没有渲染到数据,提示。{% csrf_token %}用于生成csrf_token的标签,用于防治跨站攻击验证(csrf)。 其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。
#{% verbatim %} 就是屏蔽django自己的{%%}标签,可见str1没有实现模板渲染效果。也就是禁止渲染的意思。
#{% with %}里面total引用的也是一个变量,最后是后台的hellow world 传递过来了。 也就是用更简单的变量名 替代视图复杂的变量名
#{{ a|safe }} 就是声明a所代表的标签元素是安全的可以渲染。
#另外要注意的是新窗口打开和同一个窗口打开。
target="_blank" 新窗口打开。
target="_parent" 同一窗口打开 或者不要加target="_parent" 默认是统一窗口打开。
下面稍微修改一下:
a='<a&nb�</a>'
二、内置标签例子
能用到的标签一般常用的也就是if,for这些。
2.1 for循环简单小例子
主站urls.py加上一条视图:
url(r'^info',views.info),
主站views.py加上加上一个info函数:
def info(request): info_list = [ {'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', 'counmp;nbsp;'population': '33,000,000', 'country': 'Japan'}, ] return render(request, 'info.html',{'info_list':info_list}) #{'info_list':info_list}就是将info_list所表示的列表传递给前端info.html页面的info_list
templates目录下info.html的简单编写:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body style="margin: 0"> <div style="height: 48px;background-color: #dddddd;line-height: 50px;">员工信息</div> <div> <table border="1"> {% for num in info_list %} <tr> <td>{{ num.name }}</td> <td>{{ num.population }}</td> <td>{{ num.country }}</td> </tr> {% endfor %} </table> </div> </body> </html>
最后查看一下页面显示:
再稍微改一改:
views.py改一改:
info_list = [ {'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'}, ] def info(request): if request.method == "POST": # 获取用户通过POST提交过来的数据 n = request.POST.get('name',None) p = request.POST.get('population',None) c = request.POST.get('country',None) add_info = {'name': n,'population': p,'country':c} info_list.append(add_info) return render(request, 'info.html', {'info_list': info_list}) else: return render(request, 'info.html',{'info_list':info_list})
info.html改一改(加一个增加信息的功能):
<body style="margin: 0"> <div style="height: 48px;background-color: #dddddd;line-height: 50px;">员工信息</div> <form action="/info" method="post"> <div style="float: right;margin-right: 1200px;"> <p>增加员工信息:</p> <a>name:</a><input type="text" name="name"><br/> <a>population:</a><input type="text" name="population"><br/> <a>country:</a><input type="text" name="country"><br/> <input type="submit" value="提交" /> </div> </form> <div> <table border="1"> {% for num in info_list %} <tr> <td>{{ num.name }}</td> <td>{{ num.population }}</td> <td>{{ num.country }}</td> </tr> {% endfor %} </table> </div> </body>
三、模板的继承实例
什么是继承?
Django模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。
先来一个简单小例子:
master.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}{% endblock %}</title> <link rel="stylesheet" href="/static/commons.css"> <style> .pg-header{ height: 48px; background-color: aqua; color: green; } body{ background-color: blue; } </style> {% block css %}{% endblock %} <!--这样是为了css单独引用,继承页面可以自己修改样式--> </head> <body> <div class="pg-header">管理起来</div> {% block content %}{% endblock %} <!--加上这句话,意思就是这个页面可以被继承了,将你要展示的页面和这个block的页面结合展示给用户。--> <script src="/static/jquery.js"></script> {% block js %}{% endblock %} </body> </html>
tpl1.html:
{% extends 'master.html' %} <!--引用那个模板页面--> {% block title %}用户管理{% endblock %} <!--引用title--> {% block content %} <!--引用content--> <h1>用户管理</h1> <ul> {% for i in u %} <li>{{ i }}</li> {% endfor %} </ul> {% endblock %} {% block css %} <!--引用css--> <style> body{ background-color: red; /*设置背景颜色为红色*/ } </style> {% endblock %} {% block js %} <!--block块的顺序对页面没啥关系--> <script> </script> {% endblock %}
tpl2.html:
{% extends 'master.html' %} {% block title %}用户管理{% endblock %} {% block content %} <h1>小客户用户管理</h1> <ul> {% for i in u %} <li>{{ i }}</li> {% endfor %} </ul> {% endblock %} {% block css %} {% endblock %} {% block js %} <script> alert("好开心") </script> {% endblock %}
views.py:
def tpl1(request): user_list = [1, 2, 3, 43] return render(request, 'tpl1.html', {'u': user_list}) def tpl2(request): user_list = [11, 22, 33, 343] return render(request, 'tpl2.html', {'u': user_list})
浏览器显示结果:
#从显示结果可以看到:
tp1.html直接引用了master.html里面的{% block title %} {% endblock %},然后就直接给嵌套了一个title框。tpl2.html虽然继承了master.html的背景色blue但是可以修改。
extend继承模板一个文,件中只能继承一个模板extend继承模板中的所有内容,模板的内容包括:html的head和body
block关键字是定义父模板中哪些内容需要重新,定义block块时,必须给block块命名。在子模板中,子模板会根据blcok的块名重写父文件中定义的block块部分。在子文件中如果使用block块名,子文件默认继承父文件中的block中的内容。
四、模板的导入实例
include用户公共模板的引入,当很多页面(不是所有)中都需要某段html语言时,引入公共模板是个好方法,在当前的html中的某个你需要引入公共模板的地方使用{% include '公共模板的相对路径' %}引入。
include关键字是让子文件的继承局部的内容,父文件只需要写一个公。用的模板include继承的父文件内容只是body中的具体某个或者多个标签。在一个文件中可以有多了include,但是只能有一个extend。
tag.html:
<div class="list" id="newtest_1"> {{ name }} <ul> <li class=""> <a href="http://v.dangdang.com/pn6553_3659_1.html" target="_blank"> <img src="http://img62.ddimg.cn/2016/12/21/2016122116095512294.jpg"> <span class="shop_name">花间公主新年大促</span> <span class="time"> <span overtype="5" js="true" action="countdown" type="seckill" class="time_hs" endvalue="1482976800" showtype="3"><span sec="sep">还剩<span>4</span>天</span></span> </span> <span class="left_shadow"> <span class="img_logo"> <img data-original="http://img62.ddimg.cn/2016/12/21/2016122116095524370.jpg" src="http://img62.ddimg.cn/2016/12/21/2016122116095524370.jpg" style="display: block;"> </span> <span class="shop_ad">花间公主新年大促</span> <span class="price_z"> 1.9-3.9<span>折</span> </span> <span class="sale">199减20</span> </span> <span class="red_circle" style="display: none;"></span> </a> </li> </ul> </div>
tpl1.html:
{% extends 'master.html' %} {% block title %}用户管理{% endblock %} {% block content %} <h1>大客户用户管理</h1> <ul> {% for i in u %} <li>{{ i }}</li> {% endfor %} </ul> {% for i in u %} {% include 'tag.html' %} {% endfor %} {% endblock %} {% block css %} <style> body{ background-color: white; } </style> {% endblock %} {% block js %} {% endblock %}
如果只导入两次或者是不同的文件的话:
{% include "tag.html" %} #直接饮用tag.html里面的东西 {% include "tag.html" %} #写两次引用两次
五、自定义函数simple_tag
内置方法
django中包含了很多内置方法,如下面的例子:
views.py:
def tpl3(request): name= "ABCDEFG" my_list="test" return render(request,"tpl3.html",{"name":name,"my_list":my_list})
tpl3.html:
<body> {{ name }} {{ name|lower }} <br/> {{ my_list }} {{ my_list|first|upper }} </body>
urls.py中:
url(r'^tpl3/', views.tpl3),
最后浏览器结果:
自定义方法
使用simple_tag的方法:
在app下创建templatetags目录
创建py文件
创建template对象register
@register.simple_tag def func() 如果函数有参数: def func(a1,a2)
在settings配置文件注册app
在页面文件顶部{%load py文件%},如果存在继承,这个要放在继承下面
最后在页面使用的时候{% func %},如果有参数{%func 2 3 %}
这里有几个问题需要注意:
在app下创建templatetags目录必须为templatetags不能更改
创建py文件的时候名字可以随便定义
在py文件中必须写如下代码:
from django import template from django.utils.safestring import mark_safe register = template.Library() @register.simple_tag #这四行代码必须有,并且的template对象register名字不能更改
先来一个小例子:
第一步:
首先app01下面创建一个名称叫做templatetags目录,必须是这个名称,目录下创建一个自定义的py文件,以stags.py举例:
from django import template from django.utils.safestring import mark_safe register = template.Library() @register.simple_tag def stest(): return 123
第二步:
settings.py里面做配置:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', #将app01加进来 ]
第三步:
urls.py添加一条路由规则:
url(r'^tpl4/', views.tpl4),
第四步:
views.py设置:
def tpl4(request): return render(request,"tpl3.html")
第五步:
tpl4.html:
{% load stags %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% stest %} </body> </html>
稍微改的复杂点:
stags.py:
@register.simple_tag def ssum(a1,a2): return a1+a2
tpl4.html:
<body> {% stest %} <p>The sum is:{% ssum 3 4 %}</p> </body>
#还有一个@register.filter方法。