如果您有编程方面的背景,或者您已经习惯了将编程代码直接混合到HTML中的语言,那么您应该记住Django模板系统不仅仅是嵌入到HTML中的Python。这是通过设计:模板系统是用来表示,而不是程序逻辑。
Django模板系统提供的标记功能类似于一些编程构造
if
标记用于布尔测试,for
用于循环等的标记-但是这些标记不仅仅是作为对应的Python代码执行的,模板系统也不会执行任意Python表达式。默认情况下,只支持下面列出的标记、筛选器和语法(尽管您可以添加你自己的扩展到模板语言)。
Django模板语言官方文档地址:https://docs.djangoproject.com/en/2.2/ref/templates/language/#the-django-template-language
一、模板
模板只是一个文本文件。它可以生成任何基于文本的格式(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 %}
为什么要使用基于文本的模板而不是基于XML的模板(比如Zope的TAL)?我们希望Django的模板语言不仅仅适用于XML/HTML模板。在WorldOnline,我们将其用于电子邮件、JavaScript和CSV。您可以对任何基于文本的格式使用模板语言。
哦,还有一件事:让人类编辑XML是虐待狂!
二、变量
变量如下所示:{{ variable }}。
当模板引擎遇到一个变量时,它会计算该变量并用结果替换它。变量名由字母数字字符和下划线("_"
),但不能以下划线开头。圆点("."
)也出现在变量节中,尽管这有一个特殊的含义,如下所示。重要的是,变量名中不能有空格或标点符号。
用点(.
)访问变量的属性。
从技术上讲,当模板系统遇到一个点时,它会按以下顺序尝试以下查找:
字典查找
属性或方法查找
数字索引查找
如果结果值是可调用的,则调用它时不带任何参数。调用的结果成为模板值。
此查找顺序会对覆盖字典查找的对象造成一些意外行为。例如,考虑以下试图在
collections.defaultdict
:
{% for k, v in defaultdict.items %}
Do something with k and v here...
{% endfor %}
因为字典查找首先发生,所以该行为会启动并提供一个默认值,而不是使用预期的.items()
方法。在这种情况下,考虑先转换为字典。
在上面的例子中,{{ section.title }}
将被替换为title
属性的section
对象。
如果使用不存在的变量,模板系统将插入string_if_invalid
选项,该选项设置为''
(空字符串)默认情况下。
请注意模板表达式中的“bar”,如{{ foo.bar }}
如果变量“bar”存在于模板上下文中,则将被解释为文字字符串,而不是使用变量“bar”的值。
以下划线开头的变量属性可能不会被访问,因为它们通常被认为是私有的。
三、过滤器(Filters)
可以通过以下方式修改显示变量过滤器.
过滤器看起来如下:{{ name|lower }}
..这将显示{{ name }}
变量后,通过lower
过滤器,它将文本转换为小写。用管子(|
)应用过滤器。
过滤器可以“链式”。将一个过滤器的输出应用到下一个过滤器。{{ text|escape|linebreaks }}
是一个常见的成语,用于转义文本内容,然后将换行符转换为<p>
标签。
有些过滤器采用论点。过滤器参数如下所示:{{ bio|truncatewords:30 }}
..这将显示bio
变量。
必须引用包含空格的筛选参数;例如,使用逗号和空格连接列表{{ list|join:", " }}
.
Django提供了大约60个内置模板过滤器。你可以在内置滤波器参考..为了让您体验一下可用的内容,下面是一些更常用的模板过滤器:
如果变量为false或空,则使用给定的默认值。否则,使用变量的值。例如:
{{ value|default:"nothing" }}
如果value
不提供或空,上面将显示“nothing
”.
length
返回值的长度。这既适用于字符串,也适用于列表。例如:
{{ value|length }}
如果value
是['a', 'b', 'c', 'd']
,输出将是4
.
将值格式化为“人类可读的”文件大小(例如'13 KB'
, '4.1 MB'
, '102 bytes'
等等)。例如:
{{ value|filesizeformat }}
如果value
为123456789,输出为117.7 MB
.
同样,这些只是几个例子;请参阅内置滤波器参考完整的名单。
您还可以创建自己的自定义模板筛选器;请参见自定义模板标记和过滤器.
Django的管理界面可以包含对所有模板标记和过滤器的完整引用,这些模板标记和过滤器都可以用于给定的站点。更多请见Django管理文档生成器
四、注释
若要在模板中注释行的一部分,请使用注释语法:{# #}
.
例如,此模板将呈现为'hello'
:
{# greeting #}hello
注释可以包含任何模板代码,无效或无效。例如:
{# {% if foo %}bar{% else %} #}
此语法只能用于单行注释(不允许在{#
和#}
(定界符)如果需要注释掉模板的多行部分,请参见comment
标签。
五、模板继承
Django的模板引擎中最强大、也是最复杂的部分是模板继承。模板继承允许您构建一个基本的“骨架”模板,该模板包含站点的所有公共元素并定义blocks子模板可以覆盖。
从一个示例开始,最容易理解模板继承:
<!DOCTYPE html>
<html lang="en">
<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框架文档,可以用于简单的两列页。这是“子”模板的工作,用内容填充空块。
在本例中,block
标记定义子模板可以填充的三个块。所有block
标记是告诉模板引擎,子模板可以覆盖模板的这些部分。
子模板可能如下所示:
{% 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”。
此时,模板引擎将注意到这三个block
标签base.html
并将这些块替换为子模板的内容。取决于blog_entries
,输出可能如下所示:
<!DOCTYPE html>
<html lang="en">
<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>
注意,由于子模板没有定义sidebar
块时,将使用父模板的值中的内容{% block %}
父模板中的标记总是用作回退。
您可以根据需要使用尽可能多的继承级别。使用继承的一种常见方法是以下三层方法:
-
创建一个
base.html
模板,保存您的网站的主要外观和感觉。 -
创建一个
base_SECTIONNAME.html
模板为您的网站的每个“部分”。例如,base_news.html
,base_sports.html
..这些模板都扩展了base.html
并包括特定章节的风格/设计。 -
为每种类型的页面创建单独的模板,例如新闻文章或博客条目。这些模板扩展了适当的节模板。
这种方法最大限度地实现了代码重用,并使将项添加到共享内容区域(如区段范围的导航)变得更加容易。
以下是使用继承的一些技巧:
-
如果你用
{% extends %}
在模板中,它必须是该模板中的第一个模板标记。否则,模板继承将无法工作。 -
更多
{% block %}
基本模板中的标记更好。请记住,子模板不必定义所有父块,因此可以在多个块中填充合理的默认值,然后只定义稍后需要的块。多钩比少钩好。 -
如果您发现自己在许多模板中复制内容,这可能意味着您应该将该内容移到
{% block %}
在父模板中。 -
如果需要从父模板获取块的内容,则
{{ block.super }}
变量会起作用的。如果您想要添加到父块的内容而不是完全覆盖它,这是非常有用的。插入的数据{{ block.super }}
将不会自动转义(请参阅下一节),因为如果有必要,它已经在父模板中转义了。 -
外部创建的变量。
{% block %}
使用模板标记as
语法不能在块内使用。例如,此模板不呈现任何内容:
{% trans "Title" as title %}
{% block content %}{{ title }}{% endblock %}
为了获得额外的可读性,您可以选择name给你的{% endblock %}标签。例如:
{% block content %}
...
{% endblock content %}
-
在较大的模板中,此技术帮助您查看
{% block %}
标签被关闭了。
最后,请注意,您不能定义多个block
同一模板中具有相同名称的标记。这种限制存在是因为块标记在“双向”方向上工作。也就是说,块标记不仅提供了一个可以填充的洞-它还定义了填充父母..如果有两个相似的名字block
标记在模板中,该模板的父模板将不知道要使用哪个块的内容。