Python
模板、静态文件与媒体文件
发布于 2026年7月22日
模板、静态文件与媒体文件
本篇完成 Django 的展示层:用模板继承组织页面,用静态文件管理 CSS/JS,用媒体文件保存用户上传内容。
一、推荐目录结构
mysite/
manage.py
templates/
base.html
404.html
static/
css/site.css
js/site.js
media/
notes/
templates/notes/
message_list.html
message_detail.html
应用模板多加一层 notes/,可以避免多个应用都有 list.html 时重名。
二、模板配置
settings.py:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
DIRS:项目级模板目录。APP_DIRS=True:查找各应用的templates/。- 上下文处理器:向多个模板注入公共变量。
三、模板变量、标签和过滤器
<h1>{{ message.name }}</h1>
<p>{{ message.content|linebreaksbr }}</p>
<time>{{ message.created_at|date:"Y-m-d H:i" }}</time>
{% if message.status == "published" %}
<span>已发布</span>
{% endif %}
{% for tag in message.tags.all %}
<span>{{ tag.name }}</span>
{% empty %}
<span>暂无标签</span>
{% endfor %}
模板应负责展示,不适合执行复杂查询或业务计算。复杂数据在 View、Model 方法或自定义模板标签中准备。
Django 默认对变量进行 HTML 转义,这能降低 XSS 风险。除非内容经过可信清洗,不要随意使用 safe 过滤器。
四、模板继承
templates/base.html:
{% load static %}
<!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>
<link rel="stylesheet" href="{% static 'css/site.css' %}">
{% block extra_head %}{% endblock %}
</head>
<body>
<header>
<a href="{% url 'notes:list' %}">留言板</a>
</header>
<main>
{% if messages %}
{% for message in messages %}
<p>{{ message }}</p>
{% endfor %}
{% endif %}
{% block content %}{% endblock %}
</main>
<script src="{% static 'js/site.js' %}" defer></script>
</body>
</html>
子模板:
{% extends "base.html" %}
{% block title %}留言详情{% endblock %}
{% block content %}
<article>
<h1>{{ message.name }}</h1>
<p>{{ message.content|linebreaksbr }}</p>
</article>
{% endblock %}
通用局部页面可放在 templates/includes/,通过 {% include "includes/pagination.html" %} 引入。
五、静态文件
settings.py:
STATIC_URL = "static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
STATIC_ROOT = BASE_DIR / "staticfiles"
STATICFILES_DIRS:开发时项目自带的静态资源目录。- 应用也可拥有
notes/static/notes/。 STATIC_ROOT:部署时collectstatic汇总资源的目标目录,不应手工编辑。
生产部署前执行:
python manage.py collectstatic --noinput
开发服务器能自动处理静态文件,不代表生产应用服务器也应该这样做。生产环境通常由 Nginx 或专门的静态文件方案提供资源。
六、媒体文件与上传内容
settings.py:
MEDIA_URL = "media/"
MEDIA_ROOT = BASE_DIR / "media"
模型:
class Attachment(models.Model):
message = models.ForeignKey(
Message,
on_delete=models.CASCADE,
related_name="attachments",
)
file = models.FileField(upload_to="attachments/%Y/%m/")
uploaded_at = models.DateTimeField(auto_now_add=True)
仅在开发环境添加媒体路由:
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# 原有路由
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
模板显示文件链接:
{% for attachment in message.attachments.all %}
<a href="{{ attachment.file.url }}">{{ attachment.file.name }}</a>
{% endfor %}
用户上传文件与静态文件是两类资源:静态文件随代码发布,媒体文件由用户产生,需要独立备份、权限校验和容量管理。
七、自定义模板过滤器
目录:
notes/
templatetags/
__init__.py
notes_extras.py
from django import template
register = template.Library()
@register.filter
def truncate_chars(value, length=20):
value = str(value)
return value if len(value) <= length else f"{value[:length]}..."
模板中:
{% load notes_extras %}
{{ message.content|truncate_chars:30 }}
自定义标签适合复用展示逻辑,但不应隐藏大量数据库查询。
八、常见问题
TemplateDoesNotExist:检查路径、文件名、应用是否注册以及APP_DIRS。- 静态文件 404:确认
{% load static %}、静态路径和应用命名空间目录。 - 图片上传成功但打不开:检查
MEDIA_ROOT、MEDIA_URL和开发媒体路由。 - 页面出现原始 HTML:确认是否误用了自动转义;不要为了显示富文本直接全局关闭转义。
- CSS 更新不生效:浏览器缓存或生产环境尚未重新执行
collectstatic。
九、本篇检查清单
- 能使用模板继承、包含和 URL 反向解析。
- 能区分静态文件与媒体文件。
- 知道生产环境需要执行
collectstatic。 - 知道模板自动转义的安全意义。
- 能创建简单的自定义模板过滤器。
上一篇:模型、ORM 与数据库迁移 | 下一篇:表单验证与文件上传