Django 亮点:模板化保存行(第 2 部分)

已发表: 2022-03-10
快速总结 ↬在 Django 中使用模板和服务器端渲染创建前端代码,将手写 HTML 的细粒度控制与生成页面的简洁代码和强大功能相结合。 我们探索将复杂的网页分解为多个模板,组合这些组件,并应用标签和过滤器来重构纯 HTML 页面。

一些构建网站的简单方法需要开发人员手动编写 HTML 的每一行。 在另一个极端,商业无代码站点构建器会自动为用户创建所有 HTML,通常以牺牲生成代码的可读性为代价。 模板是该范围的中间部分,但更接近于手写 HTML,而不是使用 React 或类似库在单页应用程序中生成页面结构。 连续统一体上的这个最佳点提供了从头开始手动 HTML 的许多好处(语义/可读代码、对页面结构的完全控制、快速页面加载)并增加了关注点和简洁性的分离,所有这些都以花费一些时间编写为代价手动修改 HTML。 本文演示了使用 Django 模板编写复杂页面。

HTML 频谱。 (大预览)

今天的主题适用于 Django 框架之外。 Flask(另一个 Web 框架)和 Pelican(一个静态站点生成器)只是使用相同模板方法的许多其他 Python 项目中的两个。 Jinja2 是所有三个框架都使用的模板引擎,尽管您可以通过更改项目设置来使用不同的引擎(严格来说,Jinja2 是 Django 模板的超集)。 它是一个独立的库,即使没有框架,您也可以将其合并到您自己的项目中,因此本文中的技术非常有用。

该系列的先前部分

  • Django 亮点:用户模型和身份验证(第 1 部分)
  • Django 亮点:模型、管理和利用关系数据库(第 3 部分)
  • Django 亮点:处理静态资产和媒体文件(第 4 部分)
跳跃后更多! 继续往下看↓

服务器端渲染

模板只是一个 HTML 文件,其中 HTML 已使用附加符号进行了扩展。 记住HTML代表什么:文本标记语言。 Jinja2,我们的模板语言,只是简单地在语言中添加了额外的有意义的标记符号。 当服务器呈现模板以向用户提供纯 HTML 页面时,会解释这些附加结构(也就是说,来自模板语言的附加符号不会进入最终输出)。

服务器端渲染是响应请求而构建网页的过程。 Django 使用服务器端渲染向客户端提供 HTML 页面。 在其执行结束时,视图函数将 HTTP 请求、一个或多个模板以及在函数执行期间访问的可选数据组合起来,以构建一个 HTML 页面,并将其作为响应发送给客户端。 数据从数据库通过视图进入模板以到达用户。 如果这个抽象的解释不完全有意义,请不要担心,我们将在本文的其余部分转向一个具体的例子。

配置

对于我们的示例,我们将使用一个相当复杂的网页,启动 Bootstrap 的管理模板,并将 HTML 重写为 Jinja2 模板。 请注意,MIT 许可的库使用不同的模板系统(基于 JavaScript 和 Pug)来生成您看到的页面,但它们的方法与 Jinja2 样式的模板有很大不同,所以这个例子更像是逆向工程而不是翻译他们优秀的开源项目。 要查看我们将要构建的网页,您可以查看 Start Bootstrap 的实时预览。

我为本文准备了一个示例应用程序。 要让 Django 项目在您自己的计算机上运行,​​请启动您的 Python 3 虚拟环境,然后运行以下命令:

 pip install django git clone https://github.com/philipkiely/sm_dh_2_dashboard.git cd sm_dh_2_dashboard python manage.py migrate python manage.py createsuperuser python manage.py loaddata employee_fixture.json python manage.py runserver

然后,打开您的网络浏览器并导航到https://127.0.0.1:8000 。 您应该看到与预览相同的页面,与下图匹配。

仪表板主页。 (大预览)

因为本教程专注于前端,所以底层的 Django 应用程序非常简单。 这似乎是用于呈现单个网页的大量配置,而且公平地说。 然而,如此多的设置也可以支持更强大的应用程序。

现在,我们已准备好完成将这个 668 行 HTML 文件转换为适当架构的 Django 站点的过程。

模板和继承

将数百行 HTML 重构为干净代码的第一步是将元素拆分为自己的模板,Django 将在渲染步骤中将这些模板组合成一个网页。

