Django学习(八):模板

一:Django模板介绍

作为Web 框架,Django 需要一种很便利的方法以动态地生成HTML。 最常见的做法是使用模板。 模板包含所需HTML 输出的静态部分,以及一些特殊的语法,描述如何将动态内容插入。

模板是由context来进行渲染的。 渲染的过程是用在context中找到的值来替换模板中相应的变量,并执行相关tags。 其他的一切都原样输出。

在Python中使用模板系统有三个步骤:
①配置Engine。
②将模板代码编译成Template。
③根据Context渲染模板。

模板组成部分:

引擎

django.template.backends.django.DjangoTemplates是django.template.Engine的简化版,他们都是指向Django模板后端的API。

模板

django.template.backends.django.Template 是django.template.Template的一个简化版,他们指向共同的模板API

上下文
django.template.Context 除了持有context数据以外,还持有一些元数据. 它被传递到Template.render()用于渲染一个模板.

大多数情况下,context数据是在一个普通的dict里传递

加载器

模板加载器负责定位模板,加载它们,并返回Template对象

上下文处理器
接收当前的 HttpRequest 作为参数,并返回一个 dict,该字典中包含了将要添加到渲染的context中的数据。

主要用途是添加所有的模板context共享的公共数据,而不需要在每个视图中重复代码。

配置模板引擎:

Django 项目可以配置一个或多个模板引擎(甚至是零,如果你不需要使用模板)。 Django 的模板系统自带内建的后台 —— 称为Django 模板语言(DTL),以及另外一种流行的Jinja2

模板引擎通过TEMPLATES 设置来配置

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            # ... some options here ...
        },
    },
]

BACKEND -->是一个指向实现了Django模板后端API的模板引擎类的带点的Python路径。 内置的后端有 django.template.backends.django.DjangoTemplates 和 django.template.backends.jinja2.Jinja2。

DIRS --> 定义了一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板源文件。

APP_DIRS --> 告诉模板引擎是否应该进入每个已安装的应用中查找模板。 每种模板引擎后端都定义了一个惯用的名称作为应用内部存放模板的子目录名称。(译者注:例如django为它自己的模板引擎指定的是 ‘templates’ ,为jinja2指定的名字是‘jinja2’)

OPTIONS -->包含了具体的backend设置

DjangoTemplates 引擎 OPTIONS 配置项中接受以下参数:

'autoescape':一个布尔值,用于控制是否启用HTML自动转义;默认为True

'context_processors': 是一个包含以"."为分隔符的python调用路径的列表,在一个template被request渲染时,它可以被调用以产生context的数据;默认是个空的 list

'debug':打开/关闭模板调试模式的布尔值;默认和setting中的 DEBUG有相同的值
'loaders':模板加载器类的虚拟Python路径列表;每个Loader类知道如何从特定源导入模板;默认值取决于DIRS和APP_DIRS的值

'string_if_invalid':作为字符串的输出,模板系统应该用于无效(例如拼写错误的)变量;默认为空字符串

'file_charset':用于读取磁盘上的模板文件的字符集;默认为FILE_CHARSET的值
'libraries':模板标签模块的标签和点缀Python路径的字典,用于注册模板引擎。 这可以用于添加新的库或为现有库添加备用标签。可以通过将相应的字典键传递到{% load %}标记来加载库
'builtins':添加到built-ins的模板标签模块的点缀Python路径列表

二:Django模板语言

Django模板语言的语法包括四个结构:

1,变量

变量的值是来自context中的输出, 这类似于字典对象的keys到values的映射关系

{{ variable }}

变量名必须由字母、数字、下划线(不能以下划线开头)和点组成。变量名称中不能有空格或标点符号;
变量名中点表示查找。 具体一点,当模板系统遇到变量名中的一个点时,它会按下面的顺序进行查找:
1-->字典查找。 示例:foo["bar"]
2-->属性或方法查找。 例如:foo.bar

3-->列表索引查找。 例如:foo[bar]

