Django之模板系统

此生再无相见时 提交于 2020-03-16 15:06:37

一.语法

模板渲染的官方文档

关于模板渲染你只需要记两种特殊符号(语法):

{{ }}和 {% %}

变量相关的用{{}},逻辑相关的用{%%}。

二.变量

  • 在Django的模板语言中按此语法使用:{{ 变量名 }}。
  • 当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。 变量的命名包括任何字母数字以及下划线 ("_")的组合。
    变量名称中不能有空格或标点符号。
  • 深度查询据点符(.)在模板语言中有特殊的含义。当模版系统遇到点("."),它将以这样的顺序查询:
        字典查询(Dictionary lookup)
        属性或方法查询(Attribute or method lookup)
        数字索引查询(Numeric index lookup)

示例:

views.py:

def index1(request):
    num = 10
    name = '张三'
    name_list = ['李四','王五']
    dic = {'name':'test','age':23,'hoby':'girl'}

    class Person:
        def __init__(self):
            self.name = 'dog'
        def dream(self):
            return 'dreamer'

    a = Person()  #返回一个对象

    return render(request,'index1.html',{'num':num,'name':name,'name_list':name_list,'dic':dic,'a':a})
    # return render(request,'index.html',locals())
    #locals()获取函数内容所有的变量,然后通过render方法给了index.html文件进行模板渲染,如果你图省事,你可以用它,但是很多多余的变量也被传进去了,效率低

index1.html文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>模板</h1>
<p>{{ num }}</p>
<p>{{ name }}</p>
<p>{{ name_list }}</p>
<p>{{ name_list.0 }}</p>
<p>{{ dic }}</p>
<p>{{ dic.age }}</p>
<p>{{ a.name }}</p>
</body>
</html>

三.过滤器

在Django的模板语言中,通过使用 过滤器 来改变变量的显示。
过滤器的语法: {{ value|filter_name:参数 }}
使用管道符"|"来应用过滤器。
例如:{{ name|lower }}会将name变量应用lower过滤器之后再显示它的值。lower在这里的作用是将文本全都变成小写。
注意事项:

  1. 过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
  2. 过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
  3. 过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:’, ’ }}
  4. '|'左右没有空格没有空格没有空格

Django的模板语言中提供了大约六十个内置过滤器。

length

返回值的长度,作用于字符串和列表。

{{ name_list|length }}

default

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

{{ xx|default:'啥也没有' }} #没有xx这个值就显示【啥也没有】

filesizeformat

将值格式化为一个 “人类可读的” 文件尺寸 (例如 ‘13 KB’, ‘4.1 MB’, ‘102 bytes’, 等等)。例如:

movesizi = 123342224
{{ movesizi|filesizeformat }}  #结果:117.6 MB

slice

切片,如果 value=“hello world”,还有其他可切片的数据类型

name = 'zhangsan'
{{ name|slice:'0:3' }}  #zha

date

格式化,如果 value=datetime.datetime.now()

格式化,如果 value=datetime.datetime.now()
{{ now|date:'Y-m-d' }}  #2020-03-12  不加date:March 12, 2020, 2:19 p.m.

truncatechars

如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“…”)结尾。参数:截断的字符数

words = 'i love you my girl'
{{ words|truncatechars:'9' }}   #结果:i love...  点也算在内

truncatewords

在一定数量的字后截断字符串,是截多少个单词。

例如:‘hello girl hi baby yue ma’,
{{ words1|truncatewords:'3' }}    #结果:hello girl hi ...

cut

移除value中所有的与给出的变量相同的字符串

words1 = 'hello girl hi baby yue ma'
{{ words1|cut:' ' }}  #移除空格  结果:hellogirlhibabyyuema

join

使用字符串连接列表,{{ list|join:’, ’ }},就像Python的str.join(list)

name_list = ['李四','王五']
{{ name_list|join:'*' }}  #以星号连接  结果:李四*王五

safe
Django的模板中在进行模板渲染的时候会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全,django担心这是用户添加的数据,比如如果有人给你评论的时候写了一段js代码,这个评论一提交,js代码就执行啦,这样你是不是可以搞一些坏事儿了,这叫做xss攻击,所以浏览器不让你这么搞,给你转义了。但是有的时候我们可能不希望这些HTML元素被转义,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
我们去network那个地方看看,浏览器看到的都是渲染之后的结果,通过network的response的那个部分可以看到,这个a标签全部是特殊符号包裹起来的,并不是一个标签,这都是django搞得事情。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200312143837278.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM5MjUzMzcw,size_16,color_FFFFFF,t_70
使用safe之后,允许HTML元素被转义,这个时候就是一个正常的a标签了:
在这里插入图片描述

四.标签Tags

标签看起来像是这样的: {% tag %}。标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} …标签 内容 … {% endtag %})。

for标签
遍历每一个元素: 写个for,然后 tab键自动生成for循环的结构,循环很基础,就这么简单的用,没有什么break之类的,复杂一些的功能,你要通过js

列表:
<ul>
    {% for name in name_list %}
        <li>{{ name }}</li>
    {% endfor %}
</ul>
字典:
<ol>
    {% for key,value in dic.items %} #和Python里面一样 这里可以循环key,values
        <li>{{ key }}-----{{ value }}</li>
    {% endfor %}
</ol>