看看pages/templates 。 您应该看到五个文件:

  • base.html ,每个网页都将扩展的基本模板。 它包含带有标题、CSS 导入等的<head>
  • navbar.html ,顶部导航栏的 HTML,必要时包含的组件。
  • footer.html ,页面页脚的代码,需要时包含的另一个组件。
  • sidebar.html ,侧边栏的 HTMl,需要时包含的第三个组件。
  • index.html ,主页面独有的代码。 此模板扩展了基本模板并包括三个组件。

Django 像 Voltron 一样组装这五个文件来呈现索引页面。 允许这样做的关键字是{% block %}{% include %}{% extend %} 。 在base.html中:

 {% block content %} {% endblock %}

这两行为扩展base.html以插入自己的 HTML 的其他模板留出了空间。 请注意, content是一个变量名,您可以在一个模板中拥有多个不同名称的块,从而为子模板提供灵活性。 我们看到如何在index.html中扩展它:

 {% extends "base.html" %} {% block content %} <!-- HTML Goes Here --> {% endblock %}

使用带基本模板名称的extends关键字为索引页面提供了结构,使我们免于在标题中复制(请注意,文件名是双引号字符串形式的相对路径)。 索引页面包括网站上大多数页面共有的所有三个组件。 我们引入了带有include标签的组件,如下所示:

 {% extends "base.html" %} {% block content %} {% include "navbar.html" %} {% include "sidebar.html" %} <!--Index-Specific HTML--> {% include "footer.html" %} <!--More Index-Specific HTML--> {% endblock %}

总体而言,与单独编写页面相比,这种结构提供了三个主要好处:

  • DRY(不要重复自己)代码
    通过将通用代码分解到特定文件中,我们可以只在一处更改代码,并将这些更改反映到所有页面中。
  • 提高可读性
    您可以隔离您感兴趣的特定组件,而不是滚动浏览一个巨大的文件。
  • 关注点分离
    比如说,侧边栏的代码现在必须在一个地方,不能有任何流氓script标签漂浮在代码底部或其他应该是单独组件之间的混合。 分解出各个部分会强制执行这种良好的编码实践。

虽然我们可以通过将特定组件放在base.html模板中来节省更多代码行,但将它们分开提供两个优点。 首先是我们能够将它们准确地嵌入到它们所属的单个块中(这仅与位于content块的主div内的footer.html相关)。 另一个优点是,如果我们要创建一个页面,比如一个 404 错误页面,并且我们不想要侧边栏或页脚,我们可以将它们排除在外。

这些功能与模板课程相当。 现在,我们转向可以在index.html中使用的强大标签来提供动态特性并节省数百行代码。

两个基本标签

这与可用标签的详尽列表相去甚远。 关于模板的 Django 文档提供了这样的枚举。 目前,我们专注于模板语言中两个最常见元素的用例。 在我自己的工作中,我基本上只定期使用forif标签,尽管提供的十几个或更多其他标签都有自己的用例,我鼓励您在模板参考中查看。

在我们讨论标签之前,我想对语法做一个注释。 标签{% foo %}表示“foo”是模板系统本身的函数或其他功能,而标签{{ bar }}表示“bar”是传递给特定模板的变量。

For 循环

在剩下的index.html中,几百行代码的最大部分是表格。 我们可以从数据库动态生成表,而不是这个硬编码的表。 回想一下设置步骤中的python manage.py loaddata employee_fixture.json 。 该命令使用一个名为 Django Fixture 的 JSON 文件将所有 57 条员工记录加载到应用程序的数据库中。 我们使用views.py中的视图将这些数据传递给模板:

 from django.shortcuts import render from .models import Employee def index(request): return render(request, "index.html", {"employees": Employee.objects.all()})

render的第三个位置参数是模板可用的数据字典。 我们使用这些数据和for标签来构建表格。 即使在我改编此网页的原始模板中,员工表也是硬编码的。 我们的新方法减少了数百行重复的硬编码表格行。 index.html现在包含:

 {% for employee in employees %} <trv <td>{{ employee.name }}</td> <td>{{ employee.position }}</td> <td>{{ employee.office }}</td> <td>{{ employee.age }}</td> vtd>{{ employee.start_date }}</td> <td>${{ employee.salary }}</td> </tr> {% endfor %}

