学习Tango with django(4)

模板和媒体文件

在这个章节中,我们将介绍django的模板引擎,同时还展示了如何处理静态文件和媒体文件,它们都会集成到你的应用网页上去。

使用模板

知道目前为止,我们仅仅将URL映射到一个视图,但是django框架是基于模型-视图-模板的。在这一章节,我们将会了解模板在视图中运行的原理,在接下来几个章节,我们将会把模型也加进来一起讲解。
为什么要用模板?一个网站里很多页面的布局经常都是一样的。网站页面上经常能看见同样的页头页脚,或者帮助用户导航的重复页面,都能加强页面的紧凑性和连贯性。django提供模板让开发者更容易的实现这样的设计目标,同时将页面的设计从应用的代码逻辑分离出来。在这个章节,你将会创建一个基础模板用来创建HTML页面,这个模板由django视图调度。在数据库和模型章节,我们将会进一步讨论使用模板和模型调用动态的生成数据。

总结:模板是什么?
在django世界里,可以把模板理解为构造一个完整的HTML页面所需要的架子。一个模板可以包括页面的静态部分(从不改变的部分),还包含了一些特殊的语法(或者模板标签),比如可以覆盖或者替换django应用视图里替换的动态内容,生成最终的HTML页面。

配置模板目录

为了让模板能正常的在django应用里运行起来,你需要创建一个目录用来存放模板文件。
在你的的django项目目录里(如<workspace>/tango_with_django_project/),创建一个叫templates的目录。在这个新目录里,创建一个叫rango的目录。也就是说,路径<workspace>/tango_with_django_project/templates/rango/是用来存放rango应用模板的地方。

让模板存放有序
把每个应用的模板分开分别存放到子目录中去是非常好的应用实践,所以我们在templates里创建了rango目录。如果你将你的应用打包发布给其他开发者,这样做也能一目了然的看出来哪个模板属于哪个应用。
为了让django知道templates存放在哪儿,需要打开settings.py进行设置。首先定位到TEMPLATES数据结构,django1.9版本默认如下所示:

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',
            ],
        },
    },
]

我们要做的就是修改DIR列表让django知道我们的模板存放在什么地方,DIR列表通常默认为空。如下所示修改DIR内容:

'DIRS': ['<workspace>/tango_with_django_project/templates']

这里注意下你需要使用绝对路径定位模板目录,如果你是同团队成员一起开发,或者用多台电脑开发,使用绝对路径就会有问题。不同的环境就有不同的用户名和不同的文件系统,也就意味着路径中的<workspace>不尽相同。一种解决方法就是为每种不同的配置增加一个路径。比如:

'DIRS': [ '/Users/leifos/templates',
        '/Users/maxwelld90/templates',
        '/Users/clueless_noob/templates', ]

但是这样做会产生更多的问题。首先你每次都需要为每个设置增加一条路径,其次如果你在不同的操作系统中运行,反斜杠也要对应的进行不同的处理。

不要硬编码路径
使用硬编码将会让你通往地狱之路。硬编码路径是软件工程的反面模式,会让你的项目无法移植。也就是说当你将你的应用移植到另外一台电脑上运行,很可能会运行不成功。

动态路径

更好的解决方法是使用python内置的函数自动的生成模板目录路径。这样就能获取到绝对路径了,而不是从django的项目代码中获取了。这样你的项目也就变得更加可移植了。
在一开始的settings.py文件里,定义了一个叫BASE_DIR的变量。这个变量存储着包含项目settings.py文件所在目录的路径。通过python的内置属性__file__可以获得文件所在目录路径,这样就获得了settings.py文件的绝对路径。接下来调用os.path.dirname()获取settings.py所在目录的绝对路径。再次调用os.path.dirname()获取settings.py所在目录的上一层目录,这样BASE_DIR就变成<workspace>/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的变量,用来存储新的模板路径。我们可以使用os.path.join()函数将多个路径组合成一个路径,如下面的例子所示定义此变量:

TEMPLATE_DIR = os.path.join(BASE_DIR, 'templates')

这里我们用了os.path.join()把变量BASE_DIR和’templates’组合在一起,最终结果是<workspace>/tango_with_django_project/templates/。现在我们可以用我们新定义的TEMPLATE_DIR变量去替换之前在TEMPLATES里定义的硬编码路径,如下所示更新DIR值。

