Django笔记:DTL模板

众所周知,Django采用的是MTV框架模式,本文介绍的就是其中的T(Template模板)。对于模板引擎,比较有名的有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,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,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下都查找不到对应的静态文件的话,就会在这个目录下去查找。

相关文章

1. General Supported Versions 2. Settings STATIC_URL MED...
问题01:Django枚举类型扩展方法(Model.get_FOO_display()) ...
verbose_name 可以作为第一个参数传入,使书写更加工整和有序...
# use_2to3 is invalid&#xA;# Django枚举类型扩展方法&a...
一、层次结构 GenericViewSet(ViewSetMixin, generics.Gener...