python之路--web--2--Django-12-Django模板语言

Django模板语言

关于本文档php

本文档介绍了Django模板系统语言的语法. 若是你但愿从一个更技术的角度来看它是如何工做的和如何扩展 它,请参阅 The Django template language: For Python programmers .css

Django模板语言设计的初衷是为了得到效率和易用性之间的平衡. HTML使用者会感受到他设计的很舒服.若是你有使用其余基于文本的模板语言如 Smarty 或 CheetahTemplate 的使用经验,你会感受到使用Django模板语言和那些东西没什么两样.html

哲理数据库

若是你有编程背景,或者你使用过PHP等嵌入HTML的程序语言,你要牢记, Django的模板系统是否是简单的把Python嵌入到HTML中. 它的设计是:模板系统旨在展现内容,而不是程序逻辑.django

Django的模板系统提供的标签,其功能相似于一些编程结构 – if 标签用于布尔值测试, for 标签用来作for循环, 等等.但这些都不是简单的执行相应的Python代码,模板系统不会执行任意的Python表达式. 一般状况下, 模板系统仅支持接下来列出的这些标签和过滤 (仅当须要时你能够添加 你本身的扩展 到模板语法中).编程

模板

模板是一个简单的文本文件.它能够生成任何基于文本的格式(如 HTML,XML,CSV等).api

模板中包含的 变量 被替换为变量的值, 标签 被替换为相应的模板控制逻辑.数组

下面的一小段模板代码能够说明一些基本的内容. 文中的每一个元素都将在后面解释.:浏览器

