Django 模板
在我的上一篇文章(2015 年 2 月)中,我解释了如何创建一个简单的 Django 项目(“atfproject”)并在其中创建一个简单的应用程序(atfapp)。该应用程序的功能是,如果您访问 URL http://localhost:8000/hello/Reuven,您将得到文本“hello, Reuven”。
这归功于视图函数
def hello(request, name):
return HttpResponse("hello, {}".format(name))
以及我创建的 URL 模式
urlpatterns = patterns('',
url(r'^hello/(?P<name>\w+)$', hello),
url(r'^admin/', include(admin.site.urls)),
)
请注意,在第一个 URL 模式中,我定义了一个名为“name”的命名组,作为字母数字字符的字符串 (\w+
)。捕获的字符随后被传递给视图函数的“name”参数,这允许视图函数接受并在视图函数中显示这些值。
现在,这确实有效,但如果您认为这是一种非常笨拙的显示文本的方式,即作为视图函数中的字符串,那么您并不孤单。实际上,除了生成非常小的文本片段外,您可能永远不会直接从视图函数返回 HTML。相反,您将使用模板。
对于任何从事 Web 开发一段时间的人来说,这都不应该感到惊讶。我使用过的每个 Web 框架都有某种形式的模板。不幸的是,每个 Web 框架都使用一种独特的模板类型,以及一种新的、不同的方式来集成 HTML 和您需要呈现的各种动态内容。
因此,在本文中,我将描述 Django 模板的工作原理,允许您为用户生成动态内容。
调用模板重要的是要记住,Django 的模板是 HTML 文件,其中添加了一些额外的代码。甚至说 Django 模板中有“代码”可能有点夸张。模板语法明确旨在减少您必须编写的代码量,同时也减少在模板中执行的代码量。通过从模板中删除代码并将其放入您的视图方法(和模型)中,您可以使您的应用程序更模块化、更灵活和更易于测试。
要开始使用 Django 模板,您不需要知道任何特殊的东西。这是因为一个普通的 HTML 文件就是一个很好的 Django 模板。在“atfapp”应用程序内部,让我们创建一个名为 templates 的新子目录。这是 Django 将查找您的模板的地方。您始终可以通过设置应用程序设置中的 TEMPLATE_DIRS
变量来对此进行不同的配置。
这是一个我创建的简单模板,然后放入 atfapp/templates/hello.html 中
<!DOCTYPE html>
<html>
<head>
<h3>Hello!</h3>
</head>
<body>
<h1>Hello!</h1>
<p>Hello out there!</p>
</body>
</html>
为了让 Django 显示此模板,您需要更改您的“hello”视图函数(在您的应用程序的 views.py 中定义),以便它使用模板呈现其响应。最简单的方法是使用 render_to_response
函数,该函数在 django_shortcuts
包中定义。因此,将 views.py 更改为如下所示
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import render_to_response
def hello(request, name):
return render_to_response('hello.html')
请注意,仅调用 render_to_response
是不够的。与 Python 中的所有函数一样,您必须显式返回 render_to_response
返回给您的对象。
有了模板到位并且视图函数已更新,您现在可以重新加载 http://localhost:8000/hello/Reuven 上的应用程序。并且...好吧,您可能会看到来自 Django 的调试屏幕,告诉您未找到模板。这里的问题是,当您使用 render_to_response
时,它会在项目中所有已注册的 Django 应用程序的模板目录中查找。但是等等,您从未注册您的应用程序!因此,尽管您可以从 atfapp 中调用视图函数,但 Django 不会在 atfapp/templates 目录中查找,因为它不是已注册的应用程序。
简单的解决方案是转到主项目配置目录中的 settings.py(在本例中为 atfproject/atfproject/settings.py),找到 INSTALLED_APPS
的定义,然后在末尾添加以下行
'atfapp'
请注意,您需要在上一行的末尾添加一个逗号。
这样一来,Django 的模板系统将找到您的模板。现在访问 /hello/Reuven(或 /hello/ 下的任何其他 URL)将显示您的模板。
传递变量当然,这个基本的“hello”模板并没有真正展示 Web 应用程序的强大功能。为了实现这一点,您需要将值传递给模板,然后模板将您的值与 HTML 混合并将结果显示给用户。
因此,您需要做两件事。首先,您需要更改 render_to_response
的调用,以便它传递一个或多个变量值。如果您对 Python 有任何了解,您就不会惊讶地发现您将通过传递一个字典给 render_to_response
来完成此操作,其中键是您要传递的变量名称。例如
def hello(request, name):
return render_to_response('hello.html', {'name':name})
在此示例中,您获取通过 URL 分配的参数“name”,并将其作为字典中的值传递。键被称为“name”,我承认这可能有点令人困惑,但在这里仍然是最有意义的。
在您的模板中,Django 查找双花括号:{{ 和 }}。Django 将在这些花括号内查找,并在传递给它的字典中查找名称
<!DOCTYPE html>
<html>
<head>
<h3>Hello!</h3>
</head>
<body>
<h1>Hello!</h1>
<p>Hello, {{name}}!</p>
</body>
</html>
仅需进行这两项更改——甚至无需重启服务器——您的 URL 的内容现在会影响模板的输出。
您可以在 render_to_response
中定义的字典中传递任意数量的名称-值对。传递的值可能来自传递给视图函数的参数、数据库或远程服务器。从模板的角度来看,它只能访问传递给它的数据,并且并不真正在意其余数据来自何处。
当然,有时您可能希望有条件地显示文本。Django 模板也可以做到这一点。您可以使用 {% 和 %} 包围命令,而不是使用 {{ 和 }} 包围变量名。现在,这些不是 Python 命令,因此不要期望语法、名称或行为完全相同。此外,由于您没有 Python 的缩进块语法,因此您必须使用“endif”标记结束您的“if”条件(例如)。
鉴于这些信息,您可能可以弄清楚此模板中发生了什么
<!DOCTYPE html>
<html>
<head>
<h3>Hello!</h3>
</head>
<body>
<h1>Hello!</h1>
{% if name == 'Reuven' %}
<p>Hello, master {{name}}!</p>
{% else %}
<p>Hello, {{name}}!</p>
{% endif %}
</body>
</html>
模板获取一个参数“name”,然后将其与字符串“Reuven”进行比较。如果我是指定的人,它会打印一条消息。否则,它会打印另一条消息。
循环和过滤器前面的示例显示了当您从 URL 中获取一个值,然后想要将其传递给模板以进行显示时,会发生什么情况。传递给视图函数的参数始终将作为字符串传递。但是,没有理由您不能传递另一个数据结构,例如列表、元组或字典。如果您这样做(或者,老实说,如果您传递任何可迭代对象),您可以使用模板的循环函数,该函数的操作与 Python 的“for”运算符完全相同,但添加了一个闭合的“endfor”标记。
让我们更改视图函数,使其按如下方式工作
def hello(request, name):
return render_to_response('hello.html', {'name':name,
'children': ['Atara', 'Shikma', 'Amotz']})
如您所见,您现在要将一个 section 变量传递给您的模板,其中包含我孩子的名字。在您的模板中,您可以迭代此变量,几乎与您在非 Django、非模板 Python 程序中一样精确
<!DOCTYPE html>
<html>
<head>
<h3>Hello!</h3>
</head>
<body>
<h1>Hello!</h1>
{% if name == 'Reuven' %}
<p>Hello, master {{name}}!</p>
{% else %}
<p>Hello, {{name}}!</p>
{% endif %}
<h2>Children</h2>
<ol>
{% for child in children %}
<li>{{child}}</li>
{% endfor %}
</ol>
</body>
</html>
在此示例中,您已将 HTML 的“ol”标记与 Django 模板中的“for”循环结合使用,以提供枚举列表。由于“child”被定义为循环内的变量,因此您可以使用 {{child}} 语法来指示您希望孩子的名字出现的位置。
现在,如果您要打印名称列表,则字符串可能已全部变为小写。假设您想确保名称遵循英语语言规则,其中第一个字符大写。现在,如果您使用纯 Python,则可以使用 str.upper 方法,例如
<li>{{child|capfirst}}</li>
但是,如果您将孩子的名字更改为小写,然后将模板更改为如上所示的样子...好吧,我们只能说它不会工作。这是 Django 将可执行代码保留在模板之外的理念的一部分。考虑一下:不应该可能,或者至少不容易,让某人在您的模板中运行任意代码。
因此,如果您想将单词大写,则需要使用“过滤器”,这是 Django 对预定义函数的术语,您可以将数据传递给该函数,然后该函数将返回一个将显示的新字符串。例如,“capfirst”过滤器将单词的首字母大写
<li>{{child|capfirst}}</li>
请注意过滤变量的结构。在变量名本身之后,您使用 | 字符,然后是您要使用的过滤器的名称。Django 实际上附带了大量预定义的过滤器,也允许您编写和注册自己的过滤器。但是对于大多数日常显示需求,Django 的内置过滤器可能就足够了。
结论从 Django 中使用一个或多个模板非常容易,它采用的语法与其他许多框架不同,但仍然可行且易于理解。我在这里没有讨论的一个功能是“块”,即 HTML 区域,这些区域将被来自子模板的文本替换。通过这种方式,您可以在页面标题或 h1 中显示不同的值,但在逐页的基础上显示。我将在关于 Django 的后续文章中介绍更多内容。
但是,在我的下一篇文章中,我计划研究 Django 如何与数据库一起工作,从而创建一个真正的 CRUD(即,创建-读取-更新-删除)Web 数据库应用程序。
资源Django 的主要站点是 http://DjangoProject.com,它提供了大量优秀的文档,包括教程。关于 Python 的信息(Django 在其中实现)位于 https://pythonlang.cn。