『Django』模板

本文简介

点赞 + 关注 + 收藏 = 学会了

上一篇文章介绍了 Django 视图的基础用法,当时提到了"响应HTML模版",用到的方式是渲染一段 HTML 内容的字符串,这种方式很不方便。更方便的方法是在 .html 文件里写页面内容,然后渲染这个 .html 文件。这个 .html 文件也叫 HTML 模版,就是本文要讲解的内容。

什么是模板?

简单来说,在 Django 的模板就是一个"升级版"的 HTML 文件。

我们使用 VueReact 这些流行的前端框架时也会用到模板,它们的用法其实和 Django 里的模板用法也很像。

举个例子。

html 复制代码
<div>{{ msg }}</div>

在这段 HTML 代码中有一串 {{ msg }} 这样的代码,这是 Django 模板的语法,它能将 msg 这个变量的值加载到 <div> 标签里。

这种模版最大的好处就是复用。想象一下,你有一个网站,需要在每个页面上显示相同的信息,比如标题、导航栏和页脚。模板就是用来帮你做这些的,它们让你可以创建一个模板文件,里面包含网站的基本布局和内容,然后在每个页面中使用这个模板来展示你的信息。这样,你就不必每次都重新写一遍相同的代码,而是可以简单地重复使用模板,节省时间和精力。

Django 提供了2个模板引擎分别是 DTL (Django Template Language) 和 Jinja2。同时 Django 还支持使用第三方模板,但这不是本文要讲的内容。本文主要介绍 DTL。

当然啦,现在还流行前后端分离,工作中可能用到后端模板的机会变少了。但如果你想自己搞点产品出来,又懒得前后端分离,后端模板还是一个不错的选择。现在有些企业官网也仍然使用后端模板来编写的。

配置模板

使用 Django 模板之前,需要配置一下模版的路径(位置)。

通常会在项目根目录创建一个 templates 文件夹用来存放模版(.html文件),然后在项目配置文件 settings.py 里指定 templates 文件夹的路径。

settings.py 里的 TEMPLATES 里第一个元素的 DIRS 字段配置一下 'templates',这样就指定了模版路径为项目根目录下的 templates 了。

APP_DIRS 这个字段也设置为 True ,这样就允许在应用中配置模版。如果忘了什么是"应用"可以回顾一下 《『Django』创建app(应用程序)》

模板的基础用法

全局模板

配置好模板路径就可以使用模板了。

首先在 templates 目录里创建 blog.html 文件,内容如下:

html 复制代码
<!-- blog.html -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>博客</title>
</head>
<body>
  <div>雷猴,这是博客首页~</div>
</body>
</html>

然后在项目的 urls.py 配置路由。

python 复制代码
# urls.py

from django.urls import path
from blog.views import blogIndex

urlpatterns = [
    path("blog/", blogIndex)
]

接着在blog应用里使用这个模板。

python 复制代码
# blog/views.py

from django.http import HttpResponse
from django.shortcuts import render

def blogIndex(request):
  return render(request, 'blog.html')

最后运行以下命令,并在浏览器 http://127.0.0.1:8000/blog/

bash 复制代码
python3 manage.py runserver

注意看,在 blog/views.py 是直接使用 return render(request, 'blog.html') ,直接使用模板的,并没有引入它的代码。这是因为在 settings.py 里配置过模板的路径,所以直接使用模板时会先在配置好的路径里找。

还有还有,在视图 views.py 里使用 render 方法,它可以直接渲染 html 文件。

应用模板

删掉项目里的 templates 文件夹。

然后在 settings.py 中,把 TEMPLATES 里的 APP_DIRS 设置为 True 后,再在 blog 应用中创建 templates 文件夹,里面放入 blog.html 文件,内容如下:

html 复制代码
<!-- blog/templates/blog.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>博客</title>
</head>
<body>
  <div>雷猴,这是blo应用内的博客页面~~~</div>
</body>
</html>

为了和前面的"全局模板"的内容区分一下,这个文件的内容稍微有点不同。

接着在浏览器访问 http://127.0.0.1:8000/blog/ 会发现报错了。

如果需要使用应用内的模板还需要多配置一项。

在项目配置文件 settings.pyINSTALLED_APPS 里加上你的应用名。

python 复制代码
# 省略部分代码

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "blog"
]

这里我把 blog 这个应用加上了。接着重新打开 http://127.0.0.1:8000/blog/ 就能看到应用内的模板内容了。

语法

Django 支持在模板中插入变量,支持使用条件判断、循环等功能。接下来介绍一些常用的模板能力。

标签

Django 模板的标签是一种特殊的语法,用于在模板中执行逻辑操作和控制模板的渲染行为。这些标签由一对花括号 {{ }} 或百分号 {% %} 包裹,以便与模板中的普通文本区分开来。

