赵走x博客
网站访问量:151903
首页
书籍
软件
工具
古诗词
搜索
登录
17、部署 Django 项目
16、自动化测试
14、jQuery 和 Django
13、Webhose 搜索
12、集成 Bootstrap
11、使用 Django-Registration-Redux
10、cookie 和会话
9、用户身份验证
8、模板进阶
7、表单
6、模型、模板和视图
5、模型与数据库
4、模板和媒体文件
3、Django 基础
2、前期准备工作
1、导言
4、模板和媒体文件
资源编号:76307
Tango with Django
Python Web
热度:79
本章介绍 Django 的模板引擎,并说明如何在应用中伺服静态文件和媒体文件。
本章介绍 Django 的模板引擎,并说明如何在应用中伺服静态文件和媒体文件。 # 4.1 使用模板 目前,我们只把一个 URL 映射到一个视图上。然而,Django 框架采用的是“模型-视图-模板”架 构。这一节说明模板与视图的关系,后面几章再讨论如何与模型联系起来。 为什么使用模板?网站中的不同页面通常使用相同的布局,提供通用的页头(header)和页脚 (footer),为用户呈现导航,体现一种一致性。Django 模板能让开发者轻易实现这样的设计要 求,而且还能把应用逻辑(视图代码)与表现(应用的外观)区分开。本章将创建一个简单的模 板,用于生成 HTML 页面,交由 Django 视图调度。第 5 章将更近一步,结合模型动态分发数 据。 >总结:模板是什么? Django 的模板可以理解为构建完整的 HTML 页面所需的骨架。模板中有静态内容(不变的 部分),也有特殊的句法(动态内容,即模板标签)。Django 视图会把动态内容替换成真正 的数据,生成最终的 HTML 响应。 ### 配置模板目录 若想在 Django 应用中使用模板,要创建两个目录,用于存放模板文件。 在 Django 项目配置目录(`
/tango_with_django_project/`)中创建一个名为 templates 的 目录。注意,这个目录要与项目的 manage.py 脚本放在同一级。在这个新目录中再创建一个目录,名为 rango。我们将在 `
/tango_with_django_project/templates/rango/` 目录中存放 Rango 应用的模板。 >以合理的方式组织模板 建议把各应用的模板放在单独的子目录中。这就是我们在 templates 目录中创建 rango 子目录 的原因。如果想打包应用,把它分发给其他开发者,这样就便于区分模板属于哪个应用。 接下来要告诉 Django 你把模板放在什么位置。打开项目的 settings.py 文件,找到 TEMPLATES。如 果项目是使用 Django 1.9 创建的,TEMPLATES 的默认内容如下: ``` TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, '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', ], }, }, ] ``` 为了告诉 Django,模板在何处,我们要修改 DIRS 列表(默认为空)。把这个键值对改成下面这 样: ``` 'DIRS': ['
/tango_with_django_project/templates'] ``` 注意,这里要使用绝对路径(absolute path)。然而,与团队成员协作,或者换台电脑的话,这就 是个问题了。用户名和磁盘结构变了,
目录的路径也就不一样了。这个问题的一种解 决方法是列出每个可能的路径,例如: ``` 'DIRS': [ '/Users/leifos/templates', '/Users/maxwelld90/templates', '/Users/davidm/templates', ] ``` 可是这样做也有诸多问题。首先,每增加一个团队成员就要增加一个路径。其次,如果换成其他 操作系统(例如 Windows),斜线可能都要换种形式。 >不要硬编码路径 [硬编码](http://en.wikipedia.org/wiki/Hard_coding "硬编码")路径是自找麻烦。硬编码路径是软件工程的一种[反模式](http://sourcemaking.com/antipatterns "反模式"),会导致项目不易移植,也就 是说在一台电脑中运行好好的,换台设备可能就会出错。 ### 动态路径 更好的方法是使用 Python 内置的函数自动找出 templates 目录的路径。这样无论你把 Django 项目 的代码放在何处,最终都能得到一个绝对路径。因此,项目的可移植性更高。 settings.py 文件的顶部有个名为 BASE_DIR 的变量,它的值是 settings.py 文件所在目录的路径。这 里用到了 Python 的特殊属性` __file__`,它的值是所在文件的绝对路径。调用 `os.path.dirname()` 的作用是获取 settings.py 文件所在目录的绝对路径,再调用一次 `os.path.dirname() `又去掉一层, 因此 BASE_DIR 最终的值是 `
/tango_with_django_project/`。如果你还不太理解这个过 程,可以把下面几行代码放到 settings.py 文件中: ``` print(__file__) print(os.path.dirname(__file__)) print(os.path.dirname(os.path.dirname(__file__))) ``` 有了 BASE_DIR 之后,我们便可以轻易引用 Django 项目中的文件和目录。我们可以定义一个名为 TEMPLATE_DIR 的变量,指向 templates 目录的位置。这里还要使用 os.path.join() 函数拼接多个 路径片段。TEMPLATE_DIR 变量的定义如下: ``` TEMPLATE_DIR = os.path.join(BASE_DIR, 'templates') ``` 我们使用 os.path.join() 函数把 BASE_DIR 变量和 'templates' 字符串拼接起来,得到 `
/tango_with_django_project/templates/`。如此一来,我们便可以使用 TEMPLATE_DIR 变量替代前面在 TEMPLATES 中硬编码的路径。把 DIRS 键值对改成下面这样: ``` 'DIRS': [TEMPLATE_DIR, ] ``` >拼接路径 拼接系统路径时一定要使用 os.path.join() 函数,这样为的是使用正确的路径分隔符。Unix 操作系统(及其衍生系统)使用正斜线(/)分隔目录,而 Windows 操作系统使用反斜线 (\)。如果直接使用斜线,更换操作系统后可能导致路径错误,从而降低项目的可移植 性。 ### 添加一个模板 模板目录和路径设置好之后,在 templates/rango/ 目录中创建一个文件,命名为 index.html。在这 个新文件中写入下述 HTML 代码。 ```
Rango
Rango says...
hey the partner!
{{ boldmessage }}
About
``` 这段 HTML 代码很好理解,最终得到的 HTML 页面将向用户打个招呼。你可能注意到了,这里 有些内容不是 HTML,而是 {{ boldmessage }} 形式。这是 Django 模板变量。我们可以为这样的 变量设值,这样渲染模板后便会显示我们设定的值。稍后再做。 为了使用这个模板,我们要调整一下前面编写的 index() 视图,不再分发一个简单的响应对象, 而是分发这个模板。 打开 rango/views.py 文件,看看文件顶部有没有下面这个 import 语句。如果没有,加上。 ``` from django.shortcuts import render ``` 然后根据下述代码片段修改 index() 视图函数。各行代码的作用参见注释。 ``` def index(request): # 构建一个字典,作为上下文传给模板引擎 # 注意,boldmessage 键对应于模板中的 {{ boldmessage }} context_dict = { 'boldmessage': 'Crunchy, creamy, cookie, candy, cupcake!' } # 返回一个渲染后的响应发给客户端 # 为了方便,我们使用的是 render 函数的简短形式 # 注意,第二个参数是我们想使用的模板 return render(request, 'rango/index.html', context=context_dict) ``` 首先,构建一个字典,设定要传给模板的数据。然后,调用 render() 辅助函数。这个函数的参数 是 request 对象、模板的文件名和上下文字典。render() 函数将把上下文字典中的数据代入模 板,生成一个完整的 HTML 页面,作为 HttpResponse 对象返回,分发给 Web 浏览器。 >模板上下文是什么? Django 的模板系统加载模板文件时会创建一个模板上下文。简单而言,模板上下文是一个 Python 字典,把模板变量名映射到值上。在前面的模板中,有个名为 boldmessage 的模板变 量。在修改后的 index() 视图中,我们把 Crunchy, creamy, cookie, candy, cupcake! 字符 串赋给模板变量 boldmessage。这样,渲染模板时,模板中的 {{ boldmessage }} 将会替换为 字符串 Crunchy, creamy, cookie, candy, cupcake!。 我们已经更新视图,用上了模板。现在启动 Django 开发服务器,然后访问 http://127.0.0.1:8000/ rango/ 。你应该能看到这个简单的 HTML 模板渲染出来了,如图 4-1 所示。  图 4-1:一切正常时应该看到的页面。注意加粗的文本,即“Crunchy, creamy, cookie, candy,cupcake!”,它们取自视图,通过模板渲染出来。 如果没看到上述页面,读一下错误消息,看看是什么地方出错了,再次确认前面所做的改动。常 见的问题之一是,settings.py 文件中的模板路径设置的不对。可以在 settings.py 文件中使用 print 语句输出 BASE_DIR 和 TEMPLATE_DIR 的值,确认一切是否正常。 这个示例演示了如何在视图中使用模板。然而,我们只用了 Django 模板引擎丰富功能中的一点皮 毛。本书后文还将使用更复杂的模板功能。如果想深入了解模板,请阅读[ Django 文档](https://docs.djangoproject.com/en/1.9/ref/templates/ " Django 文档")。 # 4.2 伺服静态文件 尽管我们用上了模板,但是不得不承认,Rango 应用现在还有点简陋,没有样式也没有图像装 饰。为了改善这种状况,我们可以在 HTML 模板中引用其他文件,例如层叠样式表(Cascading Style Sheet,CSS)、JavaScript 和图像。这些是静态文件(static file),因为它们不是由 Web 服 务器动态生成的,而是原封不动发给 Web 浏览器。本节说明 Django 伺服静态文件的方式,以及 如何在模板中添加一个图像。 ### 配置静态文件目录 首先要指定一个目录,用于存放静态文件。在项目配置目录中新建一个目录,名为 static,然后在static 目录中再新建一个目录,名为 images。确保 static 目录与前面创建的 templates 目录位于同一 级。 然后,在 images 目录中放一个图像。如下图所示,我们选择的是动画电影《兰戈》中变色龙兰戈 的图片。  图 4-2:把变色龙兰戈的图片放到 static/images 目录中 与前面的 templates 目录一样,我们要告诉 Django 这个 static 目录的路径。为此,还要编辑项目的 settings.py 模块。在这个文件中,我们要定义一个变量,指向 static 目录,并在一个数据结构中告 诉 Django 这个目录的路径。 首先,在 settings.py 文件的顶部定义一个变量,名为 STATIC_DIR。为了把所有路径放在一起,可 以把 STATIC_DIR 放在 BASE_DIR 和 TEMPLATES_DIR 下面。STATIC_DIR 的值也应该使用前面用过的 os.path.join,不过这一次是指向 static 目录,如下所示: ``` STATIC_DIR = os.path.join(BASE_DIR, 'static') ``` 这样得到的是一个绝对路径,指向`
/tango_with_django_project/static/`。定义好这个变 量之后,还要创建一个数据结构,名为 STATICFILES_DIRS。这个数据结构的值是一系列路径,让 Django 在其中寻找要伺服的静态文件。默认情况下,settings.py 文件中没有这个列表。在创建之 前,确认这个列表确实不存在。如果定义两次,Django 会混淆的,你自己也是一样。 本书只在一个位置存放项目的静态文件,即 STATIC_DIR 定义的路径。因此,我们可以像下面这样设置 STATICFILES_DIRS: ``` STATICFILES_DIRS = [STATIC_DIR, ] ``` >保持 settings.py 整洁有序 最好保持 settings.py 模块整洁有序。不要随意乱放,要有组织。把定义目录位置的变量放在 模块的顶部,这样便于查找。把 STATICFILES_DIRS 放在与静态文件相关的那部分(靠近底 部)。这样对你和其他协作者来说都方便。 最后,检查 settings.py 模块中有没有定义 STATIC_URL 变量。如果没有,像下面那样定义。注意, Django 1.9 默认把这个变量放在靠近底部的位置,因此你可能要向下拉滚动条才能找到。 ``` STATIC_URL = '/static/' ``` 我们做了这么多,还没说为什么要这么做。简单来说,STATIC_DIR 和 STATICFILES_DIRS 两个变量 设定静态文件在电脑中的位置;STATIC_URL 变量则指定启动 Django 开发服务器后通过什么 URL 访问静态文件。例如,把 STATIC_URL 设为 /static/ 后,我们可以通过 http://127.0.0.1:8000/static/ 访问里面的静态内容。前两个变量相当于服务器端的位置,而第三个变量是客户端访问静态内容 的位置。 >测试配置 现在,请测试一下一切是否配置正确。启动 Django 开发服务器,在浏览器中访问 rango.jpg 图像试试。如果把 STATIC_URL 设为 /static/,而 rango.jpg 的位置是 images/rango.jpg,在 Web 浏览器中输入 URL: ``` http://127.0.0.1:8000/static/images/rango.jpg ``` 设置 STATIC_URL 时,确保 URL 的末尾有一个正斜线(例如,是 /static/,而不是 /static)。根据 Django 文档,缺少末尾的斜线会导致一系列问题。在末尾加上斜线的目的 是把 URL 的根部(例如 /static/)与要伺服的静态内容(例如 images/rango.jpg)区分开。 ### 在模板中引用静态文件 我们已经做好设置,Django 项目能处理静态文件了。现在可以在模板中利用静态文件改进外观及 增添功能了。 下面说明如何引用静态文件。打开 `
/templates/rango/` 目录中的 index.html 模板,参照 下述代码修改。为了方便查找,新增的行旁边有注释。 ``` {% load staticfiles %}
Rango
Rango says...
hey the partner!
{{ boldmessage }}
About
``` 新增的第一行({% load staticfiles %})告诉 Django 模板引擎,我们将在模板中使用静态文 件。这样便可以在模板中使用 static 模板标签引入静态目录中的文件。static "images/ rango.jpg" 告诉 Django,我们想显示静态目录中名为 images/rango.jpg 的图像。static 标签会在 images/rango.jpg 前加上 STATIC_URL 指定的 URL,得到 /static/images/rango.jpg。Django 模板引擎 生成的 HTML 如下: ```
``` 建议为图像设定替代文本,以防图片由于某些原因无法加载。替代文本通过 img 标签的 alt 属性 指定,效果如下。  图 4-3:找不到图像时显示 alt 属性的值 修改视图之后,启动 Django 开发服务器,然后访问 http://127.0.0.1:8000/rango 。如果一切正常, 应该会看到类似图 4-4 中的网页。  >模板中的 HTML 模板的第一行始终是 [DOCTYPE 声明](http://www.w3schools.com/tags/tag_doctype.asp "DOCTYPE 声明")。如果把 {% load staticfiles %} 放在前面,渲染 得到的 HTML 中,DOCTYPE 声明前面将出现空白。多出的空白会导致 HTML 标记无法通过[验 证](https://validator.w3.org/ "验 证")。 ### 加载其他静态文件 只要想在模板中引用静态文件,就可以使用 {% static %} 模板标签。下述代码片段说明如何 在模板中引入 JavaScript、CSS 和图像。 ``` {% load staticfiles %}
Rango
``` 显然,static 目录中要有你引用的静态文件。如果引用的文件不存在,或者未正确引用, Django 开发服务器在控制台中的输出将报告 HTTP 404 错误。你可以引用一个不存在的文件 试试。注意下述输出中的最后一条,HTTP 状态码是 404。 ``` [10/Apr/2016 15:12:48] "GET /rango/ HTTP/1.1" 200 374 [10/Apr/2016 15:12:48] "GET /static/images/rango.jpg HTTP/1.1" 304 0 [10/Apr/2016 15:12:52] "GET /static/images/not-here.jpg HTTP/1.1" 404 0 ``` 如果想深入了解引入静态文件的方式,请阅读 [Django 文档](https://docs.djangoproject.com/en/1.9/howto/static-files/#staticfiles-in-templates "Django 文档")。 # 4.3 伺服媒体文件 应用中的静态文件可以理解为不变的文件。不过,有时还要使用可变的媒体文件(media file)。 这类文件可由用户或管理员上传,因此可能会变化。比如说,用户的头像就是媒体文件,电商网 站中的商品图片也是媒体文件。 为了能伺服媒体文件,我们要修改 Django 项目的设置。这一节说明具体需要做哪些设置,但暂不 测试,等到实现用户上传头像功能时再做检查。 >伺服媒体文件 与静态文件一样,在 Django 开发环境中也能检查设置是否正确。当然,开发环境中伺服媒 体文件的方法极其不适合在生产环境中使用,因此部署后应该寻找其他方式托管应用的媒体 文件。详情参见第 18 章。 ### 修改 settings.py 首先,打开 Django 项目配置目录中的 settings.py 模块。我们将在这个文件中添加一些内容。与静 态文件一样,媒体文件也放在文件系统中专门的一个目录中。因此,要告诉 Django 这个目录的位 置。 在 settings.py 模块的顶部,找到 BASE_DIR、TEMPLATE_DIR 和 STATIC_DIR 变量。在它们后面加上 MEDIA_DIR: ``` MEDIA_DIR = os.path.join(BASE_DIR, 'media') ``` 这一行告诉 Django,媒体文件将上传到 Django 项目根目录中的 media 目录里,即 `
/tango_with_django_project/media/`。正如前文所说,把路径相关的变量放在 settings.py 模块 的顶部便于以后修改。 然后在 settings.py 中找个地方添加两个变量:MEDIA_ROOT 和 MEDIA_URL。Django 伺服媒体文件时会 用到这两个变量。 ``` MEDIA_ROOT = MEDIA_DIR MEDIA_URL = '/media/' ``` >同样,别忘了斜线 与 STATIC_URL 变量一样,MEDIA_URL 变量的末尾要有一条正斜线(例如,是 /media/,而不 是 /media)。在末尾加上斜线的目的是把 URL 的根部(例如 /media/)与用户上传的内容区 分开。 MEDIA_ROOT 变量告诉 Django 在哪里寻找上传的媒体文件,MEDIA_URL 变量则指明通过什么 URL 伺 服媒体文件。这样设置之后,上传的 cat.jpg 文件在 Django 开发服务器中将通过 http://localhost:8000/media/cat.jpg 访问。 后面在模板中引入上传的内容时,如果能方便引用 MEDIA_URL 路径就好了。为了方便这样的操 作,Django 提供了模板上下文处理器。严格来说,现在无需这么做,但是趁机加上也没关系。 找到 settings.py 文件中的 TEMPLATES 列表,里面嵌套着 context_processors 列表。在 context_processors 列表中添加一个处理器,django.template.context_processors.media。添加 之后,context_processors 列表应该类似下面这样: ``` 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'django.template.context_processors.media' ], ``` ### 调整 URL 在开发环境中伺服媒体文件的最后一步是,让 Django 使用 MEDIA_URL 伺服媒体内容。打开项目的 urls.py 模块,修改 urlpatterns 列表,调用 static() 函数: ``` urlpatterns = [ ... ... ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ``` 此外,还要在 urls.py 模块的顶部添加下述 import 语句: ``` from django.conf import settings from django.conf.urls.static import static ``` 现在可以通过 /media/ URL 访问 media 目录中的媒体文件了。 # 4.4 基本流程 至此,你应该知道如何设置和创建模板,知道如何在视图中使用模板,知道如何设置并让 Django 开发服务器伺服静态媒体文件,以及如何在模板中引入图像了。本章的知识可不少! 本章的重点是知道如何创建模板,并在 Django 视图中使用模板。这其中涉及好几步,不过多做几 次就会习惯的。 ➊ 首先,创建要使用的模板,保存到 templates 目录中(在项目的 settings.py 模块中设定)。 模板中可以使用 Django 模板变量(例如 {{ variable_name }})或模板标签。模板变量的 值在相应的视图中设定。 ➋ 在应用的 views.py 文件中找到所需的视图,或者新建一个。 ➌ 把视图相关的逻辑写在视图函数中。例如,从数据库中检索数据,存到列表中。 ➍ 在视图中构建一个字典,通过模板上下文传给模板引擎。 ➎ 使用 render() 辅助函数生成响应。这个函数的参数是请求对象、模板文件名和上下文字 典。 ➏ 如果还没把视图映射到 URL 上,修改项目的 urls.py 文件和应用的 urls.py 文件。 在网页中引入静态文件的步骤也很重要,应该熟练掌握。具体方法参见下述步骤。 ➊ 把想用的静态文件放到项目的 static 目录中。这个目录在项目的 settings.py 模块中的 STATICFILES_DIRS 列表中设定。 ➋ 在模板中引用静态文件。例如,图像通过
标签插入 HTML 页面。 ➌ 记得在模板中加上 {% load staticfiles %},然后使用 {% static "
" %} 标签引用静态文件。把
替换成图像或其他资源的路径。只要想引用静态文件,使用static 模板标签。 伺服媒体文件的步骤与伺服静态文件差不多。 ➊ 把媒体文件放到项目的 media 目录中。这个目录由项目的 settings.py 模块中的 MEDIA_ROOT 变量设定。 ➋ 在模板中使用 {{ MEDIA_URL }} 上下文变量引用媒体文件。例如,引用上传的图像 cat.jpg:`
`。 >静态文件 vs. 媒体文件 从名称可以看出,静态文件是不变的,是网站的核心构成组件。而媒体文件是用户提供的, 时常变化。 样式表是静态文件,定义网页的外观。而用户的头像是媒体文件,用户在注册账户时上传。