Django——模板基础

每一个Web框架都需要一种很便利的方法用于动态生成HTML页面。 最常见的做法是使用模板。

模板包含所需HTML页面的静态部分,以及一些特殊的模版语法,用于将动态内容插入静态部分。

说白了,模板层就是如何往HTML文件中填入动态内容的系统。

模板的设计实现了业务逻辑view与显示内容template的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用。

 1.配置引擎

Django可以配置一个或多个模板引擎(语言),也可以不用引擎。

Django自带一个称为DTL(Django Template Language )的模板语言,以及另外一种流行的Jinja2语言(需要提前安装,pip install Jinja2)

如果使用默认引擎,也不用配置什么,详细的配置,这里不做赘述,可以参考这个博客http://www.liujiangblog.com/course/django/144,或官方文档(英文允许的话)。

2模板语法—变量

变量看起来就像是这样: {{ variable }}。

当模版引擎遇到一个变量,它将从上下文context中获取这个变量的值,然后用值替换掉它本身。

变量的命名包括任何字母数字以及下划线("_")的组合。点(".")也有可能会在变量名中出现,不过它有特殊的含义。最重要的是,变量名称中不能有空格或标点符号。

当模版系统遇到点("."),它将以这样的顺序查询这个圆点具体代表的功能:

  • 字典查询(用于字典)
  • 属性或方法查询(用于类)
  • 数字索引查询(用于列表或元组)

如果你使用的变量不存在,模版系统将插入string_if_invalid选项的值,默认设置为''(空字符串)。

示例:

视图views.py

class Book(object):
    def __init__(self, title):
        self.title=title


def test(request):
    nums=[10, 11, 12]
    info={'name':'Eric'}
    book=Book('长得帅如何与人相处')
    context={'nums':nums, 'info':info, 'book':'book'}
    return render(request, 'test.html', context)
View Code

模板test.html

<body>
<h3>书的编号:{{ nums.0 }}</h3>
<h3>书的作者:{{info.name }}</h3>
<h3>书的名字:{{ book.title }}</h3>
</body>
View Code

 注意:句点符也可以用来引用对象的方法(无参数方法):

<h3>作者:{{ info.name.upper }}</h3>

3过滤器

因为过滤器紧挨着变量,所以先说过滤器

过滤器看起来是这样的:{{ name|lower }}。使用管道符号(|)来应用过滤器。该过滤器将文本转换成小写。

一些过滤器带有参数,过滤器参数包含空格的话,必须用引号包起来。例如,使用逗号和空格去连接一个列表中的元素,你需要使用{{ list|join:", " }}

django内置的过滤器有很多,列举几个常用的:

default

如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。

{{ value|default:"nothing" }}

length

返回值的长度。它对字符串和列表都起作用。

{{ value|length }}
# 如果value是['a', 'b', 'c', 'd'],那么输出4。

slice

返回列表的一部分。也就是切片,与Python的列表切片相同的语法。

{{ some_list|slice:":2" }}
# 如果some_list是['a', 'b', 'c'] ,输出将为['a', 'b']。

truncatechars

如果字符串包含的字符总个数多于指定的字符数量,那么会被截断掉后面的部分。截断的字符串将以“...”结尾。

{{ value|truncatechars:9 }}
# 如果value是Joel is a slug,输出为Joel i...。

date

根据给定格式对一个日期变量进行格式化。

# 如果 value=datetime.datetime.now()
{{ value|date:"Y-m-d" }}

safe

Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。比如:

value="<a href="">点击</a>"
{{ value|safe}}

关于自动转义,我们后面再说。

4.标签

标签看起来像是这样的: {% tag %}

标签比变量复杂得多,有些用于在输出中创建文本,有些用于控制循环或判断逻辑,有些用于加载外部信息到模板中供以后的变量使用。

一些标签需要开始和结束标签(即 {% 标签 %} ... 标签 内容 ... {% ENDTAG %})。