{% 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. 在网络世界,它能够不止被用在电子邮件,JavaScript和CSV中. 您能够在任何文本格式中使用它.

哦,还有一件事: 让人写XML, 那就是虐待!

变量

变量看起来是这样的: {{ 变量 }}. 当模板系统遇到一个变量, 他直接被替换为他的值. 变量名由字母数字和下划线 ("_")组成. 点字符 (".") 也能够出如今变量名中,但他有特殊的含义.好比下面的. 更重要的是, 变量名中不能有空格或其余的标点符号.

使用点 (.) 来访问变量的属性.

幕后

从技术上讲,当模板系统遇到一个点,它会尝试下面的动做,顺序以下:

  • 字典查询
  • 属性查询
  • 方法调用
  • 列表索引查找

在上面的例子中, {{ section.title }} 将被替换为这个对象的title属性值.

若是你使用一个不存在的变量,模板系统会替换它为settings中的 TEMPLATE_STRING_IF_INVALID 值,在默认状况下他被指定为 '' (空字符串).

过滤器(Filters)

经过使用 过滤器 ,您能够修改变量的显示.

过滤器用起来像这样: {{ name|lower }} . 经过过滤器 lower 变量 {{ name }} 变为了小写字符. 经过管道符 (|) 间隔变量和过滤器来使用过滤器.

过滤器能够是 “链式的”. 一个过滤器的输出做为下一个过滤器的输入. {{ text|escape|linebreaks }} 是一种经常使用的转换方式, 在这以后换行符被替换为了 <p> 标签.

有些过滤器是带有参数的. 一个带参数的过滤器看起来像这样: {{ bio|truncatewords:30 }}. 他会显示 bio 变量的前30个字符.

若是过滤器的参数包含空格, 那么参数必须被引号包起来; 好比, 用逗号和空格来间隔列表内的元素, 你能够像这样用{{ list|join:", }}.

Django提供了约30个内置的过滤器. 有关这些过滤器你能够在 内置过滤器参考 中找到更详尽的描述. 这儿有一些过滤器的例子,可让你尝到一些过滤器的甜头:

default

若是一个变量是假的或空的,使用默认值. 不然,使用变量的值

例如:

{{ value|default:"nothing" }} 

若是 value 没有提供或者为空,那么他将显示为 “nothing” 。

length

返回的值的长度。能够被用于字符串或者列表;

for example:

{{ value|length }} 

若是 value 为 ['a', 'b', 'c', 'd'], 那么他将被显示为 4.

striptags

去掉全部 [X]HTML 标签. 好比:

{{ value|striptags }} 

若是 value 为 "<b>Joel</b> <button>is</button> <span>slug</span>", 那么输出就会是 "Joel is slug".

这些只是几个例子,请参阅 内置过滤器参考 的完整列表。

您还能够建立本身的自定义模板过滤器,请参见 Custom template tags and filters.

查看更多

Django的管理界面能够在一个给定的站点中包含全部的模板标签和过滤器的完整参考。 请参阅 The Django admin documentation generator.

标签(Tags)

标签看起来像这样: {% tag %}. 标签要比变量更复杂: 有些标签会建立一段文本, 有些标签会控制输出流的方式好比循环或逻辑条件, 还有些标签会添加一些扩展内容到模板中, 好比另外的标签和过滤器.

有些标签在使用时须要有开始和结束标签 (像这样 {% tag %} ... 内容 ... {% endtag %}).

Django内置了大约二十几个标签. 你能够在 内置标签参考 阅读有关内置标签的内容. 为了让你尝试有什么可用的, 这里有一些经常使用标签的例子:

for

循环数组中的每一个元素. 好比, 显示列表 athlete_list 中每一个元素的 name 属性:

<ul>
{% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} </ul> 
if and  else

判断一个变量的布尔值, 若是它为 “true” 则显示 if 块儿内的内容, 不然显示 else 块儿内的文字:

{% if athlete_list %} Number of athletes: {{ athlete_list|length }} {% else %} No athletes. {% endif %} 

在上面的例子中, 若是 athlete_list 不是空的, 那么变量 {{ athlete_list|length }} 就会被显示出来.

也能够在 if 标签里使用过滤器和各类操做符:

{% if athlete_list|length > 1 %} Team: {% for athlete in athlete_list %} ... {% endfor %} {% else %} Athlete: {{ athlete_list.0.name }} {% endif %} 
block and  extends
请看  模板继承 (在下面), 一个强大的方法, 在模板上切割下来的”样板”.

以上的例子只是整个标签列表的一小部分; 请参看 内置标签参考 完整阅览.

您还能够建立本身的自定义模板标签, 请参看 Custom template tags and filters.

查看更多

Django的管理界面能够在一个给定的站点中包含全部的模板标签和过滤器的完整参考。 请参阅 The Django admin documentation generator.

注释(Comments)

要注释掉行的一部分,在模板中使用注释语法: {# #}.

例如,该模板将呈现为 '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 标签订义了三个能够被子模板填充的块. 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”.

在这一点上, 模板引擎会在 base.html 中发现三个 block 标签, 而且使用子模板的内容替换掉这些块. 根据变量 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.htmlbase_sports.html. 这些模板都继承 base.html 模板. 这些模板中包含特定的设计/风格.
  • 为每一种类型的页面建立一个模板, 好比 news article 或 blog 内容. 这些模板扩展上一级模板的相应分类.

这种方法最大限度地重用了代码并能很容易将元素添加到公用的区域, 好比分类导航.

这里有一些关于模板继承的提示

  • 若是你在模板中使用 {% extends %}, 他必须位于模板的最开始. 若是在其余的部分声明, 则不生效.

  • 在你的基础模板中使用更多的 {% block %} 是一个好的方法. 请记住, 子模板不须要定义全部父模板中的块, 因此你能够在若干的块中填充默认值, 而后定义以后须要的块. 有更多的可用块老是更好的.

  • 若是你发现本身在许多模板中有重复内容的了, 这可能意味着你要移动这些内容到父模板的 {% block %} 中.

  • 若是你须要获得父模板块中的内容, 能够用 {{ block.super }} 变量. 这在你想使用父模板块中的内容又想在其中追加内容时是很是有用的. 使用 {{ block.super }} 插入的数据不会被自动转义 (参见 下一节), 由于它已经被转义了. 若是须要转义, 能够在父模板中转义.

  • 更好的可读性, 你能够给 {% endblock %} 标签订义一个 名字. 好比:

    {% block content %} ... {% endblock content %} 

    在一个较长的模板中, 这个方法可让你知道是哪个 {% block %} 标签订义结束了.

最后请注意, 你不能在同一模板中定义多个具备相同名称的块标签. 存在这个限制是由于 block 标签是”双向”定义的. 也就是说, 它不只指定了子模板要填充哪一个”洞”, 也说明了子模板要引用那些父模板的内容. 因此在有多个同名 block 标签时, 父模板就不知道到底要引用哪一个块的内容了.

自动HTML转义

从模板生成HTML时, 老是有一种风险, 即一个变量将会影响生成的HTML字符. 例如, 考虑这个模板片断:

Hello, {{ name }}. 

用这种方法显示用户的姓名彷佛没什么问题, 但考虑一下, 若是用户输入下面的文字做为他的名字, 会发生什么:

<script>alert('hello')</script> 

当名字为这个值, 该模板将呈现为:

Hello, <script>alert('hello')</script> 

...这意味着浏览器将弹出一个JavaScript警告框!

一样的, 若是名字中包含一个 '<' 符号, 像这样:

.. code-block:: html
<b>username

这将致使呈现出这样的模板:

Hello, <b>username

...这意味着在此以后的文字将呈现为粗体!

显然, 用户提交的数据是不可靠的且不该被直接插入到您的网页, 由于恶意用户可使用这种潜在的漏洞作很差的事情. 这种类型的安全漏洞被称为 Cross Site Scripting (跨站脚本) (XSS) 攻击.

为了不这个问题, 你有两种选择:

  • 一, 确保让不受信任的变量通过了 escape 过滤器 (下文介绍), 将危险的HTML字符替换为无害的HTML转义字符. 这在Django最初时是默认的方案, 它使得 , 开发者, 有责任确保在必要时转义了变量. 可是人们很容易忽略它.
  • 二, 你能够用Django的自动HTML转义. 本节的其他部分介绍了自动转义如何工做.

在Django中, 默认每一个模板会自动转义输出的每个变量标签. 具体来讲, 这五个字符会被转义:

  • < 被替换为 &lt;
  • > 被替换为 &gt;
  • ' (单引号) 被替换为 &#39;
  • " (双引号) 被替换为 &quot;
  • & 被替换为 &amp;

再次强调, 这种行为是默认的. 若是你使用的是Django的模板系统, 你是受保护的.

如何关闭它

若是你不但愿数据被自动转义, 你能够在站点/模板/变量这三个层面关闭它.

为何你会想要把它关掉? 由于有时候, 你但愿把模板变量中包含的数据做为原始的HTML渲染, 在这种状况下, 你不但愿本身的内容被转义. 例如, 你可能在你的数据库的BLOB字段存储HTML, 并但愿直接嵌入到您的模板. 或者你使用Django的模板系统生成不是HTML的文本 – 好比电子邮件正文.

对于单个变量

要为一个单独的变量禁用自动转义, 使用 safe 过滤器:

这个会被自动转义: {{ data }} 这个不会被自动转义: {{ data|safe }} 

safe 能够被认为是 safe from further escaping 或 can be safely interpreted as HTML 的简写. 在这个例子中, 若是 data 是 '<b>', 那么输出将会是:

这个会被自动转义: &lt;b&gt; 这个不会被自动转义: <b> 

对于模板文本块

要在模板中控制自动转义, 能够在整个模板 (或者模板的特定区域) 使用 autoescape 标签, 如:

{% autoescape off %} Hello {{ name }} {% endautoescape %} 

autoescape 标签接受 on 或 off 做为参数. 有时, 你但愿自动转义在某个区域被禁用. 如这个模板的例子:

自动转义是默认被开启的. 你好 {{ name }} {% autoescape off %} 这个不会被自动转义: {{ data }}. 这个也不会: {{ other_data }} {% autoescape on %} 自动转义被开启: {{ name }} {% endautoescape %} {% endautoescape %} 

自动转义标签的效果会传递至继承它的模板中, 包括使用 include 标签所包含的内容, 就像全部的块标签同样. 例如:

# base.html

{% autoescape off %}
<h1>{% block title %}{% endblock %}</h1>
{% block content %}
{% endblock %}
{% endautoescape %}


# child.html

{% extends "base.html" %}
{% block title %}This & that{% endblock %}
{% block content %}{{ greeting }}{% endblock %}

因为自动转义在base模板中被关闭了, 因此在子模板中他也是被关闭了的, 致使了在呈现HTML时, greeting 变量被输出为 <b>Hello!</b>:

<h1>This & that</h1>
<b>Hello!</b>

注意

通常状况下, 模板的开发者并不须要对自动转义太过关注. 这是编写Python的开发者 (写视图和写自定义模板标签的人) 须要考虑的事. 因此, 你只须要作和模板有关的活.

若是你不肯定模板在什么时候会进行自动转义(或不进行), 那么就向全部须要转义的变量添加 escape 过滤器. 当自动转义被打开, 这么作不会有任何问题, escape 过滤器不会再次转义 – escape 过滤器不会影响自动转义的变量.

字符串和自动转义

正如咱们前面提到的, 过滤器参数能够是字符串:

{{ data|default:"This is a string literal." }} 

这些做为过滤器参数的字符串 都不通过 自动转义, 他们是被认为通过了 safe 过滤器的. 这么作的缘由是, 模板的开发者是在控制字符的输出, 因此他们能确保正确的使用转义后的HTML字面值.

这意味着你应当这么写

{{ data|default:"3 &lt; 2" }} 

...而不是这样

{{ data|default:"3 < 2" }}  <-- Bad! Don't do this.

这不会影响来自变量自己的数据. 若是必要, 变量自己仍会被自动转义, 由于他们没法控制的模板做者.

访问方法调用

大多附加到对象上的方法均可以在模板中被调用. 这意味着模板能够从视图中传递过来变量中得到对象属性以外的值. 例如, Django ORM 提供了 “entry_set” 语法 寻找一个外键所关联的对象的集合. 所以, 架设一个叫 “comment” 的模型有外键指向了模型 “task”, 你能够经过给定一个实际的 task , 像这样循环输出它全部的 comment:

{% for comment in task.comment_set.all %} {{ comment }} {% endfor %} 

一样, QuerySets 提供了一个 count() 方法来统计它所包含的对象数目. 所以, 您能够获得当前 task 相关的全部 comment 的数目:

{{ task.comment_set.all.count }} 

固然, 你能够很容易地访问你本身的模型中明确地定义的方法:

# In model
class Task(models.Model):
    def foo(self):
        return "bar"

# In template
{{ task.foo }} 

因为Django有意限制了模板中语言逻辑的处理, 因此不能在模板内调用方法时传递参数. 数据应当在视图中计算, 而后再传递给模板.

自定义标签和过滤器库

某些应用提供了自定义的标签和过滤器库. 要在模板中访问这些, 应使用 load 标签:

{% load comments %} {% comment_form for blogs.entries entry.id with is_public yes %} 

在上文中, load 标签加载了 comments 标签库, 而后 comment_form 标签就能用了. 你能够在管理员文档中找到用户自定义库的安装列表.

load 标签能够根据名字加载多个标签库, 名字间使用空格分隔. 例如:

{% load comments i18n %} 

请参考 Custom template tags and filters 以得到更多的有关自定义标签的内容.

自定义库和模板继承

当你加载一个自定义标签和过滤器库, 这些被加载的标签/过滤器只能在当前模板中使用 – 其余与此模板有继承关系的(父/子)模板均不能使用这些标签/过滤器.

例如, 若是一个模板 foo.html 使用了 {% load comments %}, 一个子模板 (就是使用了 {% extends "foo.html" %}) 是不能访问 comments 库中的标签和过滤器的. 子模板须要具备本身的 {% load comments %}.

这是由于这能使模板更健全且更好维护.

相关文章
相关标签/搜索