django在视图中获取Template

django在视图中获取Template

现在对Template进行深入了解

在试图中使用模板(了解)

视图代码:

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内建的文件操作函数来读取文件内容。类似这样子:

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/lyh/mycode/question_generate/question/templates/question/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() ,还不如做出更佳选择。

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

get_template(重点)

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

要使用次模板加载API,首先你必须将模板的保存位置告诉框架。设置的保存文件是ROOT_URLCONF配置的settings.py。

打开settings.py配置文件,找到TEMPLATE_DIRS这项设置,默认是一个空元祖(tuple)。

TEMPLATE_DIRS = (
    # Put strings here, like "/home/django/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/lyh/mycode/mysite/polls/templates',
)

注意:

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

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

Python要求单价元素元组必须使用逗号,以此消除与圆括号表达式之间的歧义。

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

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下,它会只能的选择正确的反斜杠进行链接,不是有正斜杠。

完成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 对象。

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

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

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

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

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

刷新网页,发现新大陆咯

render_to_response()

好,已经说了如何加载一个模板文件,然后用Context渲染它,之后返回这个处理好的HttpResponse对象给用户。我们已经采用了优化方案,使用get_template()来代替繁华用代码来处理模板及其路径的工作。但这仍然需要一定量的时间来敲代码。Django为此提供了一个捷径,让你一次性的载入某个模板文件,渲染它,然后将此作为HttpResponse返回

下面是使用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})

(1)我们不在需要导入get_template、Template、Context和HttpResponse。相反,我们导入django.shortcuts.render_to_response。

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

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

locals()技巧

很多时候,我们像上一个例子一行,发现自己一直在计算某一个变量,保存结果到变量中(比如前面代码中的now),然后将这些变量发送给模板。我们会发现,不断地为临时变量*临时模板*命名有那么一点儿冗余,不仅多余,还需要额外的输入。

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

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

我们没有像之前那样手工指定context字典,而是传入了locals()的值,它囊括了函数执行到该时间点时所定义的一切变量。因此,我们将now变量重命名为current_date,因为那才是模板所预期的变量名称。

使用locals()时要注意它将包括*所有*的局部变。

get_template()中使用子目录

把所有的模板都存放在一个目录下可能会让事情变得难以掌控。根据Miller法则,一个层级下的文件数量在7±2个为好。考虑把模板放在你模板目录的子目录中,这样会很好,而且也推荐这样做。

把模板放在模板目录的子目录中是件非常轻松的事情。只需要在调用get_template()是,把子目录名和一条斜杠添加到模板名称之前,for example:

t = get_template("dateapp/current_datetime.html")

由于render_to_response()只是对get_template()简单封装,你可以对render_to_response()的第一个参数做同样的处理。

return render_to_response('dateapp/current_datetime.html',{'current_date':now})
posted @ 2023-01-09 17:17  zong涵  阅读(120)  评论(0编辑  收藏  举报