'DIRS': [TEMPLATE_DIR, ]

为什么要用TEMPLATE_DIR
你已经在setting.py文件的一开始就创建了一个叫TEMPLATE_DIR的新变量,因为它更容易访问也更容易修改。对于比较复杂的django项目,DIR列表需要指定不止一个模板目录。但就我们这本书而言,一个目录就已经足够让项目运行起来了。
路径连接
当连接系统路径时,一般都使用os.path.join(),使用这个内置的python函数能保证路径的分隔符是正确的。在UNIX操作系统(或者其分支),路径分隔符使用正斜杠(/),而windows操作系统使用反斜杠(\)。如果你手动添加斜杠到你的路径里,在你将你的代码移植到另外一个操作系统运行的时候就会遇到路径错误,最终会降低项目的可移植性。

增加一个模板

当你的模板目录和路径设置好后,创建一个叫index.html的文件并将其放到templates/rango目录里,在这个新文件里,添加如下代码:

<!DOCTYPE html>
<html>
    <head>
    <title>Rango</title>
    </head>
    <body>
        <h1>Rango says...</h1>
        <div>
            hey there partner! <br />
            <strong>{{ boldmessage }}</strong><br />
        </div>
        <div>
            <a href="/rango/about/">About</a><br />
        </div>
    </body>
</html>

通过上面的HTML代码,可以很清楚的知道这个页面的会生成与用户打招呼的信息。你也许会注意到非HTML元素{{ boldmessage }},这个是django模板变量。我们可以设置这些变量的值,这样在模板渲染的时候就可以替换成我们想要的数据,这个模块我们过会儿再介绍。
使用模板前我们需要重新配置之前创建的index()视图,这次我们将修改视图去调用我们的模板而不是简单的返回一个结果。
在rango/views.py文件里,检查文件一开始是否有如下的import语句,如果没有的话就增加一条。

from django.shortcuts import render

你可以像下面一样更新index视图函数,看一下函数中写的注释了解每一行都做了什么。

def index(request):
    # Construct a dictionary to pass to the template engine as its context.
    # Note the key boldmessage is the same as {{ boldmessage }} in the template!
    context_dict = {'boldmessage': "Crunchy, creamy, cookie, candy, cupcake!"}
    # Return a rendered response to send to the client.
    # We make use of the shortcut function to make our lives easier.
    # Note that the first parameter is the template we wish to use.
    return render(request, 'rango/index.html', context=context_dict)

首先我们构建了一个键值对字典用来在模板中使用,然后我们调用了render()函数,这个函数以用户请求,模板名称,上下文字典作为参数。render()函数会将这些数据与模板融合生成一个完整的页面并作为HttpResponse返回。这个响应结果就返回至用户的浏览器中。

什么是模板上下文?
当一个模板文件使用django的模板系统加载时,一个模板上下文就会被创建。一般来说,一个模板上下文就是一个python字典,将模板变量映射成python变量。在我们上面创建的模板文件中,我们编写了一个叫boldmessage的模板变量,在我们更新过的index视图函数中,字符串Crunchy, creamy, cookie, candy, cupcake!映射到boldmessage模板变量。因此字符串Crunchy, creamy, cookie, candy, cupcake!将会替换模板中的任何boldmessage对象。
既然你已经在视图函数中调用了你的模板,现在就启动开发服务器并访问http://127.0.0.1:8000/rango/。你应该能看到一个简单经过渲染的HTML页面,如下所示:

这里写图片描述
当你的模板正常工作时你应该能看到如上信息,注意加粗的文本Crunchy, creamy, cookie, candy, cupcake!,是视图渲染到模板的。

如果报错了,阅读错误信息检查一下是什么问题,并再一次检查你做的修改。最普遍发生的其中一个问题就是你的模板路径在settings.py中配置的不正确。有时候你可能需要在settings.py中添加一个print语句来打印BASE_DIR和TEMPLATE_DIR检查一下配置是否正确。
这个例子演示了在视图中如何使用模板,但是我们仅仅触及了django模板引擎的一小部分功能。随着对这本书学习的深入,我们将会使用越来越复杂的模板,同时你可以在django官方文档中获取更多关于模板的知识。

