浏览知识库目录

Python

模板、静态文件与媒体文件

模板、静态文件与媒体文件

本篇完成 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_ROOTMEDIA_URL 和开发媒体路由。
  • 页面出现原始 HTML:确认是否误用了自动转义;不要为了显示富文本直接全局关闭转义。
  • CSS 更新不生效:浏览器缓存或生产环境尚未重新执行 collectstatic

九、本篇检查清单

  • 能使用模板继承、包含和 URL 反向解析。
  • 能区分静态文件与媒体文件。
  • 知道生产环境需要执行 collectstatic
  • 知道模板自动转义的安全意义。
  • 能创建简单的自定义模板过滤器。

上一篇:模型、ORM 与数据库迁移 | 下一篇:表单验证与文件上传