『Django』模板

本文简介

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

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

什么是模板?

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

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

举个例子。

<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 文件,内容如下:

<!-- 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 配置路由。

# urls.py

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

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

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

# 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/

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 文件,内容如下:

<!-- 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 里加上你的应用名。

# 省略部分代码

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 %}。有些控制标签由“开始标签”和“结束标签”组合而成。

接下来逐一讲解。

变量

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

基本语法:

{{ 变量名 }}

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

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

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

举个例子:

# blog/views.py

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

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

然后在模板中直接使用:

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

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

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

条件判断 if

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

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

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

基本语法:

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

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

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

# blog/views.py

def blogIndex(request):
  visibility = 2

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

在模板中接收

<!-- 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 循环将其输出到页面中。

基本语法:

{% for item in list %}
    ...  # 渲染每个元素的内容
{% endfor %}

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

# 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
  })

在模版中遍历出来。

<!-- blog/templates/blog.html -->

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

循环使用一组值 cycle

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

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

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

基本语法:

{% cycle 'value1' 'value2' ... as cycle_name %}

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

# 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
  })

模版代码:

<!-- 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> 标签来实现。

# 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
  })

在模板中渲染出来。

<!-- blog/templates/blog.html -->
<div>
  {{ django_column }}
</div>

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

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

基本语法:

{% 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

<!-- blog/templates/blog.html -->

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

过滤器

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

基本语法:

{{ 变量 | 过滤器名称 }}

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

转大/小写:upper / lower

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

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

<!-- blog/templates/blog.html -->

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

字符串转slug格式:slugify

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

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

<!-- blog/templates/blog.html -->

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

默认值:default

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

视图传来的值:gender = ''

<!-- blog/templates/blog.html -->

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

字符串长度:length

返回字符串的长度。

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

<!-- blog/templates/blog.html -->

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

字符串删除指定字符:cut

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

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

<!-- blog/templates/blog.html -->

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

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

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

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

<!-- blog/templates/blog.html -->

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

列表转字符串:join

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

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

<!-- blog/templates/blog.html -->

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

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

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

<!-- blog/templates/blog.html -->

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

格式化浮点数:floatformat

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

视图传来的值:num = 12.009

<!-- blog/templates/blog.html -->

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

注释

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

单行注释:

{# 这里是被注释的内容 #}

多行注释:

{% comment %}
这里面的内容都会被注释掉
这里面的内容都会被注释掉
这里面的内容都会被注释掉
{% endcomment %}

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

加载静态资源

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

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

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

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

# 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 这张图片。

<!-- blog/templates/blog.html -->

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

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

{% load static %}

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

模板继承

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

举个例子,我在 blog 应用的 templates 里创建一个 base.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 位置里。

<!-- 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 文件,这个文件就是可复用组件。

<!-- blog/templates/com.html -->

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

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

<!-- 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>


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

posted @ 2024-11-14 09:08  德育处主任  阅读(1)  评论(0编辑  收藏  举报