news 2026/5/15 23:07:57

Django 模板(Template):告别硬编码,实现动态 HTML页面

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Django 模板(Template):告别硬编码,实现动态 HTML页面

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。


当你开始构建一个真正的 Web 应用时,很快就会厌倦这种方式:

def home(request):returnHttpResponse("<h1>欢迎,张三!</h1><p>今天的日期是 2026-05-15</p>")

这种把 HTML 直接写在 Python 代码里的做法,正是典型的硬编码。哪怕只改动一个标点,都要修改视图代码、重启服务器。而当页面结构变复杂时,代码会变成一团糟,毫无可维护性可言。

Django 的模板(Template)系统正是为了解决这个问题而生的。它让你把 HTML 页面独立出来,只负责展示逻辑,而数据则由视图(View)动态注入。这就是MTV 模式中 T(Template)的核心价值。


1. 初识 Django 模板:配置与第一个模板

首先要确保项目已配置好模板引擎。打开settings.py,你会看到类似配置:

TEMPLATES=[{'BACKEND':'django.template.backends.django.DjangoTemplates','DIRS':[BASE_DIR /'templates'],# 全局模板目录'APP_DIRS':True,# 自动查找每个应用下的 templates 目录'OPTIONS':{'context_processors':['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},]

接着,在应用目录(比如blog)下创建templates/blog/index.html

<!DOCTYPE html><html><head><metacharset="utf-8"><title>{{title}}</title></head><body><h1>欢迎,{{user_name}}</h1><p>今天的日期是{{today}}</p></body></html>

视图中使用render()将数据传入模板:

from django.shortcutsimportrender from datetimeimportdatedef home(request): context={'title':'我的博客','user_name':'张三','today':date.today(),}returnrender(request,'blog/index.html', context)

访问页面,你会看到动态生成的 HTML。我们还可以在 Django shell 中直接体验模板的渲染过程,感受它的底层运作:

>>>from django.templateimportTemplate, Context>>>t=Template("<h1>欢迎,{{ user_name }}!</h1>")>>>c=Context({"user_name":"李四"})>>>print(t.render(c))<h1>欢迎,李四!</h1>

控制台输出正是你看到的最后一行 HTML 字符串。这就是模板的本质:把上下文数据填充到占位符中,生成纯静态 HTML 返回给浏览器。


2. 三大核心语法:变量、标签、过滤器

Django 模板的语法集中体现在三种特殊标记上。

2.1 变量 ——{{ variable }}

变量用双大括号包裹,模板会将其替换为上下文中的对应值。变量名支持点号查找,比如访问字典键、对象属性和列表索引:

# 视图传入context={'book':{'title':'Django 实战','author':'王五'},'numbers':[10,20,30],}
<p>书名:{{book.title}}</p><p>作者:{{book.author}}</p><p>第二个数字:{{numbers.1}}</p>

在 shell 中验证:

>>>t=Template("书名: {{ book.title }}, 作者: {{ book.author }}")>>>c=Context({"book":{"title":"深入浅出Django","author":"老张"}})>>>print(t.render(c))书名: 深入浅出Django, 作者: 老张

2.2 标签 ——{% tag %}

标签用来实现逻辑控制,比如循环、条件判断、URL 生成等。常用的有:

for 循环
<ul>{%forarticleinarticles %}<li>{{article.title}}——{{article.author}}</li>{% empty %}<li>暂无文章</li>{% endfor %}</ul>

如果articles是空列表,会执行{% empty %}下的内容。

视图模拟数据并打印结果:

>>>from django.templateimportTemplate, Context>>>t=Template("""...<ul>...{%forartinarticles %}...<li>{{art.title}}</li>...{% empty %}...<li>无数据</li>...{% endfor %}...</ul>...""")>>>c=Context({"articles":[{"title":"Django入门"},{"title":"模板进阶"}]})>>>print(t.render(c).strip())<ul><li>Django入门</li><li>模板进阶</li></ul>
if/elif/else 条件判断
{%ifuser.is_authenticated %}<p>欢迎回来,{{user.username}}</p>{%elifuser.is_anonymous %}<p>请先登录</p>{%else%}<p>用户状态未知</p>{% endif %}

在 shell 里测试多个分支:

>>>t=Template("{% if score >= 90 %}优秀{% elif score >= 60 %}及格{% else %}不及格{% endif %}")>>>print(t.render(Context({"score":85})))及格>>>print(t.render(Context({"score":55})))不及格
url 标签

避免在模板中硬编码 URL 路径,使用命名路由:

<ahref="{% url 'blog:detail' article.id %}">阅读全文</a>

blog:detail是你在urls.py中定义的 name 参数,即使将来 URL 变化,模板也无需修改。

csrf_token

在任何有 POST 表单的模板中,必须添加:

<formmethod="post">{% csrf_token %}<!-- 表单内容 --></form>

它会生成一个隐藏的 CSRF 令牌,防止跨站请求伪造攻击。

2.3 过滤器 ——{{ variable|filter }}

过滤器就像一个小函数,对变量进行加工后再显示。可以串联使用:{{ text|truncatewords:30|safe }}

常用过滤器及控制台演示:

>>>from django.templateimportTemplate, Context>>># 1. date 格式化日期>>>t=Template("{{ today|date:'Y年m月d日' }}")>>>importdatetime>>>print(t.render(Context({"today":datetime.date(2026,5,15)})))2026年05月15日>>># 2. default 默认值>>>t=Template("昵称: {{ nickname|default:'匿名用户' }}")>>>print(t.render(Context({})))# 没传 nickname昵称: 匿名用户>>># 3. length 获取长度>>>t=Template("标签数: {{ tags|length }}")>>>print(t.render(Context({"tags":["Python","Django","Web"]})))标签数:3>>># 4. truncatechars 截断字符>>>t=Template("简介: {{ desc|truncatechars:10 }}")>>>print(t.render(Context({"desc":"这是一篇很长很长的文章介绍"})))简介: 这是一篇很长...>>># 5. safe 标记安全内容(慎用)>>>t=Template("{{ html_text|safe }}")>>>print(t.render(Context({"html_text":"<strong>加粗</strong>"})))<strong>加粗</strong># 实际 HTML 会被执行

注意safe会关闭自动转义,存在 XSS 风险,只应对可信内容使用。


3. 模板继承:消除重复代码

真实项目中,所有页面往往共享相同的头部、导航栏、侧边栏和底部。Django 的模板继承让你只需定义一个基础骨架,其他页面按需填充。

基础模板base.html

<!DOCTYPE html><html><head><title>{% block title %}我的网站{% endblock %}</title>{% block extra_head %}{% endblock %}</head><body><header><nav>首页|文章|关于</nav></header><main>{% block content %}<!-- 子模板内容会出现在这里 -->{% endblock %}</main><footer>©2026我的网站</footer></body></html>

子模板blog/list.html

{% extends"base.html"%}{% block title %}{{category.name}}- 文章列表{% endblock %}{% block content %}<h1>分类:{{category.name}}</h1>{%forpostinposts %}<article><h2>{{post.title}}</h2><p>{{post.summary|truncatewords:30}}</p></article>{% empty %}<p>该分类下暂无文章。</p>{% endfor %}{% endblock %}

在 shell 中,我们无法直接测试继承(因为需要加载模板文件),但可以在视图中通过render观察效果。更直观的方式是编写一个小的视图并查看控制台输出(或直接看浏览器)。不过我们可以模拟块覆盖的思路:

# 模拟 base.html 定义base=Template(""" 开始{% block main %}默认{% endblock %}结束""")# 模拟子模板内容(实际上 extends 会触发模板加载)# 这里仅做概念说明,真实项目中使用文件系统加载器。

概念清晰即可:继承让代码复用率大幅提升,新增页面只需关注变化的内容块。


4. 包含与复用组件 ——{% include %}

除了继承,还可以用{% include %}把独立的 UI 片段(如分页条、评论区)抽离成组件,在多个模板中引用。

定义_pagination.html

<divclass="pagination">{%ifpage_obj.has_previous %}<ahref="?page={{ page_obj.previous_page_number }}">上一页</a>{% endif %}<span>{{page_obj.number}}/{{page_obj.paginator.num_pages}}</span>{%ifpage_obj.has_next %}<ahref="?page={{ page_obj.next_page_number }}">下一页</a>{% endif %}</div>

在列表页中使用:

{% include"_pagination.html"withpage_obj=page_obj %}

with可以传递额外的变量。如果不写,模板会自动访问当前上下文中的同名变量。

还可以传递固定值:

{% include"name_card.html"withperson=usergreeting="你好"%}

5. 实战:构建一个动态博客首页

现在我们把学到的知识整合,实现一个简单的博客首页,显示文章列表、分类、用户登录状态。

视图views.py

from django.shortcutsimportrender from datetimeimportdatedef blog_home(request):# 模拟数据库数据posts=[{'id':1,'title':'深入理解Django模板','summary':'讲解模板语法...','pub_date':date(2026,5,10)},{'id':2,'title':'Python 3.13 新特性','summary':'关于新版本...','pub_date':date(2026,5,12)},]categories=['Django','Python','前端']user=request.user# 当前登录用户context={'posts':posts,'categories':categories,'user':user,}# 打印上下文数据,方便调试print("首页上下文数据:", context)returnrender(request,'blog/home.html', context)

控制台会输出:

首页上下文数据:{'posts':[{'id':1,'title':'深入理解Django模板',...},...],'categories':['Django','Python','前端'],'user':<SimpleLazyObject:<User: admin>>}

模板blog/home.html

{% extends"base.html"%}{% block title %}博客首页{% endblock %}{% block content %}<h1>最新文章</h1><!-- 用户状态 -->{%ifuser.is_authenticated %}<p>你好,{{user.username}}<ahref="/accounts/logout/">退出</a></p>{%else%}<p><ahref="/accounts/login/">登录</a>|<ahref="/accounts/register/">注册</a></p>{% endif %}<!-- 分类导航 --><divclass="categories"><strong>分类:</strong>{%forcatincategories %}<ahref="#">{{cat}}</a>{%ifnot forloop.last %},{% endif %}{% endfor %}</div><!-- 文章列表 -->{%forpostinposts %}<article><h2><ahref="{% url 'blog:detail' post.id %}">{{post.title}}</a></h2><pclass="date">{{post.pub_date|date:'Y年m月d日'}}</p><p>{{post.summary|truncatewords:20}}</p></article>{% empty %}<p>还没有文章,赶紧写一篇吧。</p>{% endfor %}<!-- 包含分页组件(示例,无实际分页对象) -->{% comment %}{% include"_pagination.html"%}{% endcomment %}{% endblock %}

这个首页完全由数据驱动,结构与展示分离。今后你只需要修改视图中的posts数据来源(例如从数据库查询),模板无需变动。


6. 进阶技巧:自定义过滤器与标签

当内置过滤器无法满足需求时,你可以创建自己的模板工具。

6.1 自定义过滤器

在应用目录下创建templatetags包(含__init__.py),新建blog_extras.py

from djangoimporttemplateimportbleach register=template.Library()@register.filter(name='truncate_chinese')def truncate_chinese(value,max_length=30):"""智能截断中文字符,避免乱码"""iflen(value)<=max_length:returnvaluereturnvalue[:max_length]+'...'@register.filter def add_class(value, css_class):"""为表单字段添加 CSS 类(简化版)"""returnvalue.as_widget(attrs={"class":css_class})

在模板中加载并使用:

{% load blog_extras %}<p>{{post.content|truncate_chinese:50}}</p>{{form.username|add_class:"form-control"}}

控制台里直接测试自定义过滤器:

>>>from django.templateimportTemplate, Context>>># 先确保加载了标签库,在实际 shell 中需要先注册 app>>># 模拟效果:>>>def truncate_chinese(value,max_len=10):...returnvalue[:max_len]+'...'iflen(value)>max_lenelsevalue...>>>t=Template("{% load blog_extras %}{{ text|truncate_chinese:6 }}")>>># 实际渲染需要模板引擎加载,这里仅示意...

6.2 自定义包含标签

如果某个片段需要一些 Python 逻辑才能渲染,可以用包含标签。比如“最新评论”组件:

@register.inclusion_tag('blog/latest_comments.html')def show_latest_comments(post_id,count=5): comments=Comment.objects.filter(post_id=post_id).order_by('-created')[:count]return{'comments':comments}

模板latest_comments.html

<ul>{%forcommentincomments %}<li>{{comment.author}}:{{comment.content|truncatechars:30}}</li>{% endfor %}</ul>

使用时:

{% show_latest_comments post.id3%}

7. 模板调试与最佳实践

7.1 控制台输出助力调试

开发过程中,你可以在视图中使用print()查看传入模板的上下文,或者查看某个对象的类型和属性:

def article_list(request): posts=Post.objects.prefetch_related('tags').all()print("查询到的文章数量:", posts.count())forpinposts: print(p.title, p.tags.all())returnrender(request,'list.html',{'posts':posts})

服务器控制台将实时输出这些信息,方便你核对数据是否符合预期。

7.2 利用 Django Debug Toolbar

安装django-debug-toolbar,它会在页面侧边栏展示模板渲染的上下文、SQL 查询等信息,比 print 更为强大。

7.3 模板设计原则

  • 逻辑尽量简单:模板中只放展示逻辑,复杂的业务逻辑应放在视图或模型中。

  • 避免大量嵌套:利用继承和包含拆分复杂页面。

  • 静态资源管理:使用{% static 'css/style.css' %}引用静态文件。

  • 安全性:不要轻易使用safe过滤器,确保转义输出;时刻记住{% csrf_token %}


8. 总结

Django 模板让你从硬编码 HTML 的泥潭中解脱,实现了:

  • 表现与逻辑分离:HTML 独立为模板文件,Python 代码专注数据处理。

  • 代码复用:通过继承和包含,公共部分只写一次。

  • 可维护性:修改页面结构时,无需触碰视图代码;反之亦然。

  • 高度可扩展:自定义标签和过滤器能满足各种个性化需求。

从最简单的{{ variable }}开始,到构建出结构清晰的动态网站,模板系统始终是 Django 快速开发理念的基石。掌握它,你就能优雅地“告别硬编码,实现动态 HTML 页面”。

还可以去公众号、今日头条搜索「IT策士」,一起升级 IT 思维 !

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/15 23:06:21

ARM架构中的辅助控制寄存器(ACTLR)详解与应用

1. ARM架构中的辅助控制寄存器(ACTLR)概述在ARMv8/v9架构中&#xff0c;辅助控制寄存器(ACTLR)是一组实现定义(IMPLEMENTATION DEFINED)的系统寄存器&#xff0c;用于提供处理器微架构级别的配置和控制选项。与标准系统寄存器不同&#xff0c;ACTLR的具体功能和行为由芯片厂商自…

作者头像 李华
网站建设 2026/5/15 23:00:51

一站式文档下载神器:kill-doc高效获取30+平台免费资源

一站式文档下载神器&#xff1a;kill-doc高效获取30平台免费资源 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档&#xff0c;但是相关网站浏览体验不好各种广告&#xff0c;各种登录验证&#xff0c;需要很多步骤才能下载文档&#xff0c;该脚本就是为了解…

作者头像 李华
网站建设 2026/5/15 23:00:47

解锁LAVIS预训练策略:打造高效视觉语言模型的完整指南

解锁LAVIS预训练策略&#xff1a;打造高效视觉语言模型的完整指南 【免费下载链接】LAVIS LAVIS - A One-stop Library for Language-Vision Intelligence 项目地址: https://gitcode.com/gh_mirrors/la/LAVIS LAVIS是一个一站式Python深度学习库&#xff0c;专为语言-视…

作者头像 李华