Django 模板系统使用 Django 模板语言 (DTL),这是一种简单而强大的语言,专门设计用于在 HTML 中嵌入动态内容。模板系统允许开发者将 Python 代码与 HTML 分离,遵循 MVC (模型-视图-控制器) 或 MTV (模型-模板-视图) 设计模式。
准备数据
渲染 HTML
查看页面
{{ variable }}{% tag %}{{ variable|filter }}{# comment #}{% extends %} 和 {% block %}Django 在以下位置查找模板:
templates 文件夹settings.py 中 DIRS 指定的目录templates 目录
# settings.py
TEMPLATES = [
{
'DIRS': [BASE_DIR / 'templates'],
# ...
},
]
模板变量用于在模板中显示来自视图的上下文数据。变量使用双花括号 {{ }} 包围。
from django.shortcuts import render
def user_profile(request):
context = {
'username': '张三',
'age': 25,
'hobbies': ['阅读', '编程', '旅行'],
'profile': {
'email': 'zhangsan@example.com',
'joined': '2022-01-15'
}
}
return render(request, 'profile.html', context)
<h1>用户资料</h1>
<p>用户名: @{{ username }}</p>
<p>年龄: {{ age }}</p>
<p>第一个爱好: {{ hobbies.0 }}</p>
<p>邮箱: {{ profile.email }}</p>
<p>注册日期: {{ profile.joined }}</p>
{# 使用 for 标签遍历列表 #}
<h3>爱好:</h3>
<ul>
{% for hobby in hobbies %}
<li>{{ hobby }}</li>
{% endfor %}
</ul>
. 访问变量的属性、字典键或列表索引。如果变量不存在,Django 默认会插入空字符串。
模板标签提供了模板逻辑控制功能,使用 {% %} 语法。标签可以执行循环、条件判断、模板继承等操作。
{% if user.is_authenticated %}
<p>欢迎, {{ user.username }}!</p>
{% else %}
<p>请<a href="/login/">登录</a></p>
{% endif %}
{% if age >= 18 %}
<p>您是成年人</p>
{% elif age >= 13 %}
<p>您是青少年</p>
{% else %}
<p>您是儿童</p>
{% endif %}
<ul>
{% for item in items %}
<li>{{ forloop.counter }}: {{ item.name }}</li>
{% empty %}
<li>没有项目</li>
{% endfor %}
</ul>
{# 遍历字典 #}
{% for key, value in data.items %}
<p>{{ key }}: {{ value }}</p>
{% endfor %}
| 变量 | 描述 |
|---|---|
forloop.counter |
当前循环的索引(从1开始) |
forloop.counter0 |
当前循环的索引(从0开始) |
forloop.revcounter |
从循环末尾开始的索引(从1开始) |
forloop.revcounter0 |
从循环末尾开始的索引(从0开始) |
forloop.first |
如果是第一次循环,则为True |
forloop.last |
如果是最后一次循环,则为True |
{# 使用 URL 名称 #}
<a href="{% url 'home' %}">首页</a>
{# 带参数的 URL #}
<a href="{% url 'user_profile' user_id=user.id %}">用户资料</a>
{# 在视图和 URL 配置中的对应 #}
{# 缓存复杂查询结果 #}
{% with bio=user.profile.bio|default:"暂无简介" %}
<p>{{ bio }}</p>
{% endwith %}
{% with total=products|length %}
<p>共有 {{ total }} 个产品</p>
{% endwith %}
过滤器用于修改变量的显示方式,使用管道符号 | 应用。可以串联多个过滤器。
{# 字符串过滤器 #}
<p>{{ name|lower }}</p>
<p>{{ title|upper }}</p>
<p>{{ message|title }}</p>
<p>{{ text|truncatewords:10 }}</p>
{# 日期过滤器 #}
<p>{{ pub_date|date:"Y-m-d" }}</p>
<p>{{ created_at|timesince }}</p>
{# 数字过滤器 #}
<p>{{ price|floatformat:2 }}</p>
<p>{{ items|length }}</p>
{# 默认值过滤器 #}
<p>{{ description|default:"暂无描述" }}</p>
{# 安全过滤器 #}
<p>{{ html_content|safe }}</p>
| 过滤器 | 描述 | 示例 |
|---|---|---|
lower |
转换为小写 | {{ "HELLO"|lower }} → "hello" |
upper |
转换为大写 | {{ "hello"|upper }} → "HELLO" |
length |
返回长度 | {{ list|length }} → 列表长度 |
default |
默认值 | {{ value|default:"空" }} |
date |
日期格式化 | {{ date|date:"Y-m-d" }} |
truncatechars |
截断字符 | {{ text|truncatechars:20 }} |
floatformat |
浮点数格式化 | {{ 3.14159|floatformat:2 }} → 3.14 |
safe |
标记为安全HTML | {{ html|safe }} |
safe 过滤器时要特别小心,确保内容是可信的,否则可能导致 XSS 攻击。
模板继承是 Django 模板系统最强大的功能之一。它允许您创建一个基础模板,然后在子模板中覆盖特定部分。
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}我的网站{% endblock %}</title>
<link rel="stylesheet" href="/css/style.css">
</head>
<body>
<div id="header">
<h1>{% block header %}网站标题{% endblock %}</h1>
</div>
<div id="content">
{% block content %}
<p>默认内容</p>
{% endblock %}
</div>
<div id="footer">
{% block footer %}
<p>© 2023 我的网站</p>
{% endblock %}
</div>
</body>
</html>
{% extends "base.html" %}
{% block title %}关于我们 - 我的网站{% endblock %}
{% block header %}
<h1>关于我们</h1>
{% endblock %}
{% block content %}
<h2>公司简介</h2>
<p>我们是一家专注于...</p>
{# 引用父模板的内容 #}
{{ block.super }}
{% endblock %}
{% block footer %}
<p>© 2023 我的网站 - 关于页面</p>
{% endblock %}
{# 包含导航栏 #}
{% include "navbar.html" %}
{# 包含带变量的模板 #}
{% include "product_item.html" with product=item %}
{# 只使用本地变量 #}
{% include "name_snippet.html" with greeting="Hello" only %}
除了内置的过滤器和标签,Django 还允许您创建自定义过滤器和标签。
from django import template
register = template.Library()
@register.filter
def multiply(value, arg):
"""将值乘以参数"""
try:
return float(value) * float(arg)
except (ValueError, TypeError):
return ''
@register.filter
def replace_comma(value):
"""将逗号替换为空格"""
return str(value).replace(',', ' ')
{% load custom_filters %}
<p>价格: {{ price|multiply:1.1 }}</p>
<p>{{ tags|replace_comma }}</p>
from django import template
register = template.Library()
@register.simple_tag
def current_time(format_string):
from datetime import datetime
return datetime.now().strftime(format_string)
@register.inclusion_tag('results.html')
def show_results(poll):
choices = poll.choice_set.all()
return {'choices': choices}
templates/
├── base.html
├── includes/
│ ├── header.html
│ ├── footer.html
│ └── sidebar.html
├── accounts/
│ ├── login.html
│ └── profile.html
└── products/
├── list.html
└── detail.html
{% with %} 缓存复杂查询{% include %} 标签
{# 使用 with 缓存查询 #}
{% with count=users.count %}
<p>用户数: {{ count }}</p>
{% endwith %}
{# 模板片段缓存 #}
{% load cache %}
{% cache 500 sidebar %}
{# 侧边栏内容 #}
{% endcache %}