主要有两种类型的 Django 模板标签:

  1. 变量标签 :用双花括号 {{ }} 包裹,用于在模板中输出变量的值,例如 {{ variable }}
  2. 控制标签 :用百分号 {% %} 包裹,用于执行逻辑操作,如循环、条件判断等,例如 {% if condition %} ... {% endif %}。有些控制标签由"开始标签"和"结束标签"组合而成。

接下来逐一讲解。

变量

首先要介绍的是变量。在模板中变量需要使用两对花括号 {{}} 包裹起来。

基本语法:

html 复制代码
{{ 变量名 }}

Django 模板变量的用法和 Vue 是一样的。

那这个变量是从哪里传过来的呢?

通常流程是在视图 views.py 把处理好的数据传入模板里。

举个例子:

python 复制代码
# blog/views.py

from django.http import HttpResponse
from django.shortcuts import render

def blogIndex(request):
  msg = '雷猴'
  return render(
    request,
    'blog.html',
    {
    	"msg": msg
  	}
  )

然后在模板中直接使用:

html 复制代码
<!-- blog/templates/blog.html -->
<!-- 省略部分代码 -->

<body>
  <div>{{ msg }}</div>
</body>

打开 http://127.0.0.1:8000/blog/ 瞧瞧

条件判断 if

条件判断是一种常用的操作,用于根据特定条件的真假来决定模板中的内容渲染方式。Django 模板提供了 {% if %}{% endif %} 标签来实现条件判断。

需要注意,结尾必须用 {% endif %} 表示条件判断结束了。

当有多个条件判断时,可以使用 {% if %} 标签配合 {% elif %}{% else %} 标签。这样可以在多个条件之间进行逐一检查,直到找到第一个满足条件的分支。

基本语法:

html 复制代码
{% if condition1 %}
    ...  # 条件1成立时执行的内容
{% elif condition2 %}
    ...  # 条件1不成立,条件2成立时执行的内容
{% elif condition3 %}
    ...  # 条件1和条件2都不成立,条件3成立时执行的内容
{% else %}
    ...  # 所有条件都不成立时执行的内容
{% endif %}

举个例子,将文章可见性的数值转换成中文。

在视图里设定一个文章可见性的变量 visibility,将它传给模版。因为本文主要介绍模版的用法

python 复制代码
# blog/views.py

def blogIndex(request):
  visibility = 2

  return render(request, 'blog.html', {
    "visibility": visibility
  })

在模板中接收

html 复制代码
<!-- blog/templates/blog.html -->

<div>
  {% if visibility == 0 %}
  <div>仅自己可见</div>
  {% elif visibility == 1 %}
  <div>VIP用户可见</div>
  {% elif visibility == 2 %}
  <div>粉丝可见</div>
  {% else %}
  <div>无限制</div>
  {% endif %}
</div>

在浏览器打开 http://127.0.0.1:8000/blog/

循环渲染 for

当需要渲染一个列表时,可以使用 for 循环将其输出到页面中。

基本语法:

html 复制代码
{% for item in list %}
    ...  # 渲染每个元素的内容
{% endfor %}

举个例子,我要将我所有专栏的名称都渲染出来。

python 复制代码
# blog/views.py

def blogIndex(request):
  list = [
    '写给前端的Django教程',
    'AIGC',
    '读书破万卷',
    'Python',
    '产品汪',
    '乱up24',
    '新手村',
    '艺术系必修课:P5.js',
    'SVG',
    'canvas',
    'Three.js',
    '零基础入门Fabric.js,提高Canvas开发效率',
    '数据可视化'
  ]

  return render(request, 'blog.html', {
    "list": list
  })

在模版中遍历出来。

html 复制代码
<!-- blog/templates/blog.html -->

<ul>
  {% for item in list %}
  <li>{{ item }}</li>
  {% endfor %}
</ul>

循环使用一组值 cycle

关于循环,Django 模板还提供了一个叫 cycle 的功能。

在前端,热门的UI框架的表格组件一般都提供"斑马纹"的样式,比如奇数行使用白色背景,偶数行使用浅灰色背景。

Django 模板的 cycle 可以很方便的实现这个功能。

基本语法:

html 复制代码
{% cycle 'value1' 'value2' ... as cycle_name %}

举个简单的例子(为了方便,这里使用 ul 而不是 table)。

python 复制代码
# blog/views.py

def blogIndex(request):
  list = [
    '写给前端的Django教程',
    'AIGC',
    '读书破万卷',
    'Python',
    '产品汪',
    '乱up24',
    '新手村',
    '艺术系必修课:P5.js',
    'SVG',
    'canvas',
    'Three.js',
    '零基础入门Fabric.js,提高Canvas开发效率',
    '数据可视化'
  ]

  return render(request, 'blog.html', {
    "list": list
  })