处理静态媒体文件

尽管你的模板已经能正常工作了,但是不得不承认你的rango应用看起来太朴素了-页面中没有样式和图片。我们可以在我们的模板中添加到其它文件的引用,比如增加一些CSS,javascript或者图像来改善页面效果。这些文件被称为静态文件,因为它们不需要web服务器动态的生成,它们只是简单的发送到客户端就可以了。这一节讲解了如何配置django来处理静态文件和如何将图像包含到你的模板上去。

配置静态媒体目录

开始之前,你需要创建一个目录用来存放静态媒体文件。在你的项目目录下(比如<workspace>/tango_with_django_project/),创建一个新的目录叫static,同时在static里创建一个新的目录叫images。检查一下static目录是和你之前创建的templates目录在同一层的。接下来放一张图片到images目录里,如下所示我们选择了一张图片,一个合适的吉祥物。

图略

就像之前我们创建模板路径一样,我们同样需要告诉django我们的static目录在哪儿。因此我们需要再次打开settings.py文件,并设置一个新的变量值指向static路径,使用django可解析的数据结构来找到static目录的位置。
首先,在settings.py开始的地方创建名为 STATIC_DIR的变量,最好就把这个路径放在BASE_DIR和TEMPLATES_DIR的下面。 STATIC_DIR也应该调用os.path.join,但这次是指向static,如下所示:

STATIC_DIR = os.path.join(BASE_DIR, 'static')

这个值将生成一个绝对路径,定位到<workspace>/tango_with_django_project/static/。这个变量创建好了后,我们还需要再创建一个叫STATICFILES_DIRS的数据结构。基本上django通过这些路径列表就能找到可以提供服务的静态文件了。默认情况下,这个列表是不存在的,因此在创建之前先检查下是否已经存在了。如果你创建了两次,django会迷惑了,你也会迷惑。
对这本书来说,我们只使用了一个路径来存储我们的静态文件,因此我们可以将STATICFILES_DIRS设置成如下所示:

STATICFILES_DIRS = [STATIC_DIR, ]

保持setting.py优雅
你应该尽可能让setting.py保持优雅和好的顺序。不要把语句随便写在一个地方,要有组织的编写。让你的DIR变量放在模块的一开始的地方,这样方便查找。将STATICFILES_DIRS放到负责配置静态媒体文件的那块(靠近底部)。当你之后回过头在编辑这个文件时,你或者你的合作者都会很容易就找到需要的变量。

最后,在setting.py文件中检查STATIC_URL变量是否定义,如果没定义,如下所示定义一下。注意在django1.9中这个变量是定义在文件的最底部,所以你得拖到最下面找下。

STATIC_URL = '/static/'

现在变量都定义好了,那么它们分别表示什么意思呢?简单点来说,一开始定义的两个变量STATIC_DIR和STATICFILES_DIRS引用了在你电脑上存放静态文件的位置,最后一个定义的变量STATIC_URL允许我们指定了一个当开发服务器运行时可以访问静态文件的URL。举例来说,当STATIC_URL设置为/static/,我们就能够以http://127.0.0.1:8000/static/访问静态内容。可以理解为,前两个变量是服务器端的位置,最后一个变量作为客户端访问的位置。

测试配置
我们做一个小练习来测试下配置的是否正确。打开开发服务器,试着看一下图片rango.jpg能否在浏览器上查看。如果STATIC_URL设置为/static/,图片rango.jpg就会被定位到image/rango.jpg,那么在浏览器上要输入什么网址才能访问到这张图片呢?
行动之前一定要先思考,越是困惑的时候答案就离你越近。

不要忘了斜杠!
设置STATIC_URL的时候,要检查一下这个URL是否以正斜杠结尾(比如/static/而不是/static)。一定要按照django官方文档来,不这么做你一定会后悔。结尾的斜杠保证了URL的根目录(如:/static/)从你要用的静态内容中(如:images/rango.jpg)分离出来。
提供静态内容
尽管在开发环境下使用开发服务器提供静态媒体文件很不错,但是在生产环境下就不合适了。django官方文档提供了更多的在生产环境部署静态的信息。这个问题我们在部署Rango的时候再进一步讨论。
如果你还没搞清楚从哪儿访问这张图片,在你的浏览器里输入这个网址:http://127.0.0.1:8000/static/images/rango.jpg

