Django模板4

上一篇Django模板3最后的问题,我们需要把数据和展现分离开。

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

<html><body>From tempTime.html====time now is {{current_date}}</body></html>
 1 def temp_time(request):
 2     now= datetime.datetime.now()
 3     #f = open(BASE_DIR + ‘\\mysite\\templates\\tempTime.html‘)
 4     f=open(r‘E:\djangosite\mysite\mysite\templates\tempTime.html‘)
 5     content = f.read()
 6     f.close()
 7     t=Template(content)
 8     c=Context({‘current_date‘:now})
 9     html = t.render(c)
10     return HttpResponse(html)

时刻记得在urls.py中去加配置哦

url(r‘^temptime/$‘,temp_time),

运行效果如下:

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

  • 它没有对文件丢失的情况做出处理。 如果文件 tempTime.html 不存在或者不可读, open() 函数调用将会引发 IOError 异常。
  • 这里对模板文件的位置进行了硬编码。
  • 它包含了大量令人生厌的重复代码。 与其在每次加载模板时都调用 open() 、 fp.read() 和 fp.close() ,还不如做出更佳选择。

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

模板加载

为了减少模板加载调用过程及模板本身的冗余代码,Django 提供了一种使用方便且功能强大的 API,用于从磁盘中加载模板,要使用此模板加载API,首先你必须将模板的保存位置告诉框架。 打开settings.py配置文件,找到TEMPLATE_DIRS这项设置。(我本地新建的站点中,settings.py没有该项设置,但是官方文档中确实有它的介绍,自行加上即可)

这里有相关介绍,截图如下:

我新建的TEMPLATE_DIRS如下

import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
#这中间省去了其他配置项和说明
TEMPLATE_DIRS=(
    os.path.join(BASE_DIR,‘mysite\\templates‘).replace(‘\\‘,‘/‘),
    #r"E:\djangosite\mysite\mysite\templates".replace(‘\\‘,‘/‘),
    )

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

TEMPLATE_DIRS = (
    ‘C:/www/django/templates‘,
)

BASE_DIR:Python 内部变量 __file__ ,该变量被自动设置为代码所在的 Python 模块文件名。os.path.dirname(__file__)将会获取自身所在的文件,即settings.py 所在的目录

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

get_template方式

进行如下修改:区别就在注释那8和9两行

 1 import datetime
 2 from django.template.loader import get_template
 3 from django.template import Template,Context
 4 from django.http import HttpResponse
 5
 6 def temp_load(request):
 7     now= datetime.datetime.now()
 8     #t = get_template(BASE_DIR + ‘\\mysite\\templates\\tempTime.html‘)
 9     t = get_template(‘tempTime.html‘)
10     c=Context({‘current_date‘:now})
11     html = t.render(c)
12     return HttpResponse(html)

同样不要忘记去配置urls.py,这里就不多说了。

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

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

要确定某个模板文件在你的系统里的位置, get_template()方法会自动为你连接已经设置的 TEMPLATE_DIRS目录和你传入该方法的模板名称参数。

运行效果如下:

render_to_response方式

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

该捷径就是位于 django.shortcuts 模块中名为 render_to_response() 的函数。

1 from django.shortcuts import render_to_response
2 import datetime
3
4 def temp_render(request):
5     now = datetime.datetime.now()
6     return render_to_response(‘tempTime.html‘, {‘current_date‘: now})

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

很多时候,我们要穿入到模板中的Context值很多,我们需要自己定义临时变量,然后组装Context对象,是不是觉得很麻烦?

Python内建函数 locals(),它返回的字典对所有局部变量的名称与值进行映射。 因此,前面的视图可以重写成下面这个样子:

1 def temp_locals(request):
2     current_date = datetime.datetime.now()
3     return render_to_response(‘tempTime.html‘, locals())

我们只是将临时变量now变成了模板需要的变量名称current_date,然后传递到render_to_response的第二个参数不在我们去构造Context对象,直接使用locals()即可。

当遇到需要传递很多参数时,只需要定义对应名称的临时变量,通过locals即可一次性传递过去,着实方便很多。

还记得Django模板1最后说的吗,解决无效参数,即便locals传递冗余没用的或者少传递了必要参数,django也不会报错的,而是将该值复制为空。

render_to_response()是对get_template()简单封装,他们都可以传递子目录,类似于

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

需要注意的是 Windows用户必须使用斜杠(/)而不是反斜杠(\)

