Django笔记:DTL模板
对于模板引擎,比较有名的有DTL和Jinja2等,Django使用的则是DTL(Django Template Language),虽然也可以配置Django项目使用别的模板引擎,但是推荐使用Django自带的DTL。DTL模板是一种含有特殊语法的HTML文件,在Django中,这种文件会先被DTL模板引擎预编译为一个普通的HTML文件,然后再发送到客户端。
一、render传参(模板变量)
使用render
返回HTML模板时,给render
的参数context
指定一个字典,字典的key对应HTML模板中使用的变量,key对应的value则是该变量的值,在HTML模板中使用语法{{ key }}
即可。如果key对应的value是一个对象,也可以使用{{ key.attr_name }}
的形式获取对象的属性等信息。
"""视图函数"""
from django.shortcuts import render
def index(request):
context = {
"username": "Hello world!"
}
# 给render的context参数指定一个字典并将其传入到HTML模板中
return render(request, "index.html", context=context)
<body>
{{ username }}
</body>
其他用法:
- 对象嵌套:例如字典中的value也是一个字典,想要获取这个嵌套字典中的value,直接使用点号即可
{{ key.sub_key }}
。 - 获取列表中的某个元素:使用形如
{{ list.0 }}
表示获取列表的第0个元素,想要获取其他的元素,也是类似的用法。
二、模板标签
模板标签就相当于在HTML模板中使用的“Python代码”,但是需要注意,所有的标签语法都需要包裹在{% %}
中,并且大多标签都有其对应的闭合标签,闭合标签通常是“end+标签名”的形式,如if
的闭合标签为endif
。
if标签
相当于Python中的if
语句,有对应的elif
和else
语句,同样也可以使用==, !=, <, <=, >, >=, in, not, is, is not
等判断运算符,对应的闭合标签为endif
。
{% if age < 18 %}
<p>未成年</p>
{% elif age == 18 %}
<p>刚成年</p>
{% else %}
<p>已成年</p>
{% endif %}
for标签
相当于Python中的for
语句,基本结构为for...in...empty
,如果遍历的对象中没有值,则会执行empty
标签中的内容,对应的闭合标签为endfor
。
注:DTL模板语法中的for
标签是没有continue
和break
语句的。
示例:正序遍历
<ul>
{% for book in books %}
<li>{{ book }}</li>
{% empty %}
<li>没有书籍!</li>
{% endfor %}
</ul>
示例:反序遍历(在遍历的对象后面添加一个reversed
关键字)
<ul>
{% for book in books reversed %}
<li>{{ book }}</li>
{% endfor %}
</ul>
示例:遍历字典,可以使用字典对应的keys
、values
和items
等方法,但是注意方法名后面没有Python中表示执行的括号。
{% for key, value in person.items %}
<p>key: {{ key }}</p>
<p>value: {{ value }}</p>
{% endfor %}
在for
循环中,DTL提供了一个forloop
变量来查询此for
循环的一些信息:
-
forloop.counter
:当前循环的下标,以1开始。 -
forloop.counter0
:当前循环的下标,以0开始。 -
forloop.revcounter
:forloop.counter
的反向下标。 -
forloop.revcounter0
:forloop.counter0
的反向下标。 -
forloop.first
:是否是第一次遍历。 -
forloop.last
:是否是最后一次遍历。 -
forloop.parentloop
:如果有多重for
循环,那么这个属性代表当前循环的上一个循环。
with标签
with
标签是用来在HTML模板中定义变量的,形如{% with var_name=value %}...{% endwith %}
或者{% with value as var_name %}...{% endwith %}
,注意,如果使用等号=
的方式,那么等号=
两边不能有空格,对应的闭合标签为endwith
。
注:with
中定义的变量只能在对应的with
语句块中使用。
"""视图函数"""
from django.shortcuts import render
def index(request):
context = {
"persons": ["张三", "李四"]
}
return render(request, "index.html", context=context)
{% with person.1 as lisi %}
<p>{{ lisi }}</p>
{% endwith %}
url标签
url
标签的作用就相当于from django.shortcuts import reverse
,用于通过URL名称反转为对应的URL,区别在于,reverse
用在Python文件中,url
标签则用在HTML模板文件中。
示例:普通用法,使用{% url "url_name" %}
的方式。
urlpatterns = [
path("book/", views.book, name="book")
]
<ul>
<li><a href="/">首页</a></li>
<li><a href="{% url "book" %}">读书</a></li>
</ul>
示例:通过url
标签传参,在url
标签语句后面添加需要的参数即可,多个参数之间使用空格分隔。
<li><a href="{% url "book" book_id="1" %}">读书</a></li>
示例:通过url
标签传入查询字符串,和reversed
的使用类似,需要手工拼接查询字符串。
<li><a href="{% url "book" %}?book_id=1">读书</a></li>
spaceless标签
此标签会移除HTML标签之间的空白字符,包括空格、tab键、换行等,闭合标签为endspaceless
。
注:此标签不会移除HTML标签内本身的内容。
以下代码:
{% spaceless %}
<p>
<a href="foo/"> Foo </a>
</p>
{% endspaceless %}
渲染完成后,变为:
<p><a href="foo/"> Foo </a></p>
autoescape标签
此标签表示自动转义功能,默认是开启的(on),表示将HTML中的特殊字符转义为HTML语法中的字符表示,如将<
转义为<
等,这意味着,字符串中的这些字符不会当成HTML语法来进行渲染加载,而是当成了普通字符,如果关闭自动转义功能(off),则会将字符串中的特殊字符当成HTML语法符号来进行渲染加载。闭合标签为endautoescape
。
注:为了安全考虑,一个字符串需要确认安全可信任后才能关闭自动转义。
示例:使用autoescape
关闭了自动转义功能后,加载出来直接就是一个超链接了。
context = {
"info": "<a href="www.baidu.com">百度</a>"
}
{% autoescape off %}
{{ info }}
{% endautoescape %}
verbatim标签
在DTL模板中会自动解析{% %}
和{{ }}
等字符,如果某段代码你不想DTL去解析,就想它按照原内容输出,就可以使用verbatim
标签将这部分代码包裹起来。闭合标签为endverbatim
。
三、模板过滤器
过滤器其实就相当于一个可以接收参数的函数,对传入模板的某些值进行处理后显示。对于一个普通函数,如果直接通过render
将函数传入模板中,把它当成一个变量来使用,如果函数没有参数需要传递,则会直接将函数返回值渲染到模板中,如果这个函数需要参数,则无法这样使用了,此时可以考虑使用自定义过滤器来实现该函数的功能。
注:过滤器最多只能接收两个参数,使用形如{{ value|filter_name[:value2] }}
。
示例:将无参函数直接传入模板中
from django.shortcuts import render
def greet():
return "hello world!"
def index(request):
context = {
"greet": greet
}
return render(request, "index.html", context=context)
# 直接在模板中这样写:{{ greet }}
# 会将greet函数的返回值添加到模板中
内置模板过滤器
这里列举一些Django内置的常用过滤器,更多过滤器可以去官网看看。
-
add
:使用形如{{ value|add:arg }}
,会尝试将value
和后面的参数先转换为int
类型再相加,如果失败,则会将两个参数直接进行+
运算(字符串拼接和列表拼接),如果再次失败,则返回一个空字符串。 -
cut
:使用形如{{ value|cut:arg }}
,移除字符串value
中指定的子串arg
,相当于Python中的value.replace(arg, "")
。 -
date
:使用形如{{ my_date|date: "Y-m-d" }}
,将传入模板的日期对象如from datetime import datetime;my_date = datetime.now()
根据后面的格式字符串进行格式化。常用的格式字符如下:格式字符 描述 Y 四位数字的年份 m 月份,如01-12 n 月份,如1-12 d 天,如01-31 j 天,如1-31 h 小时,12小时制,如01-12 g 小时,12小时制,如1-12 H 小时,24小时制,如01-24 G 小时,24小时制,如1-24 i 分钟,如00-59 s 秒,如00-59 -
default
:使用形如{{ value|default:arg }}
,如果value
在Python的if
判断中被判断为False
的话,如None
、空列表、空字符串、空字典等,则使用default
指定的值arg
。 -
default_if_none
:使用形如{{ value|default:arg }}
,如果value
的值为None
则使用default
指定的值arg
。 -
fist
:使用形如{{ value|first }}
,返回列表、元组、字符串的第一个元素。 -
last
:使用形如{{ value|last }}
,返回列表、元组、字符串的最后一个元素。 -
floatformat
:使用形如{{ value|floatformat }}
或者{{ value|floatformat:num }}
,格式化数字value
的输出(四舍五入),参数num
表示输出的小数位数,如果没有指定num
(前者),则默认输出一位小数,需要注意,默认的情况下(前者),如果数字value
的小数部分原本就全为0,则不会输出对应的小数,只会输出为整数。 -
join
:使用形如{{ value|join:"/" }}
,于Python中的join
方法类似,将列表或元组或字符串使用指定的字符拼接起来。 -
length
:使用形如{{ value|length }}
,获取列表、元组、字符串、字典等的长度。 -
lower
:使用形如{{ value|lower }}
,将value
中的字母全部转换为小写。 -
upper
:使用形如{{ value|upper }}
,将value
中的字母全部转换为大写。 -
random
:使用形如{{ value|random }}
,在给定的列表、元组、字符串中随机选择一个值。 -
safe
:使用形如{{ value|safe }}
,表示给定的字符串value
是安全的,会关闭该字符串的自动转义,相当于{% autoescape off %} {{ value }} {% endautoescape %}
,即如果value
中包含了html接去执行这部分代码。 -
slice
:使用形如{{ value|slice:"2:" }}
,相当于Python中的切片操作,Python中怎么切片,这里就怎么用,比如步长也是支持的,如{{ value|slice:"2::2" }}
指定步长为2。 -
striptags
:使用形如{{ value|stiptags }}
,删除字符串中的所有HTML标签。 -
truncatechars
:使用形如{{ value|truncatechars:num }}
,只显示字符串的前num-3
个字符串,之所以要减3,是因为num
表示要显示的字符串总长度,而最后输出的字符串后面会有三个点...
就占了3个字符了。 -
truncatechars_html
:使用形如{{ value|truncatechars_html:num }}
,功能和truncatechars
类似,不同之处在于,truncatechars
会切割value
中的所有内容,而truncatechars_html
会忽略value
中的HTML标签。
自定义模板过滤器
模板过滤器其实就是一个普通的函数,自定义过滤器注意事项和步骤如下:
- 在子app目录下新建一个
templatetags
包,注意,这个包名只能是这个名称,不能随便进行自定义,不然Django无法识别。 - 在
templatetags
包下新建一个Python文件,文件名可以自定义,如my_filter.py
,然后在文件中进行过滤器的定义和注册。函数(过滤器)定义时,第一个参数必须是竖线左侧的值value
,如果过滤器需要参数,可以定义第二个参数,注意,过滤器最多只能有两个参数。示例代码如下:
"""my_filter.py"""
from django import template
register = template.Library()
# 定义过滤器,可以只有一个参数value,也可以定义两个参数,第二个参数可以设置默认值
# 注册方式一:以装饰器的方式进行注册,过滤器名称默认和函数名一样,
# 也可以通过参数指定过滤器名称
# @register.filter("my_greet")
@register.filter
def greet(value, word=""):
return value+word
# 注册方式二:以方法的方式进行注册,可以自定义过滤器名称
# register.filter("greet", greet)
- 将子app添加到
settings.py
中的配置项INSTALLED_APPS
。 - 在模板中使用自定义过滤器时,需要先在模板开头添加如
{% load my_filter %}
,注意,这里的my_filter
为包含过滤器的Python文件。示例代码如下:
{% load my_filter %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ value|greet:" 你好!" }}
</body>
</html>
四、特殊标签
include标签
使用形如{% include "xxx.html" [with var=value] %}
,相当于是把xxx.html
文件中的内容直接插入到指定位置(这个标签使用时的位置),with
表示定义一个参数,此参数可以在xxx.html
文件中引用。
对于父模板(使用include
标签的模板)中的参数,子模板(xxx.html
)可以直接使用,如果父模板中没有此参数,就需要使用with
来定义该参数,不然子模板无法使用父模板中没有的参数了。xxx.html
的路径表示也是相对于templates
文件夹的位置。
extends标签extends
标签必须写在HTML代码的最前面一行,否则会报错。
使用形如{% extends "xxx.html" %}
,可以将xxx.html
中所有的内容继承到当前文件中,父模板(xxx.html
)中使用形如{% block block_name %}...{% endblock %}
来定义一个“块”,子模板(当前模板)如果想要重写这个block
中的内容,直接在子模板中重写这个block
即可,子模板中的相同block
名称的block
内容会覆盖父模板中同名的block
,如果不想覆盖父模板中此block
的内容,又想在此父block
中添加一些新内容,可以使用{{ block.super }}
引用父模板中此block
的所有内容。
如果模板使用了extends
标签,而子模板中的内容没有写在block
块中,那么在block
之外的代码就会被忽略(无效代码),所以子模板中的内容都必须要先在父模板中使用block
进行占位,再在子模板中进行重写。
注:传入子模板中的变量是可以直接在父模板中使用的。
五、静态文件加载
静态文件的加载可以使用全路径名,即相对于项目根目录的路径名,但是在DTL模板中也可以使用static
标签,感兴趣可以看下,以下是使用方法和注意事项:
- 因为
static
标签并不是Django内置的标签,所以每次使用时都需要先{% load static %}
,为了解决这个问题,可以在settings.py
中的TEMPLATES
的OPTIONS
字典中添加"builtins": ["django.templatetags.static"]
,这样static
标签就可以像Django内置标签一样直接使用了。 - 确保
django.contrib.staticfiles
已经被添加到settings.py
中的配置项INSTALLED_APPS
中了。(默认是已经添加了的) - 确保在
settings.py
中配置了STATIC_URL
配置项,此配置项用于设置静态文件的自动查找路径,默认为/static/
。(默认已经配置了的) - 将对应子app添加到
settings.py
中的配置项INSTALLED_APPS
中,并在子app目录下创建static
文件夹。 - 使用形如
<img src="{% static "logo.jpg" %}" alt="">
访问某个静态文件,此静态文件路径是相对于子app下的static
文件夹的相对路径。 - 如果需要放置一些整个项目都通用的静态文件(通常都需要),也可以在项目根目录下创建一个
static
文件夹,然后在settings.py
文件中配置STATICFILES_DIRS
配置项(列表)中将这个static
文件夹的路径添加进去即可(可以参考模板templates
文件夹的配置方法)。如此的话,Django在各个子app下都查找不到对应的静态文件的话,就会在这个目录下去查找。