模板继承

  到目前为止,我们的模板范例都只是些零星的 HTML 片段,但在实际应用中,你将用 Django 模板系统来创建整个 HTML 页面。 这就带来一个常见的 Web 开发问题: 在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?

  解决该问题的传统做法是使用 服务器端的 includes ,你可以在 HTML 页面中使用该指令将一个网页嵌入到另一个中。 事实上, Django 通过刚才讲述的 {% include %} 支持了这种方法。 但是用 Django 解决此类问题的首选方法是使用更加优雅的策略—— 模板继承 。

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

  通过修改 current_datetime.html 文件,为 current_datetime 创建一个更加完整的模板来体会一下这种做法: 

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>The current time</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
<p>It is now {{ current_date }}.</p> <hr>
<p>Thanks for visiting my site.</p>
</body>
</html

  这看起来很棒,但如果要为 hours_ahead 视图创建另一个模板会发生什么事情呢?  

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>Future time</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> <hr>
<p>Thanks for visiting my site.</p>
</body>
</html>

  很明显,我们刚才重复了大量的 HTML 代码。 想象一下,如果有一个更典型的网站,它有导航条、样式表,可能还有一些 JavaScript 代码,事情必将以向每个模板填充各种冗余的 HTML 而告终。

  解决这个问题的服务器端 include 方案是找出两个模板中的共同部分,将其保存为不同的模板片段,然后在每个模板中进行 include。 也许你会把模板头部的一些代码保存为 header.html 文件:

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>

  你可能会把底部保存到文件 footer.html :

   <hr>