同样,列举几个常用的:

for标签

# 循环对象中的每一个元素
<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 %}
View Code

下面是Django为for标签内置的一些属性,可以当作变量一样使用{{ }}在模版中使用。

  • forloop.counter:循环的当前索引值,从1开始计数;常用于生成一个表格或者列表的序号!
  • forloop.counter0:循环的当前索引值,从0开始计数;
  • forloop.revcounter: 循环结束的次数(从1开始)
  • forloop.revcounter0 循环结束的次数(从0开始)
  • forloop.first:判断当前是否循环的第一次,是的话,该变量的值为True。我们经常要为第一行加点特殊的对待,就用得上这个判断了,结合if。
  • 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>
View Code

if标签

{% if %}会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的False值),这个内容块就会输出。

if标签可以使用not,and或or来测试布尔值

if标签允许使用这些操作符:==!=<><=>=innot inisis not

{% if num > 100 or num < 0 %}
    <p>无效</p>
{% elif num > 80 and num < 100 %}
    <p>优秀</p>
{% else %}
    <p>凑活吧</p>
{% endif %}
View Code

include

加载指定的模板并以标签内的参数渲染。这是一种引入别的模板的方法,include类似Python的import。

{% include "foo/bar.html" %}        # 将子模版渲染并嵌入当前HTML中

url

这是路由在模板层面反向解析用到的标签,返回与给定视图和可选参数匹配的绝对路径引用(不带域名的URL)

{% url 'some-url-name' v1 v2 %}
# 第一个参数是url()的名字,其他参数是可选的并且以空格隔开,这些值会在URL中以参数的形式传递

如果使用urlconf的名称空间网址,通过冒号指定完全名称,如下所示:

{% url 'myapp:view-name' %}

with

使用一个简单地名字缓存一个复杂的变量,当你需要使用一个代价较大的方法(比如访问数据库)很多次的时候这是非常有用的。

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

csrf_token

这个标签用于跨站请求伪造保护

5.自定制标签、过滤器

Django为我们提供了自定义的机制,可以通过使用Python代码,自定义标签和过滤器来扩展模板引擎,然后使用{% load %}标签。

5.1配置准备

1.将要增加自定义标签的app在INSTALLED_APPS中注册,否则django无法找到自定义的标签。

2.在app中新建一个templatetags(名字固定,不能变,只能是这个),和views.py、models.py等文件处于同一级别目录下。这是一个包!不要忘记创建__init__.py文件以使得该目录可以作为Python的包。并在该包下创建了一个名为mytags.py的文件。

3.要在模块内自定义标签,首先,这个模块必须包含一个名为register的变量,它是template.Library的一个实例,所有的标签和过滤器都是在其中注册的。 所以把如下的内容放在mytags.py文件顶部:

from django import template

register = template.Library()

5.2自定义过滤器

  1.  自定义过滤器实际上就是写一个函数
  2. django会将过滤器前的值传入该函数
  3. 函数完成后,需要进行注册register

因为第二步django已经帮我们完成,所以我们实际上只需要自己完成第一步和第三步

示例:定义一个自动省略字符的过滤器

# mytags.py

from django import template

register = template.Library()


@register.filter(name='truncate_char')        # 注册过滤器的装饰器,name属性可以省略
def truncate_char(value):       # 定义过滤器的函数
    if len(value) > 20:
        return value[0:20]+'...'
    else:
        return value
View Code

然后在模板页面装载使用

{% load mytags %}     装载自定义过滤器
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{{ '超过20个字符后,将后面的字符省略,没超过20个字符,则可以显示全部'|truncate_chars }}
</body>
</html>
View Code

5.3自定义标签

自定义标签相对于自定义过滤器来说要复杂很多,因为自定义标签可以做任何事情!

自定义标签分为很多类型

  1. 简单标签  Simple tags
  2. 内含标签  Inclusion tags
  3. 分配标签  Assignment tags

5.3.1简单标签

