68·模块十三:Web开发基础进阶

Django 模板系统

djangotemplates

第 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>&copy; 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 模板,要求:

  1. 继承 base.html
  2. 在视图中传递一个文章列表(每篇文章包含标题、作者、发布日期、正文)
  3. 在模板中循环显示所有文章
  4. 使用过滤器:
    • 将作者名显示为大写
    • 格式化日期为"年-月-日"格式
    • 如果文章正文为空,显示"暂无内容"
  5. 使用 {% if %} 标签,如果文章数量超过5篇,显示"加载更多"按钮

练习 3:模板继承实战

设计一个简单的网站布局:

  1. 基础模板包含:头部导航栏、侧边栏(占1/4宽度)、主内容区、底部版权信息
  2. 创建一个 products.html 继承基础模板:
    • 左侧边栏显示产品分类
    • 主内容区显示产品列表
  3. 创建一个 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. 小结

关键要点回顾:

  1. 模板系统的核心作用:实现业务逻辑与显示逻辑的分离,提高代码复用性和可维护性。

  2. 基本语法

    • {{ variable }}:输出变量
    • {% tag %}:模板标签
    • {{ variable|filter }}:过滤器
  3. 模板继承:通过 {% extends %}{% block %} 实现,是构建复杂网站的关键技术。

  4. 常见内置标签

    • {% if %}...{% endif %} - 条件判断
    • {% for %}...{% endfor %} - 循环
    • {% include %} - 包含其他模板
  5. 常见内置过滤器

    • {{ text|upper }} - 转大写
    • {{ value|default:"默认值" }} - 设置默认值
    • {{ date|date:"Y-m-d" }} - 格式化日期
  6. 安全最佳实践:Django 默认对模板变量进行 HTML 转义,防止 XSS 攻击。如需显示原始 HTML,使用 {{ variable|safe }},但务必确保内容可信。

掌握 Django 模板系统后,你将能够高效地构建动态、可维护的 Web 页面。下一课我们将学习 Django 表单系统,它常与模板系统配合使用来处理用户输入。

练习编辑器

python
Loading...

继续学习

完成本课后,建议继续学习下一课「Django 表单与表单处理」 以巩固所学知识。