Django 从入门到精通:知行博客实战(6.1) · 第 6 / 36 节

模板继承与安全输出

吴秀峰 4 次阅读 0 条评论 ↓

学习目标

将 HTML 从视图移到模板,用继承复用页头页脚,用上下文字典传递数据,理解自动转义为何不能随意关闭。

为什么让视图和模板分工

视图负责“取什么数据、是否允许访问”,模板负责“怎样显示”。把 HTML 拼在 Python 字符串中会让条件、链接和页面结构越来越难维护。render(request, 模板名, 上下文) 会加载模板并返回 HTML 响应。

base.html 定义公共骨架,子模板通过 extends 继承,通过 block 替换页面标题和正文。模板语言不是完整 Python:尽量在视图中计算数据,只在模板中做展示判断。这个分工与本站 templates/base.html、templates/course/show.html 一致。

具体怎么做

  1. 在根目录建立 templates/,其中 blog/ 存放博客页面。
  2. 替换视图,使首页传入 greeting。字典键 greeting 对应模板里的 {{ greeting }}。
  3. 基础模板使用 {% url %},避免导航地址散落在各页。
  4. 加入 lang、字符集、viewport 和“跳到正文”链接,开始建立可访问的页面结构。

本章新增或替换的完整文件

以下路径均相对于练习项目根目录。替换同名文件的全部内容;未列出的文件保持上一章版本。

blog/views.py

from django.shortcuts import render, redirect
from django.views.decorators.http import require_GET

@require_GET
def home(request):
    return render(request, "blog/home.html", {"greeting": "欢迎来到知行博客"})

@require_GET
def about(request):
    return render(request, "blog/about.html")

@require_GET
def old_home(request):
    return redirect("blog:home")

templates/base.html

<!doctype html>
<html lang="zh-CN">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}知行博客{% endblock %}</title></head>
<body>
<a href="#main">跳到正文</a>
<header><nav aria-label="主导航"><a href="{% url 'blog:home' %}">知行博客</a> <a href="{% url 'blog:about' %}">关于</a></nav></header>
<main id="main">{% block content %}{% endblock %}</main>
<footer>知行博客 · 记录、实践、分享</footer>
</body></html>

templates/blog/about.html

{% extends "base.html" %}
{% block title %}关于 · 知行博客{% endblock %}
{% block content %}<h1>关于知行博客</h1><p>这是贯穿教程的博客项目,支持阅读、写作和讨论。</p>{% endblock %}

templates/blog/home.html

{% extends "base.html" %}
{% block content %}<h1>{{ greeting }}</h1><p>今天开始,把学习变成可以运行的代码。</p>{% endblock %}

如何确认成功

python manage.py check
python manage.py runserver

首页显示“欢迎来到知行博客”,关于页有独立的浏览器标题,但页头和页脚相同。按 Tab 键,应能用键盘走到导航链接。

在 shell 中做一个不修改文件的安全实验:

python manage.py shell -c "from django.template.loader import render_to_string; print(render_to_string('blog/home.html', {'greeting': '<script>alert(1)</script>'}))"

输出中危险字符串应变成 &lt;script&gt;,不会被当成脚本执行。以后文章正文默认以纯文本保存并转义展示;只有经过可信清洗的 HTML 才能使用 safe。本站的教程内容会经过现有 HTML 清洗器,和练习项目的纯文本文章是两个不同场景。

练习:为关于页添加一个新的 block 或一段说明,验证没有复制整份 HTML。再尝试拼错模板路径,阅读 TemplateDoesNotExist 错误展示的搜索位置。

常见问题

变量不显示也不报错? 模板中的不存在变量通常显示为空,先核对上下文键名。extends 放在哪里? 子模板中它应是第一个模板标签,避免继承行为不明确。为什么不用 safe 解决换行? safe 会改变安全边界,换行请用后面的 linebreaks 过滤器,它会处理转义和段落。

官方参考

把学习连起来

登录后可保存阅读位置、标记章节完成,并在其他设备继续学习。

登录并保存学习进度 →
联系站长

微信:VIPdjango。技术问题建议先在 社区讨论 中交流,方便更多人参与和查阅。

章节讨论 0