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 模板访问变量

如果传给变量的不是一个字符串,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})

浏览器访问结果如下

Django 模板对象变量


过滤器

通过使用过滤器,我们可以对模板中的变量的值进行修改。格式 {{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"})

Django 模板变量过滤器字符串大写

截断字符串

下面这个例子将迹忆客网址 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!"})

Django 过滤器截断单词

注意,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>

Django 模板条件语句

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>

访问结果如下

Django 模板for循环


块标记和继承标记

对于一个模板系统,如果没有模板继承的功能,那么这个模板系统是不玩这个的。因此我们在设计模板的时候,应该首先新建一个带有许多 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进行了一下修改。访问结果如下

Django 模板继承

通过上面的例子我们看到,在 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块儿。但是子模板中并没有定义相对应的块儿内容。访问结果如下

Django 模板未对应块儿处理

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 模板注释

我们可以看到,Django 模板中的注释并没有显示在浏览器查看的源码中,相反HTML中的注释是显示在前端的。因此,我们在开发过程中尽量使用 Django 模板引擎中的注释方式,在一定程度上可以节流。

查看笔记

扫码一下
查看教程更方便