在视图中使用模板

 

在学习了模板系统的基础之后,现在让我们使用相关知识来创建视图。 重新打开我们在前一章在 mysite.views 中创建的 current_datetime 视图。 以下是其内容:

 
 
from django.http import HttpResponse
import datetime def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)

让我们用 Django 模板系统来修改该视图。 第一步,你可能已经想到了要做下面这样的修改:

 
 
from django.template import Template, Context
from django.http import HttpResponse
import datetime def current_datetime(request):
now = datetime.datetime.now()
t = Template("<html><body>It is now {{ current_date }}.</body></html>")
html = t.render(Context({'current_date': now}))
return HttpResponse(html)

没错,它确实使用了模板系统,但是并没有解决我们在本章开头所指出的问题。 也就是说,模板仍然嵌入在Python代码里,并未真正的实现数据与表现的分离。 让我们将模板置于一个单独的文件 中,并且让视图加载该文件来解决此问题。

 
 

你可能首先考虑把模板保存在文件系统的某个位置并用 Python 内建的文件操作函数来读取文件内容。假设文件保存在/home/djangouser/templates/mytemplate.html 中的话,代码就会像下面这样:

 
 
from django.template import Template, Context
from django.http import HttpResponse
import datetime def current_datetime(request):
now = datetime.datetime.now()
# Simple way of using templates from the filesystem.
# This is BAD because it doesn't account for missing files!
fp = open('/home/djangouser/templates/mytemplate.html')
t = Template(fp.read())
fp.close()
html = t.render(Context({'current_date': now}))
return HttpResponse(html)

然而,基于以下几个原因,该方法还算不上简洁:

 
 
  • 它没有对文件丢失的情况做出处理。 如果文件 mytemplate.html 不存在或者不可读, open() 函数调用将会引发 IOError 异常。

     
     
     
     
  • 这里对模板文件的位置进行了硬编码。 如果你在每个视图函数都用该技术,就要不断复制这些模板的位置。 更不用说还要带来大量的输入工作!

     
     
     
     
  • 它包含了大量令人生厌的重复代码。 与其在每次加载模板时都调用 open()fp.read()fp.close() ,还不如做出更佳选择。

     
     
     
     

为了解决这些问题,我们采用了 模板自加载模板目录 的技巧.

 
 

模板加载

 

为了减少模板加载调用过程及模板本身的冗余代码,Django 提供了一种使用方便且功能强大的 API ,用于从磁盘中加载模板,

 
 

要使用此模板加载API,首先你必须将模板的保存位置告诉框架。 设置的保存文件就是我们前一章节讲述ROOT_URLCONF配置的时候提到的settings.py

 
 

如果你是一步步跟随我们学习过来的,马上打开你的settings.py配置文件,找到TEMPLATE_DIRS这项设置吧。 它的默认设置是一个空元组(tuple),加上一些自动生成的注释。

 
 
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)

该设置告诉 Django 的模板加载机制在哪里查找模板。 选择一个目录用于存放模板并将其添加到 TEMPLATE_DIRS 中:

 
 
TEMPLATE_DIRS = (
'/home/django/mysite/templates',
)

下面是一些注意事项:

 
 

你可以任意指定想要的目录,只要运行 Web 服务器的用户可以读取该目录的子目录和模板文件。 如果实在想不出合适的位置来放置模板,我们建议在 Django 项目中创建一个templates 目录(也就是说,如果你一直都按本书的范例操作的话,在第二章创建的mysite 目录中)。

3
 

如果你的 TEMPLATE_DIRS只包含一个目录,别忘了在该目录后加上个逗号。

 
 

Bad:

 
 
# Missing comma!
TEMPLATE_DIRS = (
'/home/django/mysite/templates'
)

Good:

 
 
# Comma correctly in place.
TEMPLATE_DIRS = (
'/home/django/mysite/templates',
)