更大的好处是,这大大简化了更新表的过程。 无需让开发人员手动编辑 HTML 以反映加薪或新员工,然后将该更改推送到生产中,任何管理员都可以使用管理面板进行实时更新(https://127.0.0.1/admin,使用您使用python manage.py createsuperuser创建的用于访问的凭据)。 这是将 Django 与此渲染引擎一起使用而不是在静态站点生成器或其他模板方法中单独使用它的好处。

如果别的

if标签是一个非常强大的标签,它允许您评估模板中的表达式并相应地调整 HTML。 像{% if 1 == 2 %}这样的行是完全有效的,如果有点无用的话,因为它们每次都评估相同的结果。 if标记的亮点在于与视图传递到模板的数据进行交互时。 考虑sidebar.html中的以下示例:

 <div class="sb-sidenav-footer"> <div class="small"> Logged in as: </div> {% if user.is_authenticated %} {{ user.username }} {% else %} Start Bootstrap {% endif %} </div>

请注意,默认情况下将整个用户对象传递到模板中,而无需我们在视图中指定任何内容来实现这一点。 这允许我们访问用户的身份验证状态(或缺少身份验证状态)、用户名和其他功能,包括遵循外键关系以访问存储在用户配置文件或其他连接模型中的数据,所有这些都来自 HTML 文件。

您可能会担心这种访问级别可能会带来安全风险。 但是,请记住,这些模板适用于服务器端呈现框架。 构建页面后,标签已经消耗了自己,并被纯 HTML 替换。 因此,如果if语句在某些条件下将数据引入页面,但数据未在给定实例中使用,则该数据根本不会发送到客户端,因为if语句是在服务器端评估的。 这意味着正确构建的模板是一种非常安全的方法,可以将敏感数据添加到页面,除非必要,否则数据不会离开服务器。 也就是说,使用 Django 模板并不能消除以安全、加密方式传递敏感信息的需要,它只是意味着像user.is_authenticated这样的安全检查可以安全地在 HTML 中进行,因为它是在服务器端处理的。

此功能还有许多其他用例。 例如,在一般产品主页中,您可能希望隐藏“注册”和“登录”按钮,并用登录用户的“退出”按钮替换它们。 另一个常见用途是显示和隐藏表单提交等操作的成功或错误消息。 请注意,如果用户未登录,通常您不会隐藏整个页面。根据用户的身份验证状态更改整个网页的更好方法是在views.py中的适当函数中处理它。

过滤

视图的部分工作是为页面适当地格式化数据。 为此,我们对标签进行了强大的扩展:过滤器。 Django 中有许多过滤器可用于执行诸如对齐文本、格式化日期和添加数字等操作。 基本上,您可以将过滤器视为应用于标签中变量的函数。 例如,我们希望我们的工资数字显示为“$1,200,000”而不是“1200,000”。 我们将使用过滤器在index.html中完成工作:

 <td>${{ employee.salary|intcomma }}</td>

管道字符| 是将intcomma命令应用于employee.salary变量的过滤器。 “$”字符不是来自模板,对于像这样每次出现的元素,将其粘贴在标签之外更容易。

请注意, intcomma要求我们在settings.pyINSTALLED_APPS中的index.html'django.contrib.humanize',的顶部包含{% load humanize %} 。 这是在提供的示例应用程序中为您完成的。

结论

使用 Jinja2 引擎的服务器端渲染为创建干净、适应性强、响应迅速的前端代码提供了关键工具。 将页面分成文件允许具有灵活组合的 DRY 组件。 标签提供了显示视图函数从数据库传递的数据的基本功能。 如果做得好,这种方法可以提高网站的速度、SEO 功能、安全性和可用性,并且是 Django 和类似框架编程的核心方面。

如果您还没有这样做,请查看示例应用程序并尝试使用完整列表添加您自己的标签和过滤器。

Django Highlights 是一个介绍 Django 中 Web 开发的重要概念的系列。 每篇文章都是作为 Django 开发方面的独立指南编写的,旨在帮助前端开发人员和设计人员更深入地了解代码库的“另一半”。 这些文章主要是为了帮助您了解理论和约定,但包含一些代码示例,这些示例是用 Django 3.0 编写的。

该系列的先前部分

  • Django 亮点:用户模型和身份验证(第 1 部分)
  • Django 亮点:模型、管理和利用关系数据库(第 3 部分)
  • Django 亮点:处理静态资产和媒体文件(第 4 部分)