django之模板层(templates)

发布时间 2023-06-26 17:23:05作者: wwwxxx123

django之模板层(templates)

模板语法简介

模板语法是由后端处理的,我们一般使用render函数处理(视图层的函数,最终将处理好的html作HttpResponse返回出去)。

模板层基本涉及三种形式的语法:

  • {{}}:主要与数据值相关
  • {%%}:主要与逻辑值相关
  • {##}:模板语法注释

关于模板注释,与我们html中所自带的注释是有本质的区别的,说到底,模板语法{{}}是由后端处理的,当识别为模板注释时就会从html文件中移除了,不会返回给用户;而html注释<!---->是由前端浏览器对html处理时渲染时不做处理,但检查网页源码时还是能看见这些注释的。

模板语法数据相关{{}}

传值和展示值

  • 传值

    render函数的第三个参数(名称空间)就是用来传值的,是以字典的形式:

    {"模板中名称1":后端数据,"模板中名称2":后端数据2,..}

    我们用字典形式传值的特点是传值精准,但是写起来比较麻烦。

    我们还可以直接用local()的返回值作为名称空间,实际上就是将视图函数的局部空间整个打包给模板语法使用,这样做便于测试,不必复杂的编写,不过可能浪费空间资源。

    传值总结:

    可以使用名称空间字典作为render函数的第三个参数进行传值,名称空间可以是字典和local()

  • 展示值

    将名称传入模板后,我们可以用{{ 模板变量 }}的形式往html内部插入值。

    模板传值语法展示

    渲染效果:

    img

传值的一些特性总结:

  • 基本数据类型正常展示
  • 文件对象也可以展示并调用方法(如read方法)
  • 函数名会自动加括号执行并将返回值展示到页面上,但不支持额外传参
    这个函数可以是独立的函数,也可以是对象的属性方法
  • 类名也会被识别自动加括号执行并返回一个对象
    对象可以使用不含额外参数的对象方法和获取对象的一些数据属性
  • 索引、键、属性只能通过句点的方式取

模板语法过滤器(filters)

过滤器可以对获取的数据做一些简单操作,它会将获取的数据作为输入,并做一些简单操作后作为输出再去插入我们的html页面中。

语法:{{ value|过滤器名:参数 }}

  • 过滤器用管道符隔开(无空格),最多支持多传入一个参数。
  • 过滤器是支持链式的,可以将多个过滤器串起来,上一个过滤器的输出作为下一个的输入

Django的模板语言中提供了大约六十个内置过滤器,这里简单介绍一下。

整理至此,即查即用

过滤器 功能 示例
default 如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值。 {{ value|default:"nothing"}}
length 对于字符串列表这类有length属性的,得到其值 {{ value|length}}
filesizeformat 将传入的数字当做文件的字节数,将其处理成合适展示的文件大小,如2048就会展示为2 KB {{ value|filesizeformat }}
slice 对字符串进行切片 {{value|slice:"2:-1"}}
add 将传入的数字或字符串做相加或拼接处理 {{value|add:1}}
safe 模板语法默认转义带html语法的文本,safe取消标签文本转义,让其可以被html渲染 {{ value|safe}}
truncatechars 如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。 {{ value|truncatechars:9}}
truncatewords 在一定数量的字后截断字符串,处理同上...。 {{ value|truncatewords:9}}
cut 移除value中所有的与给出的变量相同的字符串如果value为'i love you',那么将输出'iloveyou'. {{ value|cut:' ' }}
timesince datetime数据距离现在的时间(从现在起) {{ blog_date|timesince }}
timeuntil datetime数据距离现在的时间(到现在止) {{ blog_date|timesince }}
date datetime数据字符化输出 {{ value|date:"Y-m-d H:i:s"}}

自定义过滤器(了解)

自定义过滤器需要搭建:

  • 应用下创建一个templatetags目录
  • 目录下可以创建一个任意名字的py文件
  • 在上述py文件中写入:
# 将py文件命名为mytag.py
from django import template
register = template.Library()


# 自定义过滤器
@register.filter(name='myupper')  # 这里的名字就是自定义filter的名字
def func1(a):   # 如果是一个参数,则就是将模板语法获取数据传入参数a
    return a.upper()

@register.filter(name="myadd")
def func2(a,b):  # 如果是两个参数,则额外的过滤器后的实参传入参数b
    return a+b

过滤器最多支持两个参数,参照{{ value|filter param }}一个是|前的,一个是filter后的

自定义过滤器的使用:

{% load mytag%}   {# 将py文件导入 #}
{{ s|myupper }}   {# s字符串大写 #} 
{{ i|myadd:2 }}    {# i数字加2 #}

模板语法逻辑相关

模板标签(分支、循环)

在模板语法中与逻辑相关的一些语法都用{% %}括起来。这些形式的模板语法被称为模板标签,它们常常可以将html页面分割成很多块,这些html文本块可以按一定的逻辑被重新排列。

分支标签

{% if 条件1 %}
<p>如果条件1成立,我则会出现在html页面上</p>
{% else if 条件2 %}
<p>如果条件2成立,我则会出现在html页面上</p>
{% else %}
<p>如果以上条件都不成立,我则会出现在html页面上</p>
{% endif %}  {# 结束分支体 #}

if逻辑块中的小块只会出现一个,就像我们分支程序中的多个子代码只能执行一段子代码一样。

  • 条件的形式支持:and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断
  • 条件中的值可以直接用模板变量,也可以加装过滤器

循环标签

{% for row in asc_row %}   {# row的内容是"第1行""第2行"直到5 #}
    {% if forloop.first %}	{# 循环套分支,并且条件里面有一个forloop对象 #}
        <p>这是第一次循环,所以forloop.first为真</p>
	{% else %}		
		<p>{{ row }}</p>
    {% endif %}
{% empty %}
	<p>如果是asc_row是空的,则这个标签会出现</p>
{% endfor %}

img

for模板标签中的块是重复块,重复块会重复的出现在页面中,当然我们也可以通过其他逻辑让其每次的重复有些许的不同。

除了关键字{% for 变量 in 迭代对象 %} {% empty %} {% endfor %}外,for模板标签中还可以使用forloop对象拿到一些参数:

变量 描述
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是不是第一次循环(布尔值)
forloop.last 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环

给模板变量起别名

{% with d1.aaa.2.ss as vari %}  {# 给复杂变量取别名 #}
<p>{{ vari }}</p>
{# 在此之前都可以使用这个名字 #}
{% endwith %}

load加载

这个主要是配合django的一些配置使用的,如我们之前所说的加载静态文件路径,配置中就已经将我们的静态文件的路由和路径配置好了:

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

那么在模板语法中就加载这个路径,并动态的进行拼接:

{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-5.1.3-dist/css/bootstrap.css' %}">
<script src="{% static 'bootstrap-5.1.3-dist/js/bootstrap.bundle.js' %}"></script>

当然load的用法因为与配置挂钩,其用法也要结合具体的配置发生变化,如下文中的自定义标签。

自定义标签、inclusion_tag(了解)

自定义标签和局部html代码也属于自定义代码,需要三步走:

templatetags文件夹--一个py文件--写入下述代码
from django import template
register = template.Library()   # register看起来是个变量,但是一个字都不能错
  • 自定义标签

    @register.simple_tag(name="show_info")  # 注册自定义标签的名字
    def tag1(name,age,gender):  # 参数没有限制
        return f"姓名:{name}|年龄:{age}|性别:{gender}"
    

    使用:

    {% load mytag%}   {# 将py文件导入 #}
    {% show_info "leethon" 18 "male"  %}   {# 多个参数空格隔开跟在标签名后 #}
    
  • 自定义inclusion_tag

    inclusion_tag可以组织一段html代码,最终将处理好的html文本导入模板

    @register.inclusion_tag("display.html", name="display_info")  # menu文件时承载组织html文本的文件
    def func(name, age, gender):
        name = "姓名:" + name.upper()
        age = f"年龄:{age}"
        gender = "性别:" + gender.upper()  # 对信息做一些预处理
        return locals()  # 将名称空间提供给display.html
    

使用:

首先display.html中可以使用上述代码中locals提供给它的所有变量。

其次在其他模板中:

{% load mytag%}   {# 将所属py文件导入 #}
{% display_info "lee" 18 'male' %}   {# 按位置传参数 #}

母版的继承(重点)

多个模板中可能出现多个重复的地方,如很多页面都有相似或者相同的侧边栏、页顶组件等,django提供了一种语法让templates的所有html文件能够成为母版,让别的模板可以引用这个母版的形式,并对事先开设的一些区块做个性化的修改。

母版中:
{% block 块名 %}
	预留给子版做修改的区域
{% endblock %}

子版继承:
{% extends "home.html" %} 
{#将home.html整个引入#}
{% block 块名 %}
	子版自己独有的内容
{% endblock %}

img

关于子版继承的位置,我们建议有三个位置:

  • 页面内容区:对页面核心内容做修改
  • css样式区:导入一些独有的样式
  • js代码区:页面底端导入一些js代码,做一些界面逻辑

我们还可以在子版继承时,将原html文件中的block内容拿过来

{% block 块名 %}
	在block内部可以使用block的super属性拿到母版的这个区域的内容
	{{ block.super }}
	{{ block.super }}
{% endblock %}

模板的导入(了解)

在一个html文件中预先编辑好局部的html文本,其他模板可以直接通过下面语句导入这部分的html文本:

{% include 'myform.html' %}