如果计算结果的值是可调用的,它将被无参数的调用。 调用的结果将成为模版的值。
模板系统使用找到的第一个可用的类型。 这是一个短路逻辑

如果变量的任何部分是可调用的,模板系统将尝试调用它。

2,标签

标签在渲染的过程中提供任意的逻辑。
{% tag %}

常用标签介绍:

for 标签-->循环数组中的每个元素。

<ul>
{% for user in user_list %}
    <li>{{ user.name }}</li>
{% empty %}
    <li>空空如也</li>
{% endfor %}
</ul>

Variable                        Description
forloop.counter            当前循环的索引值(从1开始)
forloop.counter0          当前循环的索引值(从0开始)
forloop.revcounter      当前循环的倒序索引值(从1开始)
forloop.revcounter0    当前循环的倒序索引值(从0开始)
forloop.first                 如果这是第一次通过循环,则为真
forloop.last                 如果这是最后一次循环,则为真
forloop.parentloop     本层循环的外层循环

if标签 -->条件判断if,elif和else
支持的操作符有 not,and,or,==, !=, <, >, <=, >=, in, not in, is, is not

{% if user_list %}
  用户人数:{{ user_list|length }}
{% elif black_list %}
  黑名单数:{{ black_list|length }}
{% else %}
  没有用户
{% endif %}

include标签 -->加载模板并以标签内的参数渲染。 这是一种可以引入别的模板的方法。

{% include "name_snippet.html" %}
{% include "name_snippet.html" with person="Jane" greeting="Hello" %}

load标签 -->加载自定义模板标签集

{% load somelibrary package.otherlibrary %}
{% load foo bar from somelibrary %}

url标签 -->返回与给定视图和可选参数匹配的绝对路径引用(不带域名的URL)

{% url 'some-url-name' v1 v2 %}

{% url 'some-url-name' arg arg2 as the_url %}
<a href="{{ the_url }}">I'm linking to {{ the_url }}</a>

with标签 -->使用一个简单地名字缓存一个复杂的变量

{% with total=business.employees.count %}
    {{ total }} employee{{ total|pluralize }}
{% endwith %}

cycle标签 -->每当这个标签被访问,则传出一个它的可迭代参数的元素。 第一次访问返回第一个元素,第二次访问返回第二个参数,以此类推. 一旦所有的变量都被访问过了,就会回到最开始的地方,重复下去

{% for o in some_list %}
    <tr class="{% cycle 'row1' 'row2' %}">
        ...
    </tr>
{% endfor %}

firstof标签 -->输出第一个不为False参数。 如果传入的所有变量都为False,就什么也不输出

{% firstof var1 var2 var3 %}

 

3,过滤器

过滤器会更改变量或标签参数的值
{{ django|title }}

可以通过使用 过滤器来改变变量的显示;使用管道符号 (|)来应用过滤器;过滤器可以“链接”,即一个过滤器的输出应用于下一个过滤器

过滤器参数包含空格的话,必须被引号包起来;例如,使用逗号和空格去连接一个列表中的元素,你需要使用 {{ list|join:", " }}。
注:大多数模版过滤器返回字符串,length返回的是数字类型

常用的模板过滤器介绍:

{{ value|default:"nothing" }}  -->如果 value没有被提供,或者为空,将显示“nothing”
{{ value|default_if_none:"nothing" }} -->如果(且仅当)value为None,则使用给定的默认值。 否则,使用该value。
{{ value|center:"15" }}  -->使"value"在给定的宽度范围内居中.

{{ value|length }} -->返回值的长度;它对字符串和列表都起作用。
{{ value|filesizeformat }} -->格式化为“人类可读”文件大小
{{ value|add:"2" }} -->把add后的参数加给value

{{ value|lower }} -->转换为小写格式
{{ value|cut:" " }} -->移除value中所有的与给出的变量相同的字符串
{{ value|dictsort:"name" }} -->接受一个字典列表,并返回按参数中给出的键排序后的列表

