Django 模板
Django 实现了 python 和 HTML 分离的功能,python 控制视图,HTML 作为单纯的模板。为了将两者联系起来,Django 依赖于 render
函数和 Django 模板语言。在视图一节中,我们初步接触了模板。本节我们详细说一说模板的使用。
首先我们来看一下 render 函数的语法
render(request, templatePath, Params)
这个函数需要三个参数 -
- request - 初始请求。
- 模板路径- 这是相对于项目 settings.py 变量中的 TEMPLATE_DIRS 选项的路径。
- 参数字典 - 包含模板中所需的所有变量的字典。可以创建此变量,也可以使用 locals() 传递视图中声明的所有局部变量。
Django 模板语言 (DTL)
Django 的模板引擎提供了一种迷你语言来定义应用程序的面向用户的层。
显示变量
在模板中使用{{variable}}
这种形式定义一个变量。模板使用 render 函数的第三个参数中将变量替换为视图传递的变量值。让我们举个例子看一下
首先在 app 中新建一个 templates文件夹用来存放模板文件。然后新建一个 template.html 模板文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django - 迹忆客</title>
</head>
<body>
<p>欢迎访问 {{webname}}! </p>
</body>
</html>
然后我们新建一个视图 template
from django.shortcuts import render
from django.http import HttpResponse
def template(request):
return render(request, "tempate.html", {"webname": "迹忆客"})
这里模板的路径需要在 settings.py 配置中进行配置,或者也可以在视图中定义绝对路径。这里我们选择在配置文件中配置模板存放路径
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "app/templates")],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
上面的 DIRS 元组中定义的是模板的路径。
最后再定义一个路由
from django.urls import path, re_path
from . import views
urlpatterns = [
path('hello/', views.hello),
path('visit/', views.visit),
re_path(r'article/(\w+)', views.article),
re_path(r'articles/(?P<month>\d{2})/(?P<year>\d{4})', views.articles),
path('template/', views.template)
]
重启服务,浏览器访问 /app/template 结果如下
如果传给变量的不是一个字符串,Django 模板引擎将使用 __str__
函数强制转换成字符串进行显示。除此之外,视图中的变量也可以是一个和Python中一样的数据类型,访问方式也是一样的。例如传给视图一个对象,则可以使用 {{object.property}} 的方式访问对象的属性。 我们改造一下上面的视图和模板
修改模板文件 template.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Django - 迹忆客</title>
</head>
<body>
<h2>欢迎访问 {{webname}} ! </h2>
<p>今天是 {{today.month}}月{{today.day}}号</p>
</body>
</html>
修改视图 template
def template(request):
today = datetime.datetime.now().date()
return render(request, "template.html", {"webname": "迹忆客", "today": today})
浏览器访问结果如下
过滤器
通过使用过滤器,我们可以对模板中的变量的值进行修改。格式 {{var|filter}}
。 其中 filter 可以是一些python系统函数及其对应的参数。例如
- {{string|truncatewords:5}} - 此过滤器将截断字符串,因此您只会看到前 5 个单词。
- {{string|lower}} - 将字符串转换为小写。
下面我们通过实际例子来加深印象
将字符串转换为大写
下面这个例子,将迹忆客的网址 jiyik.com 转换为大写显示
修改模板文件 template.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Django - 迹忆客</title>
</head>
<body>
<h2>欢迎访问 {{webname}} ! </h2>
<h3>迹忆客网址:{{website|upper}}</h3>
<p>今天是 {{today.month}}月{{today.day}}号</p>
</body>
</html>
修改视图
def template(request):
today = datetime.datetime.now().date()
return render(request, "template.html", {"webname": "迹忆客", "today": today, "website": "jiyik.com"})
截断字符串
下面这个例子将迹忆客网址 jiyik.com 截出前5个字符显示
修改模板文件 template.html
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Django - 迹忆客</title>
</head>
<body>
<h2>欢迎访问 {{webname}} ! </h2>
<h3>迹忆客网址:{{website|upper}}</h3>
<h4>截取字符串为:{{str|truncatewords:2}}</h4>
<p>今天是 {{today.month}}月{{today.day}}号</p>
</body>
</html>
视图 template
def template(request):
today = datetime.datetime.now().date()
return render(request, "template.html",
{"webname": "迹忆客", "today": today, "website": "jiyik.com", "str": "That is wonderful!"})
注意,truncatewords 后面指定的数字 表示的是截取几个单词,而不是字符。 所以上面的例子显示的是 That is 而不是 Th。
标签
在 Django 模板中也支持很多的标签: if 条件、for 循环、模板继承等
if 条件
和使用 Python写代码一样,在模板中也可以使用 if、else 和 elif。
修改 template.html 模板文件
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Django - 迹忆客</title>
</head>
<body>
<h2>欢迎访问 {{webname}} ! </h2>
<h3>迹忆客网址:{{website|upper}}</h3>
<p>今天是 {{today.month}}月{{today.day}}号</p>
<p>
{% if today.day == 1 %}
今天是本月的第一天
{% elif today.day == 30 %}
今天是本月的最后一天
{% else %}
今天学习 Django
{% endif %}
</p>
</body>
</html>
for 循环
除了可以使用if条件语句之外,还支持 for循环。使用方式就和在Python中一样。
首先我们修改 template 视图
def template(request):
today = datetime.datetime.now().date()
daysOfWeek = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
return render(request, "template.html",
{"webname": "迹忆客", "today": today, "days_of_week" : daysOfWeek, "website": "jiyik.com", "str": "That is wonderful!"})
然后是用 {%for%} 标签显示模板
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Django - 迹忆客</title>
</head>
<body>
<h2>欢迎访问 {{webname}} ! </h2>
<h3>迹忆客网址:{{website|upper}}</h3>
<p>今天是 {{today.month}}月{{today.day}}号</p>
<p>
{% if today.day == 1 %}
今天是本月的第一天
{% elif today.day == 30 %}
今天是本月的最后一天
{% else %}
今天学习 Django
{% endif %}
</p>
<p>
{% for day in days_of_week %}
{{day}}
{% endfor %}
</p>
</body>
</html>
访问结果如下
块标记和继承标记
对于一个模板系统,如果没有模板继承的功能,那么这个模板系统是不玩这个的。因此我们在设计模板的时候,应该首先新建一个带有许多 block 块儿的主模板。然后再定义一些子模板,这些子模板去填充主模板中的block块儿。就像页面可能需要为所选选项卡添加特殊的 css样式 一样。
让我们来改造一下之前的template.html模板。 我们让其作为一个子模板,继承一个 主模板,这里我们将主模板新建为 main_template.html,其内容如下
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>
{% block title %}Page Title{% endblock %}
</title>
</head>
<body>
{% block content %}
Body content
{% endblock %}
</body>
</html>
然后修改模板文件 template.html
{% extends "main_template.html" %}
{% block title %}Django 继承主模板 - 迹忆客{% endblock %}
{% block content %}
<h2>欢迎访问 {{webname}} ! </h2>
<h3>迹忆客网址:{{website|upper}}</h3>
<p>今天是 {{today.month}}月{{today.day}}号</p>
<p>
{% if today.day == 1 %}
今天是本月的第一天
{% elif today.day == 30 %}
今天是本月的最后一天
{% else %}
今天学习 Django
{% endif %}
</p>
<p>
{% for day in days_of_week %}
{{day}}
{% endfor %}
</p>
{% endblock %}
为了区分,这里我们对title进行了一下修改。访问结果如下
通过上面的例子我们看到,在 template.html 中使用 {%extends%} 标签继承了主模板 main_template.html。然后 在子模板中定义的块 {% block title %} 和 {% block content %} 分别回去替换主模板中的相对应的块儿,这是根据 block 后面跟着的名称来判断的。子模板中的title去对应主模板中的title,content 去对应 content。
那么,如果说在子模板 template.html 中定义了一个块儿,而在主模板中没有对应的块儿怎么办。此时Django 模板引擎就会忽略子模板中的块儿,不会将其渲染出来。例如子模板中的代码如下
{% extends "main_template.html" %}
{% block title %}Django 继承主模板 - 迹忆客{% endblock %}
{% block content %}
<h2>欢迎访问 {{webname}} ! </h2>
<h3>迹忆客网址:{{website|upper}}</h3>
<p>今天是 {{today.month}}月{{today.day}}号</p>
<p>
{% if today.day == 1 %}
今天是本月的第一天
{% elif today.day == 30 %}
今天是本月的最后一天
{% else %}
今天学习 Django
{% endif %}
</p>
<p>
{% for day in days_of_week %}
{{day}}
{% endfor %}
</p>
{% endblock %}
{% block otherContent %}
<h2>这是另一个块</h2>
{% endblock %}
我们定义了一个 otherContent块儿,因为在主模板中没有对应的占位块。所以这也就被模板引擎忽略了。 访问结果没有任何变化
那反过来,在主模板中定义了一个占位块,但是在子模板中没有相对应的块儿,那结果有点儿不一样。Django 模板引擎会将该块儿的内容渲染出来。例如我们的主模板定义如下
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>
{% block title %}Page Title{% endblock %}
</title>
</head>
<body>
{% block content %}
Body content
{% endblock %}
{% block leftContent %}
LeftContent Block
{% endblock %}
</body>
</html>
这里在主模板中定义了一个 leftContent块儿。但是子模板中并没有定义相对应的块儿内容。访问结果如下
Comment 标记
Comment 标记起注释的作用。和HTML的注释不同,它们不会出现在 HTML 页面中。它可用于文档或仅注释一行代码。虽然 HTML 的注释也不会在页面上显示,但是查看源码的时候还是能查看到的,在访问的时候也是在一定程度上占用了流量的。
例如,template.html 模板引擎修改如下
{% extends "main_template.html" %}
{% block title %}Django 继承主模板 - 迹忆客{% endblock %}
{% block content %}
<h2>欢迎访问 {{webname}} ! </h2>
<h3>迹忆客网址:{{website|upper}}</h3>
<p>今天是 {{today.month}}月{{today.day}}号</p>
<p>
{% if today.day == 1 %}
今天是本月的第一天
{% elif today.day == 30 %}
今天是本月的最后一天
{% else %}
今天学习 Django
{% endif %}
</p>
<p>
{% for day in days_of_week %}
{{day}}
{% endfor %}
{% comment %} 这是 Django 模板引擎中的注释 {% endcomment %}
<!-- 这是html注释 -->
</p>
{% endblock %}
在浏览器中访问查看源码结果如下
我们可以看到,Django 模板中的注释并没有显示在浏览器查看的源码中,相反HTML中的注释是显示在前端的。因此,我们在开发过程中尽量使用 Django 模板引擎中的注释方式,在一定程度上可以节流。