第 68 课 - Django 模板系统
1. 学习目标
完成本课学习后,你将能够:
- 理解 Django 模板系统的工作原理和目的
- 掌握 模板变量的使用方法和常见的内置标签与过滤器
- 运用 模板继承(Template Inheritance)来构建可复用的页面结构
- 配置 并在视图中正确渲染模板
- 区分 模板中的静态文件引用与动态数据渲染
2. 核心概念
Django 模板系统是什么?
想象一下你要给 100 个朋友写节日贺卡,每张贺卡的内容 90% 都相同,只有姓名和祝福语不同。你会怎么做?最有效的方法是写一个"模板",把姓名和祝福语留空,然后填入不同内容即可。Django 的模板系统就是这个原理。
核心思想: 模板是一个文本文件(通常是 HTML),它定义了页面的结构和外观,其中包含一些特殊的"占位符"(模板变量和标签),这些占位符会在渲染时被真实的数据替换。
与直接在视图中拼接 HTML 相比,模板系统的优势:
- 分离关注点: 设计师可以专注于 HTML/CSS,程序员专注于 Python 逻辑
- 安全性: 自动对变量进行转义,防止 XSS 攻击
- 复用性: 通过模板继承,可以构建基底模板,避免代码重复
- 易维护: 修改页面结构只需改模板文件,无需动后端代码
3. 代码示例
1. 配置模板目录
首先,在项目根目录下创建一个 templates 文件夹。在 settings.py 中配置模板目录:
# settings.py
import os
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], # 指向项目根目录的templates文件夹
'APP_DIRS': True, # 也会在每个app的templates文件夹中查找
'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',
],
},
},
]
2. 创建一个基础模板 (base.html)
<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}我的网站{% endblock %}</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.navbar { background: #333; padding: 10px; color: white; }
.content { padding: 20px; }
.footer { margin-top: 40px; padding: 20px; background: #eee; }
</style>
</head>
<body>
<div class="navbar">
<a href="/" style="color: white; text-decoration: none;">首页</a>
</div>
<div class="content">
{% block content %}
<p>这里将被子模板覆盖</p>
{% endblock %}
</div>
<div class="footer">
<p>© 2023 我的网站</p>
</div>
</body>
</html>
3. 创建一个继承基础模板的子模板 (home.html)
<!-- templates/home.html -->
{% extends "base.html" %}
{% block title %}首页 - 我的网站{% endblock %}
{% block content %}
<h1>欢迎来到我的网站!</h1>
<p>当前时间:{{ current_time }}</p>
<p>访问次数:{{ visit_count }}</p>
<h2>用户列表</h2>
<ul>
{% for user in users %}
<li>{{ user.name }} - {{ user.email }}</li>
{% empty %}
<li>暂无用户</li>
{% endfor %}
</ul>
<p>{{ message|upper }}</p> <!-- 使用upper过滤器将文本转为大写 -->
{% endblock %}
4. 在视图中渲染模板
# views.py
from django.shortcuts import render
from django.utils import timezone
def home(request):
# 准备传递给模板的上下文数据
context = {
'current_time': timezone.now(),
'visit_count': 150,
'users': [
{'name': '张三', 'email': '[email protected]'},
{'name': '李四', 'email': '[email protected]'},
{'name': '王五', 'email': '[email protected]'},
],
'message': '这是来自视图的消息'
}
# 渲染模板并返回响应
return render(request, 'home.html', context)
5. 配置 URL 路由
# urls.py (项目级别)
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
]
4. 实践练习
练习 1:基础模板继承
创建一个新的 about.html 模板,它继承自 base.html:
- 修改页面标题为"关于我们"
- 在内容区域添加一段自我介绍的文字
- 预期效果:页面显示带有导航栏和页脚的关于我们页面
练习 2:模板标签与过滤器应用
创建一个 blog.html 模板,要求:
- 继承
base.html - 在视图中传递一个文章列表(每篇文章包含标题、作者、发布日期、正文)
- 在模板中循环显示所有文章
- 使用过滤器:
- 将作者名显示为大写
- 格式化日期为"年-月-日"格式
- 如果文章正文为空,显示"暂无内容"
- 使用
{% if %}标签,如果文章数量超过5篇,显示"加载更多"按钮
练习 3:模板继承实战
设计一个简单的网站布局:
- 基础模板包含:头部导航栏、侧边栏(占1/4宽度)、主内容区、底部版权信息
- 创建一个
products.html继承基础模板:- 左侧边栏显示产品分类
- 主内容区显示产品列表
- 创建一个
contact.html继承基础模板:- 左侧边栏显示联系方式
- 主内容区显示联系表单
预期效果: 两个页面保持相同的布局结构,但内容不同。
5. 常见错误
错误 1:模板文件找不到
# 错误信息:TemplateDoesNotExist
原因与解决:
- 检查
TEMPLATES设置中的DIRS配置是否正确 - 确保模板文件名拼写正确
- 如果使用
APP_DIRS: True,确保在 app 内创建了templates文件夹
错误 2:模板变量显示原始代码而不是渲染结果
<!-- 错误示例:{{ user.name }} 显示为 {{ user.name }} -->
原因与解决:
- 检查视图是否正确传递了上下文数据
- 确保变量名在模板中和视图中完全一致(区分大小写)
- 使用
print(context)调试视图中的上下文数据
错误 3:模板继承中块定义冲突
<!-- 子模板中的块名必须与父模板中定义的块名一致 -->
{% block content %} <!-- 必须与父模板中定义的块名完全相同 -->
错误 4:过度使用模板逻辑
<!-- 错误示例:在模板中写复杂的业务逻辑 -->
{% if user.is_authenticated and user.has_perm('blog.add_post') and not user.is_banned %}
<!-- 复杂条件判断应该放在视图中 -->
{% endif %}
解决: 将复杂的业务逻辑放在视图中处理,模板只负责展示
6. 小结
关键要点回顾:
-
模板系统的核心作用:实现业务逻辑与显示逻辑的分离,提高代码复用性和可维护性。
-
基本语法:
{{ variable }}:输出变量{% tag %}:模板标签{{ variable|filter }}:过滤器
-
模板继承:通过
{% extends %}和{% block %}实现,是构建复杂网站的关键技术。 -
常见内置标签:
{% if %}...{% endif %}- 条件判断{% for %}...{% endfor %}- 循环{% include %}- 包含其他模板
-
常见内置过滤器:
{{ text|upper }}- 转大写{{ value|default:"默认值" }}- 设置默认值{{ date|date:"Y-m-d" }}- 格式化日期
-
安全最佳实践:Django 默认对模板变量进行 HTML 转义,防止 XSS 攻击。如需显示原始 HTML,使用
{{ variable|safe }},但务必确保内容可信。
掌握 Django 模板系统后,你将能够高效地构建动态、可维护的 Web 页面。下一课我们将学习 Django 表单系统,它常与模板系统配合使用来处理用户输入。