include 模板标签

在讲解了模板加载机制之后,我们再介绍一个利用该机制的内建模板标签: {% include %} 。该标签允许在(模板中)包含其它的模板的内容。 标签的参数是所要包含的模板名称,可以是一个变量,也可以是用单/双引号硬编码的字符串。 每当在多个模板中出现相同的代码时,就应该考虑是否要使用 {% include %} 来减少重复。

下面的例子包含了 includes/nav.html 模板的内容:

在templates下创建mypage.html和includes文件夹,文件夹下创建nav.html,如下

1 # mypage.html
2
3 <html>
4 <body>
5 {% include "includes/nav.html" %}
6 <h1>{{ title }}</h1>
7 </body>
8 </html>
1 # includes/nav.html
2
3 <div id="nav">
4     You are in: {{ current_section }}
5 </div>
1 def temp_include(request):
2     now = datetime.datetime.now()
3     c= Context({‘title‘:‘my title‘,‘current_section‘:‘mysection‘})
4     return render_to_response(‘mypage.html‘,c)

运行效果

模板继承

使用include标签可以解决一定层面上的代码代码重用问题,但是考虑一下,include是怎么一个情况呢?

定义页面公共部分的代码分别放置在不同的文件中,某一个页面需要时便include进来。这样页面布局一致,展示内容不同的页面都要分别取做页面,并include不同的文件。

这里强调了页面布局一致。

由此想起面向对象的类继承,我们抽象一个一致的页面布局,然后让内容不同的子页面扩展该布局怎么样?就是说和include思想相逆的方式。

Django确实提供了这样一种方式---模板继承 。

本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含的公用部分和定义块进行重载。

定义基础模板,该框架之后将由 子模板 所继承。 以下是我们目前所讲述范例的基础模板:

 1 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
 2 <html lang="en">
 3 <head>
 4     <title>{% block title%}{% endblock %}</title>
 5 </head>
 6 <body>
 7     <h1>My helpful timestamp site</h1>
 8     {% block content %}{% endblock %}
 9     {% block footer %}
10     <hr>
11     <p>Thanks for visiting my site.</p>
12     {% endblock %}
13 </body>
14 </html>

这个叫做 base.html 的模板定义了一个简单的 HTML 框架文档,我们将在本站点的所有页面中使用。 子模板的作用就是重载、添加或保留那些块的内容。

所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。 每个{% block %}标签所要做的是告诉模板引擎,该模板下的这一块内容将有可能被子模板覆盖。

现在我们已经有了一个基本模板,我们可以修改 current_datetime.html 模板来 使用它:

1 {% extends "base.html" %}
2
3 {% block title %}The current time{% endblock %}
4
5 {% block content %}
6 <p>It is now {{ current_date }}.</p>
7 {% endblock %}

工作方式

在加载 current_datetime.html 模板时,模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。 模板引擎立即装载其父模板,即本例中的 base.html 。

此时,模板引擎注意到 base.html 中的三个 {% block %} 标签,并用子模板的内容替换这些 block 。因此,引擎将会使用我们在 { block title %} 中定义的标题,对 {% block content %} 也是如此。

注意由于子模板并没有定义 footer 块,模板系统将使用在父模板中定义的值。 父模板 {% block %} 标签中的内容总是被当作一条退路。

继承并不会影响到模板的上下文。 换句话说,任何处在继承树上的模板都可以访问到你传到模板中的每一个模板变量。

使用模板继承的一些说明:

  • 如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
  • 一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。
  • 如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
  • 如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
  • 不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是双向的。 也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。
  • {% extends %} 对所传入模板名称使用的加载方法和 get_template() 相同。 也就是说,会将模板名称被添加到TEMPLATE_DIRS 设置之后。
  • 多数情况下, {% extends %} 的参数应该是字符串,但是如果直到运行时方能确定父模板名,这个参数也可以是个变量。

{{ block.super }}示例

1 {% extends "base.html" %}
2
3 {% block title %}Block.surper {% endblock %}
4 {% block content %}
5 {{ block.super  }}<br />
6 From current_datetime.html====time now is {{current_date}}
7 {% endblock %}

和上边current_datetime.html相比之增加了红色第五行代码

意思很明白了:子模板中,重写的{% block %}内包含{{ block.super }}就可以先展示父模板内容,再添加重写的内容。就像Java中super和c#中base。

小结