Python 要求单元素元组中必须使用逗号,以此消除与圆括号表达式之间的歧义。 这是新手常犯的错误。

 
 

如果使用的是 Windows 平台,请包含驱动器符号并使用Unix风格的斜杠(/)而不是反斜杠(),就像下面这样:

3
 
TEMPLATE_DIRS = (
'C:/www/django/templates',
)

最省事的方式是使用绝对路径(即从文件系统根目录开始的目录路径)。 如果想要更灵活一点并减少一些负面干扰,可利用 Django 配置文件就是 Python 代码这一点来动态构建TEMPLATE_DIRS 的内容,如: 例如:

2
 
import os.path

TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)

这个例子使用了神奇的 Python 内部变量 __file__ ,该变量被自动设置为代码所在的 Python 模块文件名。 `` os.path.dirname(__file__)`` 将会获取自身所在的文件,即settings.py 所在的目录,然后由os.path.join 这个方法将这目录与templates 进行连接。如果在windows下,它会智能地选择正确的后向斜杠”“进行连接,而不是前向斜杠”/”。

6
 

在这里我们面对的是动态语言python代码,我需要提醒你的是,不要在你的设置文件里写入错误的代码,这很重要。 如果你在这里引入了语法错误,或运行错误,你的Django-powered站点将很可能就要被崩溃掉。

 
 

完成 TEMPLATE_DIRS 设置后,下一步就是修改视图代码,让它使用 Django 模板加载功能而不是对模板路径硬编码。 返回current_datetime 视图,进行如下修改:

 
 
from django.template.loader import get_template
from django.template import Context
from django.http import HttpResponse
import datetime def current_datetime(request):
now = datetime.datetime.now()
t = get_template('current_datetime.html')
html = t.render(Context({'current_date': now}))
return HttpResponse(html)

此范例中,我们使用了函数 django.template.loader.get_template() ,而不是手动从文件系统加载模板。 该get_template() 函数以模板名称为参数,在文件系统中找出模块的位置,打开文件并返回一个编译好的Template 对象。

1
 

在这个例子里,我们选择的模板文件是current_datetime.html,但这个与.html后缀没有直接的联系。 你可以选择任意后缀的任意文件,只要是符合逻辑的都行。甚至选择没有后缀的文件也不会有问题。

2
 

要确定某个模板文件在你的系统里的位置, get_template()方法会自动为你连接已经设置的TEMPLATE_DIRS目录和你传入该法的模板名称参数。比如,你的TEMPLATE_DIRS目录设置为'/home/django/mysite/templates',上面的get_template()调用就会为你找到/home/django/mysite/templates/current_datetime.html 这样一个位置。

1
 

