5.1 DTL 概览
DTL(Django Template Language)刻意做得「弱逻辑」——它鼓励把复杂逻辑留在视图,模板只管展示。三个基本构件:变量、标签、过滤器。
- DTL
- Django 内置模板引擎,语法安全(自动 HTML 转义防 XSS)、故意限制逻辑能力,避免模板里塞业务代码。
- 变量(Variable)
{{ variable }},输出上下文中的值,支持点号访问属性/字典键/方法/列表索引。- 标签(Tag)
{% tag %},控制逻辑与流程,如{% if %}/{% for %}/{% url %}/{% block %}。- 过滤器(Filter)
{{ value|filter }},对变量做格式化,如|upper/|date/|truncatewords/|default。- 模板继承(Inheritance)
{% extends %}+{% block %},用「骨架 + 覆盖块」复用布局,避免每页重复 header/footer。- 上下文(Context)
- 视图传给模板的数据字典。
render(request, tpl, {...})里的字典即上下文。 - 静态文件(Static)
- CSS/JS/图片等不变资源,用
{% load static %}+{% static %}生成 URL。 - 上下文处理器(Context Processor)
- 为所有模板注入公共变量的函数,如
request、user,在settings.TEMPLATES配置。
5.2 变量、标签、过滤器
<h1>{{ post.title }}</h1>
<p>作者:{{ post.author.username|default:"匿名" }}</p>
<p>发布于 {{ post.created|date:"Y-m-d H:i" }}</p>
<p>{{ post.body|truncatewords:30 }}</p>
{% if post.published %}
<span>已发布</span>
{% else %}
<span>草稿</span>
{% endif %}
<ul>
{% for tag in post.tags.all %}
<li>{{ forloop.counter }}. {{ tag.name }}</li>
{% empty %}
<li>暂无标签</li>
{% endfor %}
</ul>
常用过滤器
| 过滤器 | 作用 |
|---|---|
| |upper / |lower | 大小写转换 |
| |date:"Y-m-d" | 日期格式化 |
| |default:"—" | 为空时的默认值 |
| |truncatewords:20 | 截断到 N 个词 |
| |length | 长度 |
| |linebreaks | 换行转 <p>/<br> |
| |safe | 标记为安全 HTML(不转义) |
5.3 模板继承
<!-- templates/base.html:骨架 -->
{% load static %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}古法编程{% endblock %}</title>
<link rel="stylesheet" href="{% static 'css/site.css' %}">
</head>
<body>
<header>导航...</header>
<main>{% block content %}{% endblock %}</main>
<footer>© 古法编程</footer>
</body>
</html>
<!-- templates/blog/list.html:继承并覆盖 -->
{% extends "base.html" %}
{% block title %}文章列表 · 古法编程{% endblock %}
{% block content %}
{% for post in posts %}
<a href="{% url 'blog:detail' post.pk %}">{{ post.title }}</a>
{% endfor %}
{% endblock %}
DRY 的展示层
把公共布局放 base.html,各页面只覆盖 title/content 块。改导航、换 CSS 只需动一处——这就是模板继承的价值。
5.4 模板查找路径
# settings.py
TEMPLATES = [{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"], # 项目级模板目录
"APP_DIRS": True, # 自动搜每个 App 的 templates/
...
}]
App 模板命名空间
APP_DIRS=True 时 Django 会搜所有 App 的 templates/,同名文件会冲突。惯例是再套一层 App 名:blog/templates/blog/list.html,引用时写 "blog/list.html"。
5.5 静态文件
{% load static %}
<img src="{% static 'blog/logo.png' %}" alt="logo">
<script src="{% static 'blog/app.js' %}"></script>
# settings.py
STATIC_URL = "/static/"
STATICFILES_DIRS = [BASE_DIR / "static"] # 开发期额外目录
STATIC_ROOT = BASE_DIR / "staticfiles" # collectstatic 目标(生产)
5.6 自定义标签与过滤器
# blog/templatetags/blog_extras.py
from django import template
register = template.Library()
@register.filter
def badge(value):
return "🔥" if value > 100 else ""
# 模板中:{% load blog_extras %} {{ post.views|badge }}
5.7 小结与下一步
- DTL 用变量、标签、过滤器渲染数据,逻辑弱化以保持展示层纯净。
- 模板继承(extends + block)实现布局复用;App 模板要加命名空间目录。
- 静态文件用
{% static %},生产用collectstatic收集到STATIC_ROOT。 - 下一章进入 表单与验证——安全地接收与校验用户输入。