模板终于算是简单写完了,东西很多很杂乱,但是不难。大多数都是从DjangoBook摘过来的,如果写的不够清晰,请查看原文。

Django模板4

时间: 2024-11-14 06:30:47

Django模板4的相关文章

Django模板语言小记

1.blog.views.py  # Create your views here. from django.template import loader,Context from django.http import HttpResponse from blog.models import BlogPost def archive(request):     posts = BlogPost.objects.all()     t = loader.get_template('archive.

Django项目实践2 - Django模板(常用语法规则)

http://blog.csdn.net/pipisorry/article/details/45727309 模板中常用的语法规则 {最新版本的Django语法可能有改变,不支持的操作可能支持了.[HTML教程 - 基本元素/标签及属性]} Django 模板标签 if/else 标签 1. 基本语法格式如下: {% if condition %} ... display {% endif %} 或者: {% if condition1 %} ... display 1 {% elif con

Django -- 模板

一切伟大的行动和思想,都有一个微不足道的开始:   -- 徐志摩<励志天下> 一切能忍受的微不足道,都有一个行动思想在脚下.   -- 小QQ <励志自己> ------------------------------------------------------------------------------------------------------ 前一节,我们把HTML直接硬编码在python中,尽管他便于解释使徒的工作原理,但是却不是一个好主意: 1.对页面设计进行

Django 模板.html中 href参数传入

在Django模板中可能会出现访问多个URL指向同一函数,为减少代码可以利用正则表达式实现 url(r'^remove_userinfo(?P<nid>\d+)/',views.removeuserinfo,name='reinfo'), (?P<nid>\d+)表示此部分的名称为nid,对应removeuserinfo(request,nid)中的nid参数 def removeuserinfo(request,nid): return HttpResponse(nid) 此时

Django 模板中引用静态资源(js,css等)

Django 模板中免不了要用到一些js和CSS文件,查了很多网页,被弄得略晕乎,还是官网靠谱,给个链接大家可以自己看英文的. https://docs.djangoproject.com/en/1.6/howto/static-files/ 大致步骤是这样的: 1.确保setting.py里的installed_apps中包括了django.contrib.staticfiles,没有的话大家给添上就行. 2.同样是在setting.py里面进行添加,我们需要添加静态资源相关的配置.可以这么写

Django模板的使用流程-muahao02目录下测试

在我的云主机上,muahao02的测试: Django模板的使用流程 环境:阿里云主机 步骤: 首先建立blog 这个应用 在blog这个目录下手动建立 templates目录,默认的模板就在这个目录下 vim url.py这个文件 vim views.py这个文件 在一级目录下,执行python manage.py runserver 121.42.138.224:8000 [[email protected] templates]# pwd /root/muahao02/blog/templ

Django模板系统学习整理

block extends include三者的差别跟用法 一.定义基础模板,在html内容中定义多个block块,block由子模板引用同名block块,来决定是否替换这些部分 {% block title %}一些内容,这里可不填{% endblock %} {% block content %}一些内容,这里可不填{% endblock %} {% block footer %}一些内容,这里可不填{% endblock %} 这里 title content footer 不是变量,名字

Django模板1

上一篇中带参数的URLconf虽然可以做到传参动态显示内容,但是最终现实的内容还是硬编码到Python代码中的 1 def hours_ahead(request,phours): 2 try: 3 phours = int(phours) 4 except VauleError: 5 raise Http404() 6 7 dt = datetime.datetime.now() + datetime.timedelta(hours=phours) 8 html = "<html>

转换器2:ThinkPhp模板转Django模板

前天写了个<ThinkPhp模板转Flask模板> 居然被同事鄙视了,原因是他用Django,我用Flask,为了避免被他继续安利Django的强大.我决定写一个Django模板转换器. 为了复用代码,得用继承,我把原代码分成三段,一下子获得了三个转换器. class ConverterTemplateEncoding(object): separators = [('<', '>')] def __init__(self): self.match = {'opening': 0,

Django模板API

基础部分 模板是一个文档或者说一个普通的python字符串由Django模板语言标记而成.一个模板语言可以包括block标签或者是变量. 一个block标签是一个处于模板中的标记,能过完成一些事情. Block的定义看起来有点模糊,这是django开发团队有意为之的.比如一个block标签即可以用来输出内容:也可以被当做一个控制结构(比如if声明或者是for循环)从数据库中抓去数据:或者是通往另一个模板的入口. Block标签由"{%"和"%}"组成. 比如一个模板