静态媒体文件和模板

既然你已经配置了让django项目来处理静态文件了,现在你就可以在模板里使用这些静态文件了,这样即改善了页面效果,还可以增加一些额外功能。
为了演示如何包含静态文件,让我们打开之前创建的index.html模板,这个模板应该位于<workspace>/templates/rango/。如下所示修改HTML源代码,增加的两行代码我们用html的注释标记了以便于查看。

<!DOCTYPE html>
{% load staticfiles %} <!-- New line -->
<html>
    <head>
    <title>Rango</title>
    </head>
    <body>
        <h1>Rango says...</h1>
        <div>
            hey there partner! <br />
            <strong>{{ boldmessage }}</strong><br />
        </div>
        <div>
            <a href="/rango/about/">About</a><br />
            <img src="{% static "images/rango.jpg" %}" alt="Picture of Rango" /> <!-- New line -->
        </div>
    </body>
</html>

第一个新增的行({% load staticfiles %})是告诉django模板引擎我们将在模板里使用静态文件。这样我们就能够通过使用模板标签static来访问静态目录里的文件。这就告诉django我们希望显示位于静态媒体目录里的images/rango.jpg图像。模板标签通过大括号标记(如:{% %})。调用static标签将会把在STATIC_URL里指定的URL和images/rango.jpg结合起来生成/static/images/rango.jpg。django模板引擎将会生成如下HTML代码:

<img src="/static/images/rango.jpg" alt="Picture of Rango" />

如果因为某些原因导致图片加载失败,为图片指定一个可选择的文本提示是个不错的主意。HTML标签img里alt属性可以提供这样的文本,结果显示如下:
这里写图片描述

rango图片未找到,由img的alt属性中定义的文本替代显示。

代码经过小范围调整后,再次启动开发服务器并打开网址http://127.0.0.1:8000/rango,如果一切正常,你应该会看到类似如下的截图。
这里写图片描述

我们的第一个rango模板,包括一个rango图片

模板和<!DOCTYPE>
创建HTML模板时,一定要保证在第一行进行DOCTYPE声明,如果你把模板命令{% load staticfiles %}放在第一行,模板渲染后在DOCTYPE前会增加一些空格,而这些空格会导致你的HTML标签验证失败。

加载另外一个静态文件
模板标签{% static %}可以在你想引用静态文件的时候就能使用,下面的代码示例演示了如何使用正确的HTML标签将你的Javascript、CSS和图像引用到模板文件中去。

<!DOCTYPE html>
{% load staticfiles %}
<html>
    <head>
        <title>Rango</title>
        <!-- CSS -->
        <link rel="stylesheet" href="{% static "css/base.css" %}" />
        <!-- JavaScript -->
        <script src="{% static "js/jquery.js" %}"></script>
    </head>

    <body>
        <!-- Image -->
        <img src="{% static "images/rango.jpg" %}" alt="Picture of Rango" />
    </body>
</html>

你引用的静态文件在静态目录里一定要存在,如果不请求的静态文件不存在或者引用不正确,django开发服务器控制台就会输出HTTP404错误。尝试引用一个不存在的文件看看会发生什么。看一下下面的输出截图,注意看最后一条HTTP状态代码是404。

这里写图片描述
想了解更多的关于django静态媒体设置,你可以阅读django官方文档。

提供媒体文件

静态媒体文件可以被认为是一种不需要改变的、一个应用的基础文件。但是实际上你经常需要动态的存储这些媒体文件。这些文件可以由你的用户或者管理员上传,所以它们也有可能改变。举个例子,一个媒体文件可能会是一个用户的配置图像。如果你要运行一个电子商务网站,你线上商店的不同产品展示就要用到一系列的媒体文件了。
为了成功使用媒体文件,我们需要更新django的项目配置。这节会详解的介绍增加的内容,但是我们现在不会对新增内容进行充分的测试,之后我们会测试用户上传图片的功能。