循环序号:

注:循环序号可以通过{{forloop}}显示,必须在循环内部用  
forloop.counter            当前循环的索引值(1开始),forloop是循环器,通过点来使用功能
forloop.counter0           当前循环的索引值(从0开始)
forloop.revcounter         当前循环的倒序索引值(从1开始)
forloop.revcounter0        当前循环的倒序索引值(从0开始)
forloop.first              当前循环是不是第一次循环(布尔值)
forloop.last               当前循环是不是最后一次循环(布尔值)
forloop.parentloop         本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等

forloop.parentloop示例:

d2 = [[11,22],[33,44]]
<ol>
    {% for dd2 in d2 %}
        <li>
            {% for ddd2 in dd2 %}
                {{ forloop.parentloop.counter }}
                {{ forloop.counter}}  
                <a href="">{{ ddd2 }}</a>
            {% endfor %}
        </li>
    {% endfor %}
</ol>
结果:
	1 1 11 1 2 22  
	2 1 33 2 2 44
解释:
	父层循环里面有两个元素,第一次循环计数是1,内部循环里面两个值,第一次打印11 第二次打印22 计数分别为12
	父层循环里面有两个元素,第一次循环计数是2,内部循环里面两个值,第一次打印33 第二次打印44 计数分别为12

for … empty
for 标签带有一个可选的{% empty %} 从句,以便在给出的组是空的或者没有被找到时,可以有所操作。

<ul>
    {% for foo in d3 %}
        <li>{{ foo }}</li>
    {% empty %}
        <li>什么也没有</li>
    {% endfor %}
</ul>

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

if语句支持 andor==><!=<=>=innot inisis not判断,注意条件两边都有空格。

{% if num > 100 %}
    <a href="">大于100</a>
    {% elif num < 100 %}
    <a href="">小于100</a>
{% endif %}

还可以加过滤器:
{% if name_list|length > 3%}
    <a href="">大于3</a>
    {% elif name_list|length < 3%}
    <a href="">小于3</a>
    {% else %}
    <a href="">等于3</a>
{% endif %}

with
使用一个简单地名字缓存一个复杂的变量,多用于给一个复杂的变量起别名,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的注意等号左右不要加空格。

<p>{{ dic.name }}</p>

第一种写法:
{% with shitai=dic.name %}
    <h2>{{ shitai }}</h2>
{% endwith %}

第二种写法(as:类似与起别名){% with dic.name as shitai %}
    <h2>{{ shitai }}</h2>
{% endwith %}

以上标签注意事项:

1. Django的模板语言不支持连续判断,即不支持以下写法:
{% if a > b > c %}
...
{% endif %}

2. Django的模板语言中属性的优先级大于方法(了解)
def xx(request):
d = {"a": 1, "b": 2, "c": 3, "items": "100"}
return render(request, "xx.html", {"data": d})
如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items并且还有默认的 d.items() 方法,此时在模板语言中:
{{ data.items }}
默认会取d的items key的值。并不是itemsl方法。

csrf_token

我们以post方式提交表单的时候,会报错,还记得我们在settings里面的中间件配置里面把一个csrf的防御机制给注销了啊,本身不应该注销的,而是应该学会怎么使用它,并且不让自己的操作被forbiden,通过这个东西就能搞定。
这个标签用于跨站请求伪造保护,
在这里插入图片描述

五.模板继承

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

母版页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        .nav{
            background-color: red;
            height: 40px;
        }
        .left_menu{
            background-color: green;
            color: white;
            width: 20%;
            height: 400px;
            float: left;
        }
        .content{
            width: 80%;
            float: right;
        }
        .clearfix{
            content: '';
            display: block;
            clear: both;
        }

    </style>
</head>
<body>

<div class="nav">
    <a href="">22</a>
    <a href="">23</a>
    <a href="">24</a>
    <input type="text"><button>搜索</button>
</div>

<div class="clearfix">
    <div class="left_menu">
    <ul>
        <li><a href="{% url 'app02:menu1' %}">菜单1</a></li>
        <li><a href="{% url 'app02:menu2' %}">菜单2</a></li>
        <li><a href="{% url 'app02:menu3' %}">菜单3</a></li>
    </ul>
</div>

<div class="content">
    {% block content %}
        母版页面
    {% endblock %}
</div>
</div>

</body>
</html>
{% extends 'object.html' %}    #继承母版页面
{% block content %}            #预留的钩子 用来修改内容
    {{ block.super }}          #显示父类的内容
    首页
{% endblock %}
{% extends 'object.html' %}
{% block content %}
    菜单3
{% endblock %}
{% extends 'object.html' %}
{% block content %}
    菜单2
{% endblock %}
{% extends 'object.html' %}
{% block content %}
    菜单1
{% endblock %}

这里是使用继承的一些提示:

  • 如果你在模版中使用 {% extends %}标签,它必须是模版中的第一个标签。其他的任何情况下,模版继承都将无法工作,模板渲染的时候django都不知道你在干啥。
  • 在base模版中设置越多的 {% block %}标签越好。请记住,子模版不必定义全部父模版中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,只定义你需要的那一个。多一点钩子总比少一点好。
  • 如果你发现你自己在大量的模版中复制内容,那可能意味着你应该把内容移动到父模版中的一个 {% block %} 中。
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!