模版代码:

html 复制代码
<!-- blog/templates/blog.html -->

<style>
  .row1 {
    background: white;
  }
  .row2 {
    background: gainsboro;
  }
</style>

<ul>
  {% for item in list %}
  <li class="{% cycle 'row1' 'row2' %}">{{ item }}</li>
  {% endfor %}
</ul>

自动转义 autoescape

Django 默认会将 HTML 代码进行转义。自动转义功能可以确保在渲染模板时,将 HTML 标签和特殊字符(如 <, >, &, ', " 等)转义为相应的HTML实体(如 <, >, &, ', "),从而避免用户提供的数据被误解释为 HTML 标签或 JavaScript 代码,导致安全漏洞,以防止跨站点脚本攻击(XSS)。

比如,我想在页面输出一个超链接,使用 <a> 标签来实现。

python 复制代码
# blog/views.py

def blogIndex(request):
  django_column = '<a href="https://juejin.cn/column/7355677638881706019">写给前端的Django教程</a>'

  return render(request, 'blog.html', {
    "django_column": django_column
  })

在模板中渲染出来。

html 复制代码
<!-- blog/templates/blog.html -->
<div>
  {{ django_column }}
</div>

出来的效果是这样的,明显不是我想要的。

如果此时想将 <a> 标签这段字符串转换成 HTML 元素来渲染,而不是输出字符串的话,可以使用 autoescape

基本语法:

python 复制代码
{% autoescape on %}
    <p>{{ user_input }}</p>  <!-- user_input会被自动转义 -->
{% endautoescape %}

{% autoescape off %}
    <p>{{ user_input }}</p>  <!-- user_input不会被自动转义 -->
{% endautoescape %}

注意,在开始的 autoescape 后面会跟上 on 或者 off,默认值是 on ,也就是说你不写 {% autoescape on %} 这段,默认情况也会按 {% autoescape on %} 来渲染。

  • on:表示自动转义
  • off:表示不自动转义

此时我想将 '<a href="https://juejin.cn/column/7355677638881706019">写给前端的Django教程</a>' 这段字符串渲染成 HTML 元素,就要将 autoescape 设置为 off

html 复制代码
<!-- blog/templates/blog.html -->

<div>
  {% autoescape off %}
  {{ django_column }}
  {% endautoescape %}
</div>

过滤器

过滤器可以让你在模板中对数据进行转换和修改, Django 的过滤器语法和 Vue 2 的过滤器语法一样。

基本语法:

html 复制代码
{{ 变量 | 过滤器名称 }}

常用的过滤器有以下这些(为了方便演示,下面的例子不再罗列视图的代码)。

转大/小写:upper / lower

使用 upper 可以将英文字母都转成大写,用 lower 可以转成小写。但这两个过滤器都无法处理中文。

视图传来的值:msg = 'Abc'

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ msg | upper }}</div>
<div>{{ msg | lower }}</div>

字符串转slug格式:slugify

slug 过滤器可以将"Hello World"变成"hello-world",但它无法处理中文。

视图传来的值:msg = 'Hello World'

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ msg | slug }}</div>

默认值:default

当视图传过来的值是空,那就使用默认值。

视图传来的值:gender = ''

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ gender | default:'未知' }}</div>

字符串长度:length

返回字符串的长度。

视图传来的值:msg = '雷猴'

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ msg | length }}</div>

字符串删除指定字符:cut

将指定的字符串删除掉,比如这个例子中要删除所有 txt

视图传来的值:msg = 'txt雷猴txt'

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ msg | cut:"txt" }}</div>

超出长度用省略号表示:truncatechars

将超出指定数量的字符串用省略号表示。比如限制了输出10个字符,后面的都用省略号表示。

视图传来的值:msg = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ msg | truncatechars:10 }}</div>

列表转字符串:join

将列表转换为指定内容分隔的字符串。例如,我想让列表转换成使用 -/- 这3个字符串分割的字符串。

视图传来的值:list = ['雷猴', '鲨鱼辣椒', '蝎子莱莱', '蟑螂恶霸']

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ list | join:"-/-" }}</div>

返回列表中的第一个或最后一个元素: firstlast

视图传来的值:list = ['雷猴', '鲨鱼辣椒', '蝎子莱莱', '蟑螂恶霸']

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ list | first }}</div>
<div>{{ list | last }}</div>

格式化浮点数:floatformat

让浮点数保留多少位小数,可以用 floatformat 过滤器来过滤,它会四舍五入保留指定位小数。

视图传来的值:num = 12.009

html 复制代码
<!-- blog/templates/blog.html -->

<div>{{ num | floatformat:"2" }}</div>

注释