使用媒体文件
就像静态内容一样,django在开发环境中也提供了使用媒体文件的功能。django提供的使用媒体文件的方法在生产环境中是不合适的,所以你应该通过其它方式使用你的媒体文件,部署服务器章节会详细讨论如何配置。

修改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’,或者<workspace>/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的根目录从用户上传的路径中分离出来。
这两个变量告诉了django将上传的媒体文件存放在哪里(MEDIA_ROOT)和使用什么样的URL来使用它们(MEDIA_URL)。举个例子,根据之前定义的配置,将文件cat.jpg上传到开发服务器使用http://localhost:8000/media/cat.jpg.
我们在这本书的后面使用模板时,我们可以很方便的在我们想引用一个上传的内容时获取到MEDIA_URL的引用。django提供了模板上下文处理器,让我们很容易就能这样做了。严格来说,我们现在还不需要这给配置,但是我们先加上它。
在settings.py里找到TEMPLATES列表,并在这个列表里找到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'
],

微调urls.py

在开发环境中配置媒体文件的最后一个步骤是告诉django从MEDIA_URL使用静态文件,打开项目的urls.py文件,添加一个static()函数调用到项目的urlpatterns列表里。

urlpatterns = [
...
...
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

你还需要将下面的导入语句添加到urls.py文件的一开始

from django.conf import settings
from django.conf.urls.static import static

一旦这个完成之后,你应该就能获取到由/media/ URL中的项目媒体目录中的媒体内容了。

基本工作流程

这章学习完后,你应该知道如何创建和配置模板、在视图里使用模板、在开发环境中配置使用静态媒体文件、在模板中包含图片,这些我们都涉及到了。
创建模板并将其整合到django视图是理解django概念的关键,尽管需要不少步骤,但是经过练习后就能上手了。

  • 首先,创建模板并保存到settings.py模块中指定的templates目录,在模板中可以用到模板变量和标签,你可以在相应的视图里替换成任何你定义的内容。
  • 在一个应用的views.py里找到或者创建一个视图函数
  • 在视图函数中增加业务逻辑,比如说从数据库中抽取数据并存储到一个列表
  • 在视图函数里,构建一个字典对象传递给模板引擎,作为模板上下文
  • 使用render()函数生成渲染后的返回对象,确保你引用了请求,然后是模板文件,最后是模板上下文字典
  • 如果你还没做,修改项目的urls.py文件和应用里的urls.py将视图映射到URL上

将静态文件引用到页面上的步骤也是很重要的过程,你应该掌握它。理解下面的步骤是如何做的:

  • 将静态文件放到项目的static目录,这个目录在settings.py的STATICFILES_DIRS列表变量中指定
  • 将静态文件引用到模板上,比如使用<img/>标签将图片插入到HTML页面中
  • 在模板里访问静态文件,记住要使用{% load staticfiles %}{% static "<filename>" %}标记。将<filename>替换成你想引用的图像的路径。无论你什么时候引用静态文件,一定要使用static模板标签!

使用媒体文件的步骤和使用静态文件的步骤类似

  • 将媒体文件放到项目的media目录,这个目录在settings.py的MEDIA_ROOT变量中指定
  • 通过使用{{ MEDIA_URL }}上下文变量将媒体文件链接到模板里,比如说引用一个已上传的图片cat.jpg使用<img />标签,如<img src="{{ MEDIA_URL}}cat.jpg" />

练习
给出了下面的练习来巩固我们这节学习的内容

  • 将about页面也转换成使用模板,模板名称叫about.html
  • 在新的about.html模板里,增加一个存储在项目媒体目录里的图片
  • 在about页面里,添加一行This tutorial has been put togetherby <your-name>
  • 在你的django项目目录里,创建一个新的叫media的目录,下载一个图片命名为cat.jpg并保存在media目录里
  • 在about页面里,增加img标签展现cat图片,确保你的媒体文件能被正确访问。将Rango的静态图片放到你的主页上,以便于你的app作为例子展现静态和媒体文件

静态媒体文件
记住:静态文件,顾名思义,不会变,这些文件构成了网站的核心。媒体文件是用户定义的,也就是说,会经常变动。
一个静态文件的例子如样式文件,它定义你的应用页面的界面。一个媒体文件的例子如用户头像,它是由用户在创建账户的时候上传的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值