如果 get_template() 找不到给定名称的模板,将会引发一个TemplateDoesNotExist 异常。 要了解究竟会发生什么,让我们按照第三章内容,在 Django 项目目录中运行python manage.pyrunserver 命令,再次启动Django开发服务器。 接着,告诉你的浏览器,使其定位到指定页面以激活current_datetime视图(如http://127.0.0.1:8000/time/ )。假设你的DEBUG项设置为True,而你有没有建立current_datetime.html 这个模板文件,你会看到Django的错误提示网页,告诉你发生了TemplateDoesNotExist 错误。

1
 

图 4-1: 模板文件无法找到时,将会发送提示错误的网页给用户。

 
 

该页面与我们在第三章解释过的错误页面相似,只不过多了一块调试信息区: 模板加载器事后检查区。 该区域显示 Django 要加载哪个模板、每次尝试出错的原因(如:文件不存在等)。 当你尝试调试模板加载错误时,这些信息会非常有帮助。

5
 

接下来,在模板目录中创建包括以下模板代码 current_datetime.html 文件:

 
 
<html><body>It is now {{ current_date }}.</body></html>

在网页浏览器中刷新该页,你将会看到完整解析后的页面。

3
 

render_to_response()

 

我们已经告诉你如何载入一个模板文件,然后用 Context渲染它,最后返回这个处理好的HttpResponse对象给用户。 我们已经优化了方案,使用get_template() 方法代替繁杂的用代码来处理模板及其路径的工作。 但这仍然需要一定量的时间来敲出这些简化的代码。 这是一个普遍存在的重复苦力劳动。Django为此提供了一个捷径,让你一次性地载入某个模板文件,渲染它,然后将此作为HttpResponse返回。

1
 

该捷径就是位于 django.shortcuts 模块中名为render_to_response() 的函数。大多数情况下,你会使用``\``````对象,除非你的老板以代码行数来衡量你的工作。

6
 

System Message: WARNING/2 (<string>, line 1736);backlink

Inline literal start-string without end-string.

 
 

System Message: WARNING/2 (<string>, line 1736);backlink

Inline literal start-string without end-string.

 
 

System Message: WARNING/2 (<string>, line 1736);backlink

Inline literal start-string without end-string.

 
 

下面就是使用 render_to_response() 重新编写过的current_datetime 范例。

 
 
from django.shortcuts import render_to_response
import datetime def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('current_datetime.html', {'current_date': now})

大变样了! 让我们逐句看看代码发生的变化:

 
 
  • 我们不再需要导入 get_templateTemplateContext HttpResponse 。相反,我们导入django.shortcuts.render_to_responseimport datetime 继续保留.

     
     
     
     
  • current_datetime 函数中,我们仍然进行now 计算,但模板加载、上下文创建、模板解析和HttpResponse 创建工作均在对 render_to_response() 的调用中完成了。 由于 render_to_response() 返回 HttpResponse 对象,因此我们仅需在视图中 return 该值。

     
     
     
     

render_to_response() 的第一个参数必须是要使用的模板名称。 如果要给定第二个参数,那么该参数必须是为该模板创建Context 时所使用的字典。 如果不提供第二个参数,render_to_response() 使用一个空字典。

2
 

locals() 技巧

6

思考一下我们对 current_datetime 的最后一次赋值:

 
 
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('current_datetime.html', {'current_date': now})

很多时候,就像在这个范例中那样,你发现自己一直在计算某个变量,保存结果到变量中(比如前面代码中的 now ),然后将这些变量发送给模板。 尤其喜欢偷懒的程序员应该注意到了,不断地为临时变量临时模板命名有那么一点点多余。不仅多余,而且需要额外的输入。

 
 

如果你是个喜欢偷懒的程序员并想让代码看起来更加简明,可以利用 Python 的内建函数 locals() 。它返回的字典对所有局部变量的名称与值进行映射。 因此,前面的视图可以重写成下面这个样子:

7
 
def current_datetime(request):
current_date = datetime.datetime.now()
return render_to_response('current_datetime.html', locals())

在此,我们没有像之前那样手工指定 context 字典,而是传入了 locals() 的值,它囊括了函数执行到该时间点时所定义的一切变量。 因此,我们将 now 变量重命名为 current_date ,因为那才是模板所预期的变量名称。 在本例中,locals() 并没有带来多 的改进,但是如果有多个模板变量要界定而你又想偷懒,这种技术可以减少一些键盘输入。

7
 

使用 locals() 时要注意是它将包括 所有 的局部变量,它们可能比你想让模板访问的要多。 在前例中, locals() 还包含了 request 。对此如何取舍取决你的应用程序。

django在视图中使用模板的更多相关文章

  1. Django-1版本的路由层、Django的视图层和模板层

    一.Django-1版本的路由层(URLconf) URL配置(URLconf)就像Django所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:我们就是以这种方式告诉Dja ...

  2. Django模板-在视图中使用模板

    之前我们已经有了自己的视图mysite.views.py中,应该是这样子的 from django.http import HttpResponse import datetime def curre ...

  3. Django之视图层与模板层

    目录 视图层 小白必会三板斧 HttpResponse render redirect JsonResponse 前后端分离 FBV CBV 给CBV加装饰器 模板层 模板语法 模板传值 过滤器 语法 ...

  4. django 之视图层及模板层 04

    目录 视图层 render方法是Template和Contex两个对象的组合使用 JsonResponse对象 CBV及源码分析 CBV 加装饰器的方式 模板层 模板语法传值 模板语法 变量 过滤器( ...

  5. Django的视图层和模板层

    目录 一.视图层 1. 小白必会三板斧 2. JsonResponse 3. FBV与CBV 3.1 FVB 3.2 CBV 4. CBV的源码 5. 给CBV加装饰器 二.模板层 1. 模板语法 2 ...

  6. Django templates html中进行模板渲染时使用python语法的基本方式

    导包(可以在模板中导入python包进行使用): <%!import urllib%> <%! from ** import **%> 使用if for等python语句: % ...

  7. 如何在django视图中使用asyncio(协程)和ThreadPoolExecutor(多线程)

    Django视图函数执行,不在主线程中,直接 loop = asyncio.new_event_loop() # 更不能loop = asyncio.get_event_loop() 会触发 Runt ...

  8. Django(十五)模板详解:模板标签、过滤器、模板注释、模板继承、html转义

    一.模板的基础配置及使用 [参考]https://docs.djangoproject.com/zh-hans/3.0/topics/templates/ 作为Web框架,Django提供了模板,用于 ...

  9. 五、Django之视图和模板-Part 3

    一.概述 一个视图就是一个页面,通常提供特定的功能,使用特定的模版.列如:在一个博客应用中,你可能会看到下列视图: 博客主页:显示最新发布的一些内容 每篇博客的详细页面:博客的永久链接 基于年的博客页 ...

随机推荐

  1. Asp.net 提供程序模型

    需要说明一下几点 1.什么是提供程序? 2.ASP.NET 4.5 中的提供程序 3.配置提供程序 有一下几种存储状态的方式 1.应用程序状态 2.会话状态 3.高速缓存状态 4.cookie 5.查 ...

  2. jQuery validate api(转)

    官网地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation jQuery plugin: Validation 使用说明 转载 ...

  3. iOS 时钟动画

    在iOS开发中,定时器NSTimer并不能够准确的出发,通常使用NSTimer只能控制不需要精确处理的操作,而CADisplayLink就是在每次屏幕刷新时,通知系统.CADisplayLink最大的 ...

  4. 【微信公众号】使用a标签打开链接显示空白

    window.location.href 改成 top.location.href

  5. BZOJ 1489: [HNOI2009]双递增序( dp )

    dp(i, j)表示选第i个, 且当前序列长度为j, 另一个序列的最后一个元素的最小值...然后根据上一个是哪个序列选的讨论一下就行了...奇怪的dp... --------------------- ...

  6. ASP.NET 使用My97DatePicker日期控件

    首先要下载该控件的包,下载地址:http://pan.baidu.com/s/1Aa5gk 引用文件 <script src="js/My97DatePicker/WdatePicke ...

  7. Maven本地

    <localRepository></localRepository>

  8. (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单

    原文 (C#)Windows Shell 外壳编程系列7 - ContextMenu 注册文件右键菜单 (本系列文章由柠檬的(lc_mtt)原创,转载请注明出处,谢谢-) 接上一节:(C#)Windo ...

  9. Android4.3模拟器界面中右侧菜单按钮无法使用问题解决办法

    开发环境:笔记本电脑Windows2008+MyEclipse 10+Android4.3 问题描述:运行或者调试Android项目时,发现模拟器中右侧Menu按钮无法点击,截图如下: 查看在Andr ...

  10. Java中有关构造函数的一道笔试题解析

    Java中有关构造函数的一道笔试题解析 1.详细题目例如以下 下列说法正确的有() A. class中的constructor不可省略 B. constructor必须与class同名,但方法不能与c ...