<p>Thanks for visiting my site.</p>
</body>
</html>

  对基于 include 的策略,头部和底部的包含很简单。 麻烦的是中间部分。 在此范例中,每个页面都有一个<h1>My helpful timestamp site</h1> 标题,但是这个标题不能放在 header.html 中,因为每个页面的<title> 是不同的。 如果我们将 <h1> 包含在头部,我们就不得不包含 <title> ,但这样又不允许在每个页面对它进行定制。 何去何从呢?

  Django 的模板继承系统解决了这些问题。 你可以将其视为服务器端 include 的逆向思维版本。 你可以对那些不同 的代码段进行定义,而不是 共同 代码段。

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

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
{% block content %}{% endblock %}
{% block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{% endblock %}
</body>
</html>

  这个叫做 base.html 的模板定义了一个简单的 HTML 框架文档,我们将在本站点的所有页面中使用。 子模板的作用就是重载、添加或保留那些块的内容。 (如果你一直按顺序学习到这里,保存这个文件到你的template目录下,命名为 base.html .)

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

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

 {% extends "base.html" %}

 {% block title %}The current time{% endblock %}

 {% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}

  看起来很漂亮是不是? 每个模板只包含对自己而言 独一无二 的代码。 无需多余的部分。 如果想进行站点级的设计修改,仅需修改 base.html ,所有其它模板会立即反映出所作修改。

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

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

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

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

  你可以根据需要使用任意多的继承次数。 使用继承的一种常见方式是下面的三层法:

  1. 创建 base.html 模板,在其中定义站点的主要外观感受。 这些都是不常修改甚至从不修改的部分。
  2. 为网站的每个区域创建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对 base.html 进行拓展,并包含区域特定的风格与设计。
  3. 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。 这些模板拓展相应的区域模板。

  这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工作。

  Tips

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

Python框架之Django学习笔记(八)的更多相关文章

  1. Python框架之Django学习笔记(十七)

    Django框架之表单(续二) 今天的这篇博客将是Django学习笔记博客的最后一篇,基本每周最少一篇的Django框架学习,坚持到今天也实属不易,当然了,这个框架的学习仅仅是Django框架的基础部 ...

  2. Python框架之Django学习笔记(十一)

    话说上次说到数据库的基本访问,而数据库我们主要进行的操作就是CRUD,也即是做计算处理时的增加(Create).读取(Retrieve)(重新得到数据).更新(Update)和删除(Delete),俗 ...

  3. Python框架之Django学习笔记(十二)

    Django站点管理 十一转眼结束,说好的充电没能顺利开展,反而悠闲的看了电视剧以及去影院看了新上映的<心花路放>.<亲爱的>以及<黄金时代>,说好的劳逸结合现在回 ...

  4. Python框架之Django学习笔记(十)

    又是一周周末,如约学习Django框架.在上一次,介绍了MVC开发模式以及Django自己的MVT开发模式,此次,就从数据处理层Model谈起. 数据库配置 首先,我们需要做些初始配置:我们需要告诉D ...

  5. Python框架之Django学习笔记(六)

    模板 上篇博文学习了动态视图,但是,视图中返回文本的方式有点特别. 也就是说,HTML被直接硬编码在 Python 代码之中. def current_datetime(request): now = ...

  6. Python框架之Django学习笔记(十六)

    Django框架之表单(续) 今天简直无力吐槽了,去了香山,结果和网上看到的简直是天壤之别啊,说好的香山的枫树呢?说好的香山的红叶呢?说好的漫山遍野一片红呢?本以为在山上,一口气爬上去,沿路基本都是翠 ...

  7. Python框架之Django学习笔记(十五)

    表单 从Google的简朴的单个搜索框,到常见的Blog评论提交表单,再到复杂的自定义数据输入接口,HTML表单一直是交互性网站的支柱.本次内容将介绍如何用Django对用户通过表单提交的数据进行访问 ...

  8. Python框架之Django学习笔记(九)

    模型 之前,我们用 Django 建造网站的基本途径: 建立视图和 URLConf . 正如我们所阐述的,视图负责处理一些主观逻辑,然后返回响应结果. 作为例子之一,我们的主观逻辑是要计算当前的日期和 ...

  9. Python框架之Django学习笔记(五)

    第一个Django网页小结 进来的请求转入/hello/. Django通过在ROOT_URLCONF配置来决定根URLconf. Django在URLconf中的所有URL模式中,查找第一个匹配/h ...

随机推荐

  1. GCC 编译错误 relocation truncated to fit: R_X86_64_32S against `.bss'

    问题如下图所示:(.text+0x53a): relocation truncated to fit: R_X86_64_32S against `.bss' 以前在Linux中编译程序,从来没有遇到 ...

  2. 使用adbWireless无线调试Android真机设备[转]

    开发Android的朋友都知道,真机调试需要把手机与PC相连,然后把应用部署到真机上进行安装和调试.长长的USB线显得很麻烦,而且如果需要USB接口与其他设备连接的话显得很不方便.今天介绍一种不通过U ...

  3. 美国L1签证申请的常见问题解析

    美国L1是一种允许在美国和中国都有机构的跨国公司从国外的母公司派遣一定层次的经理或专业技术人员去美国分支机构工作的非移民签证.L1签证分两类:美国L1A是跨国公司经理及主管人员签证,L1B是专门技术人 ...

  4. SwiftHN阅读器应用IOS源码

    SwiftHN是用Swift语言编写的Hacker News阅读器,同时采用了iOS 8最新的API. <ignore_js_op> <ignore_js_op> 详细说明:h ...

  5. [转载]AngularJS快速开始

    AngularJS快速开始 Hello World! 开始学习AngularJS的一个好方法是创建经典应用程序“Hello World!”: 使用您喜爱的文本编辑器,创建一个HTML文件,例如:hel ...

  6. 分析ELF的加载过程

    http://blog.chinaunix.net/uid-72446-id-2060538.html 对于可执行文件来说,段的加载位置是固定的,程序段表中如实反映了段的加载地址.对于共享库来?段的加 ...

  7. 《剑指offer》【调整数组顺序使奇数位于偶数前面】(python版)

    题目描述: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分 思路: 我认真看了一下,题目应该是要求在原地调整,所以这里不能再 ...

  8. 【转】 Solr的SolrCloud与Master-slave主从模式对比

    第一印象 SolrCloud是Solr4.0引入的,主要应对与商业场景.它很像master-slave,却能自动化的完成以前需要手动完成的操作.利用ZooKeeper这个工具去监控整个Solr集群,以 ...

  9. js数据结构处理--------树结构数据遍历

    1.深度遍历 深度遍历利用栈来实现 class Stack { constructor () { this.top = 0, // 栈的长度 this.list = [] } push(item) { ...

  10. javaweb基础(27)_jsp标签库实例

    一.开发标签库 1.1.开发防盗链标签 1.编写标签处理器类:RefererTag.java 1 package me.gacl.web.simpletag; 2 3 import java.io.I ...