django之模板层(templates)
django之模板层(templates)
模板语法简介
模板语法是由后端处理的,我们一般使用render函数处理(视图层的函数,最终将处理好的html作HttpResponse返回出去)。
模板层基本涉及三种形式的语法:
- {{}}:主要与数据值相关
- {%%}:主要与逻辑值相关
- {##}:模板语法注释
关于模板注释,与我们html中所自带的注释是有本质的区别的,说到底,模板语法{{}}
是由后端处理的,当识别为模板注释时就会从html文件中移除了,不会返回给用户;而html注释<!---->
是由前端浏览器对html处理时渲染时不做处理,但检查网页源码时还是能看见这些注释的。
模板语法数据相关{
传值和展示值
-
传值
render函数的第三个参数(名称空间)就是用来传值的,是以字典的形式:
{"模板中名称1":后端数据,"模板中名称2":后端数据2,..}
我们用字典形式传值的特点是传值精准,但是写起来比较麻烦。
我们还可以直接用
local()
的返回值作为名称空间,实际上就是将视图函数的局部空间整个打包给模板语法使用,这样做便于测试,不必复杂的编写,不过可能浪费空间资源。传值总结:
可以使用名称空间字典作为render函数的第三个参数进行传值,名称空间可以是字典和local()
-
展示值
将名称传入模板后,我们可以用
{{ 模板变量 }}
的形式往html内部插入值。模板传值语法展示
渲染效果:
传值的一些特性总结:
- 基本数据类型正常展示
- 文件对象也可以展示并调用方法(如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 %}
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 %}
关于子版继承的位置,我们建议有三个位置:
- 页面内容区:对页面核心内容做修改
- css样式区:导入一些独有的样式
- js代码区:页面底端导入一些js代码,做一些界面逻辑
我们还可以在子版继承时,将原html文件中的block内容拿过来
{% block 块名 %}
在block内部可以使用block的super属性拿到母版的这个区域的内容
{{ block.super }}
{{ block.super }}
{% endblock %}
模板的导入(了解)
在一个html文件中预先编辑好局部的html文本,其他模板可以直接通过下面语句导入这部分的html文本:
{% include 'myform.html' %}