DTL模板

内容摘要
对于模板引擎,比较有名的有DTL和Jinja2等,Django使用的则是DTL(Django Template Language),虽然也可以配置Django项目使用别的模板引擎,但是推荐使用Django自带的DTL。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语句,有对应的elifelse语句,同样也可以使用==, !=, <, <=, >, >=, 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标签是没有continuebreak语句的。
示例:正序遍历

<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>

示例:遍历字典,可以使用字典对应的keysvaluesitems等方法,但是注意方法名后面没有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.revcounterforloop.counter的反向下标。
  • forloop.revcounter0forloop.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语法中的字符表示,如将<转义为&lt;等,这意味着,字符串中的这些字符不会当成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标签。

自定义模板过滤器

模板过滤器其实就是一个普通的函数,自定义过滤器注意事项和步骤如下:

  1. 在子app目录下新建一个templatetags包,注意,这个包名只能是这个名称,不能随便进行自定义,不然Django无法识别。
  2. 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)
  1. 将子app添加到settings.py中的配置项INSTALLED_APPS
  2. 在模板中使用自定义过滤器时,需要先在模板开头添加如{% 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标签,感兴趣可以看下,以下是使用方法和注意事项:

  1. 因为static标签并不是Django内置的标签,所以每次使用时都需要先{% load static %},为了解决这个问题,可以在settings.py中的TEMPLATESOPTIONS字典中添加"builtins": ["django.templatetags.static"],这样static标签就可以像Django内置标签一样直接使用了。
  2. 确保django.contrib.staticfiles已经被添加到settings.py中的配置项INSTALLED_APPS中了。(默认是已经添加了的)
  3. 确保在settings.py中配置了STATIC_URL配置项,此配置项用于设置静态文件的自动查找路径,默认为/static/。(默认已经配置了的)
  4. 将对应子app添加到settings.py中的配置项INSTALLED_APPS中,并在子app目录下创建static文件夹。
  5. 使用形如<img src="{% static "logo.jpg" %}" alt="">访问某个静态文件,此静态文件路径是相对于子app下的static文件夹的相对路径。
  6. 如果需要放置一些整个项目都通用的静态文件(通常都需要),也可以在项目根目录下创建一个static文件夹,然后在settings.py文件中配置STATICFILES_DIRS配置项(列表)中将这个static文件夹的路径添加进去即可(可以参考模板templates文件夹的配置方法)。如此的话,Django在各个子app下都查找不到对应的静态文件的话,就会在这个目录下去查找。
代码注释
[!--zhushi--]

作者:喵哥笔记

IDC笔记

学的不仅是技术,更是梦想!