{{ value|first }}、{{ value|last }} -->返回列表中的第一项、最后一项
{{ value|join:" // " }} -->使用字符串连接列表
{{ value|make_list }} -->返回转换为列表的值
{{ some_list|slice:":2" }} -->返回列表的一个切片

{{ value|random }} -->返回给定列表中的随机项
{{ value | floatformat:3 }}  -->指定浮点数格式
{{ value|get_digit:"2" }} -->返回指定位置的数字(从右边开始数)

{{ value|linebreaks }} -->用适当的HTML替换纯文本中的换行符,使用<br />,</p>
{{ num_messages|pluralize }} -->如果值不是1则返回一个复数形式的后缀;默认后缀为 's'
{{ value|safe }} -->不进行HTML转义

{{ value|truncatechars:9 }} -->如果字符串长于指定的字符数,则截断该字符串。 截断的字符串将以省略号序列(“...”)结束。
{{ value|wordcount }} -->返回字数
{{ value|date:"D d M Y" }} {{ value|time:"H:i" }} -->根据给定格式对一个date/time变量格式化

4,注释

单行注释:{# comment #}
多行注释:在第一个标签可以插入一个可选的记录。 比如,当要注释掉一些代码时,可以用此来记录代码被注释掉的原因。

{% comment "Optional note" %}
    <p>Commented out text with {{ create_date|date:"c" }}</p>
{% endcomment %}

三:模板继承

模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。

//骨架”模版:base.html

<!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>
//子模板样式举例

{% 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 标签,并用子模版中的内容来替换这些block

注:若子模版没有定义父模板中的某个 block,系统会使用父模版中的值。 父模版的 {% block %} 标签中的内容总是被用作备选内容(fallback)

可使用多级继承--使用继承的一个常用方式是类似下面的三级结构:
1,创建一个 base.html 模版来控制您整个站点的主要视觉和体验。
2,为您的站点的每一个“分支”创建一个base_SECTIONNAME.html 模版;这些模版都继承自 base.html ,并且包含了每部分特有的样式和设计。
3,为每一种页面类型创建独立的模版;这些模版继承对应分支的模版。
 

若干注意事项:

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

②在base模版中设置越多的 {% block %} 标签越好。 请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。 多一点钩子总比少一点好。

③如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中。

④如果需要获取父模板中的block 的内容,可以使用{{ block.super }} 变量。 如果你想要在父block 中新增内容而不是完全覆盖它,它将非常有用。

⑤在{% block %}之外创建的变量使用模板标签as语法不能在块内使用

⑥为了更好的可读性,你也可以给你的 {% endblock %} 标签一个 名字 。

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

⑦请注意不能在一个模版中定义多个相同名字的block 标签

四:HTML转义

用户提交的数据都不应该被盲目的信任,并且被直接插入到你的网页中,因为一个怀有恶意的用户可能会使用这样的漏洞来做一些可能的坏事。 这种类型的安全问题被叫做 跨站脚本(Cross Site Scripting) (XSS) 攻击。

两个解决方案:
第一, 你可以对每个不被信任的值运行escape 过滤器,它将把潜在的有害HTML 字符转换成无害的
第二,你可以利用Django的自动HTML转义(默认使用这种)

默认情况下,Django 中的每个模板会自动转义每个变量的输出。
明确地说,下面五个字符被转义:

字符 转义输出 字符 转义输出
< &lt; > &gt;
'(单引号) &#39; " (双引号) &quot;
& &amp;    

关闭自动转义:

1,使用safe过滤器来关闭独立变量上的自动转义:

This will not be escaped: {{ data|safe }}

2,将模板(或者模板中的特定区域)包裹在autoescape标签 中:

{% autoescape off %}
    This will not be auto-escaped: {{ data }}.

    Nor this: {{ other_data }}
    {% autoescape on %}
        Auto-escaping applies again: {{ name }}
    {% endautoescape %}
{% endautoescape %}

猜你喜欢

转载自blog.csdn.net/hua1011161696/article/details/80985621