注释分单行注释和多行注释。

单行注释:

html 复制代码
{# 这里是被注释的内容 #}

多行注释:

html 复制代码
{% comment %}
这里面的内容都会被注释掉
这里面的内容都会被注释掉
这里面的内容都会被注释掉
{% endcomment %}

多行注释需要使用 comment 来实现。

加载静态资源

这里指的静态资源文件包括图片、css文件、js文件等。

当我们想将公共的样式写在一个 css 文件里,或者有一些公共的 js 方法要单独放在一个 js 文件里,又或者要在页面加载一张存放在项目里的图片时,可以用以下方法配置。

首先在项目根目录中创建一个 static 文件夹,然后把静态资源放进去。

然后在项目配置文件 settings.py 里配置静态资源路径。

python 复制代码
# demo1/settings.py
import os

STATIC_URL = 'static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static')
]

STATIC_URL是一个Django设置,用于指定在模板中引用静态文件时的基础URL。

STATICFILES_DIRS 用于指定额外的静态文件目录,所以要引入 os 模块。

然后在 html 中,需要在页面第一行写上 {% load static %},作用是用于加载静态文件模板标签库。加载静态文件模板标签库后,模板就可以使用静态文件相关的模板标签,例如{% static %}标签。

比如我要在页面中引入 static/images/raccoon.jpg 这张图片。

html 复制代码
<!-- blog/templates/blog.html -->

{% load static %}
<img src="{% static '/images/raccoon.jpg' %}" alt="">

要引入 cssjs 也同理,settings.py 文件的配置跟前面配置的一样。

html 复制代码
{% load static %}

<head>
  <link rel="stylesheet" href="{% static '/css/style.css' %}">
</head>

模板继承

对于相同的内容,我们就可以使用一个父模版,然后中间不同的地方用相应的内容进行替换。

举个例子,我在 blog 应用的 templates 里创建一个 base.html 文件,里面包含页头和页脚内容。

html 复制代码
<!-- blog/templates/base.html -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <!-- 这是基础模版(父模版) -->

  <header>这是页头</header>

  <!-- 这里使用block占位符接收不同的内容 -->
  <!-- 标签都是一组的,有block就有endblock -->
  <!-- 这个占位符的名字叫 content -->
  {% block content %}
  {% endblock %}
  <footer>这是页脚</footer>
</body>
</html>

上面的代码中有 {% block content %}{% endblock %} ,占位符的意思,而且这个占位符的名字叫 content

然后在 blog.html 里引入这个父模板,把内容插入到 content 位置里。

html 复制代码
<!-- blog/templates/blog.html -->

{% extends 'base.html' %}
<!-- 继承模版 -->
{% block content %}
<h1>雷猴雷猴</h1>
{% endblock %}

这代码第一行 {% extends 'base.html' %} 表示引入 base.html 文件,这里需要写入 base.html 文件地址,因为我把 base.htmlblog.html 放在同一个目录下,所以可以这样直接引入。

然后使用 {% extends 'base.html' %} 表示从这里开始使用 base.html 模板,在 {% block content %}{% endblock %} 之间插入自定义内容即可。

模板包含

包含的意思可以理解为前端的组建,写好的组件可以在不同地方重复调用。

比如我创建一个 com.html 文件,这个文件就是可复用组件。

html 复制代码
<!-- blog/templates/com.html -->

<!-- 可复用组件 -->
<div>这是一个可复用组件啊啊啊啊啊</div>

然后在需要用到的地方使用它。

html 复制代码
<!-- blog/templates/blog.html -->

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>引入可复用组件</title>
</head>
<body>
  {% include 'com.html' %}
  {% include 'com.html' %}
  {% include 'com.html' %}
  {% include 'com.html' %}
</body>
</html>

点赞 + 关注 + 收藏 = 学会了

相关推荐
爱喝白开水a3 分钟前
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板_langchain prompt
开发语言·数据库·人工智能·python·langchain·prompt·知识图谱
间彧1 小时前
Windows Server,如何使用WSFC+nginx实现集群故障转移
后端
间彧1 小时前
Nginx + Keepalived 实现高可用集群(Linux下)
后端
间彧1 小时前
在Kubernetes中如何部署高可用的Nginx Ingress Controller?
后端
间彧1 小时前
Ribbon负载均衡器和Nginx负载均衡器有什么区别
后端
间彧1 小时前
Nacos详解与项目实战
后端
间彧1 小时前
nginx、网关Gateway、Nacos、多个服务实例之间的数据链路详解
后端
间彧1 小时前
Nacos与Eureka在性能上有哪些具体差异?
后端
间彧1 小时前
详解Nacos健康状态监测机制
后端
间彧1 小时前
如何利用Nacos实现配置的灰度发布?
后端