import datetime
from django import template

register = template.Library()

@register.simple_tag
def current_time(format_string):    # 传入一个时间格式
    return datetime.datetime.now().strftime(format_string)     # 返回当前时间

Library.simple_tag(takes_context=True),takes_context=True参数可以让我们访问模板的当前环境上下文,即将当前环境上下文中的参数和值作为字典传入函数中的一个名为context的参数

@register.simple_tag(takes_context=True)
def current_time(context,fromat_string):
    timezone = context['timezone']      # 接收上下文参数
    return your_get_current_time_method(timezone, format_string)

当使用take_context=True时,函数的第一个参数必需为context。也可以使用name参数对函数进行重命名。

5.3.2内含标签

这种类型的标签可以被其他模板进行渲染,然后将渲染结果输出

Library.inclusion_tag()支持take_context=True,用法类似Library.simple_tag()

from django import template
register = template.Library()

@register.inclusion_tag('result.html')
def tset():
    a=['first', 'second', 'third']
    return {'choices': a}

result.html

<ul>
{% for choice in choices %}
    <li> {{ choice }} </li>
{% endfor %}
</ul>

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% load mytags %}      # 装载自定义模块
{% test %}      # 导入标签
</body>
</html>
View Code

5.3.3分配标签

类似于简单标签,但并不会输出结果,可以使用 as 关键字将结果赋给一个参数。

@register.assignment_tag
def get_current_time(format_string):
    return datetime.datetime.now().strftime(format_string)
{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>

6.模板继承

Django模版引擎中最强大也是最复杂的部分就是模版继承了。模版继承可以让我们创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。

模板继承和类的继承含义是一样的,主要是为了提高代码重用,减轻开发人员的工作量。

父模板

如果发现在多个模板中某些内容相同,那就应该把这段内容定义到父模板中。

block标签:用于在父模板中预留区域,留给子模板填充差异性的内容,名字不能相同。 为了更好的可读性,建议给endblock标签写上名字,这个名字与对应的block名字相同。父模板中也可以使用上下文中传递过来的数据。

{% block 名称 %}
    预留区域,可以编写默认内容,也可以没有默认内容
{% endblock %}

子模板

extends标签继承,写在子模板文件的第一行

{% extends "父模板路径" %}

子模版不用填充父模版中的所有预留区域,如果子模版没有填充,则使用父模版定义的默认值。
填充父模板中指定名称的预留区域。

{% block 名称 %}
实际填充内容
{{ block.super }}     # 用于保留父模板中block的内容
{% endblock 名称 %}

示例

父模板:base.html

<html>
<head>
    <title>{{title}}</title>
</head>
<body>
    <h2>这是头</h2>
    <hr>
    {%block content%}
    这是内容,有默认值
    {%endblock content%}
    <hr>
    {%block foot%}
    {%endblock foot%}
    <hr>
    <h2>这是尾</h2>
</body>
</html>
View Code

子模板:test.html

{% extends "base.html" %}

{% block content %}
    两个黄鹂鸣翠柳
    我还没有女朋友
    {{ block.super }}
{% endblock content %}

{% block foot %}
    垂死病中惊坐起
    笑问客从何处来
{% endblock foot %}
View Code

那么子模板的输出效果就是:

<html>
<head>
    <title>{{title}}</title>
</head>
<body>
    <h2>这是头</h2>
    <hr>
    两个黄鹂鸣翠柳
    我还没有女朋友
    这是内容,有默认值
    <hr>
    垂死病中惊坐起
    笑问客从何处来
    <hr>
    <h2>这是尾</h2>
</body>
</html>
View Code

注意:

  • 如果你在模版中使用 {% extends %} 标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作。
  • 在base模版中设置越多的 {% block %} 标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
  • 如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中
  • 不能在一个模版中定义多个相同名字的 block 标签。
终日不为以思,无益,不如学也
原文地址:https://www.cnblogs.com/lymlike/p/11561551.html