Django笔记:DTL模板 - 山上下了雪-bky - 博客园

AllenQ 关注

收藏于 : 2021-11-25 17:55   被转藏 : 1   

众所周知,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 语句,有对应的 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语法中的字符表示,如将 < 转义为 &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 中的 TEMPLATES OPTIONS 字典中添加 '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下都查找不到对应的静态文件的话,就会在这个目录下去查找。
 阅读文章全部内容  
点击查看
文章点评
相关文章
AllenQ 关注

文章收藏:36

TA的最新收藏