django--模板的继承

include 模板标签

 

 

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

 

 

 

下面这两个例子都包含了 nav.html 模板。两个例子的作用完全相同,只不过是为了说明单、双引号都可以通用。

{% include 'nav.html' %}

{% include "nav.html" %}

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

{% include 'includes/nav.html' %}

下面的例子包含了以变量 template_name 的值为名称的模板内容:

{% include template_name %}

和在 get_template() 中一样, 对模板的文件名进行判断时会在所调取的模板名称之前加上来自 TEMPLATE_DIRS 的模板目录。

 

所包含的模板执行时的 context 和包含它们的模板是一样的。

 

如果未找到给定名称的模板文件,Django 会从以下两件事情中择一而为之:

 

  • 如果 DEBUG 设置为 True ,你将会在 Django 错误信息页面看到 TemplateDoesNotExist 异常。

     

  • 如果 DEBUG 设置为 False ,该标签不会引发错误信息,在标签位置不显示任何东西。

模板继承

 

 

到目前为止,我们的模板范例都只是些零星的 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 视图创建另一个模板会发生什么事情呢?如果我们再次创建一个漂亮、有效且完整的 HTML 模板,我们可能会创建出下面这样的东西:

 

 

<!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 框架文档,我们将在本站点的所有页面中使用。子模板的作用就是重载、添加或保留那些块的内容。(如果一直按我们的范例做话,请将此文件保存到模板目录。)

 

 

我们使用一个以前没有见过的模板标签: {% block %} 。 所有的 {% block %} 标签告诉模板引擎,子模板可以重载这些部分。

 

 

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

 

 

{% extends "base.html" %}

{% block title %}The current time{% endblock %} {% block content %} <p>It is now {{ current_date }}.</p> {% endblock %}

再为 hours_ahead 视图创建一个模板,看起来是这样的:

 

 

{% extends "base.html" %}

{% block title %}Future time{% endblock %} {% block content %} <p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p> {% endblock %}

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

 

 

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

 

 

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

 

 

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

 

 

继承并不改变 context 的工作方式,而且你可以按照需要使用多层继承。使用继承的一种常见方式是下面的三层法:

 

 

  1. 创建 base.html 模板,在其中定义站点的主要外观感受。这些都是不常修改甚至从不修改的部分。

     

     

     

     

  1. 为网站的每个区域创建 base_SECTION.html 模板(例如, base_photos.html 和 base_forum.html )。这些模板对 base.html 进行拓展,并包含区域特定的风格与设计。

     

     

     

     

  1. 为每种类型的页面创建独立的模板,例如论坛页面或者图片库。这些模板拓展相应的区域模板。

     

     

     

     

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

 

 

以下是使用模板继承的一些诀窍:

 

 

  • 如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。否则,模板继承将不起作用。

     

     

     

     

  • 一般来说,基础模板中的 {% block %} 标签越多越好。记住,子模板不必定义父模板中所有的代码块,因此你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。俗话说,钩子越多越好。

     

     

     

     

  • 如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。

     

     

     

     

  • 如果需要获得父模板中代码块的内容,可以使用 {{ block.super }} 变量。如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。

     

     

     

     

  • 不可同一个模板中定义多个同名的 {% block %} 。存在这样的限制是因为block 标签的工作方式是双向的。也就是说,block 标签不仅挖了一个要填的坑,也定义了在 父 模板中这个坑所填充的内容。如果模板中出现了两个相同名称的{% block %} 标签,父模板将无从得知要使用哪个块的内容。

     

     

     

     

  • {% extends %} 对所传入模板名称使用的加载方法和 get_template() 相同。也就是说,会将模板名称被添加到TEMPLATE_DIRS 设置之后。

     

     

     

     

  • 多数情况下, {% extends %} 的参数应该是字符串,但是如果直到运行时方能确定父模板名,这个参数也可以是个变量。这使得你能够实现一些很酷的动态功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
django-gridfs-storage是一个用于在Django项目中使用GridFS存储后端的库。GridFS是MongoDB的一种存储引擎,它可以用于存储大型文件,解决了传统的文件存储方式的一些限制。 使用django-gridfs-storage,我们可以轻松地在Django项目中将文件存储到MongoDB的GridFS中,同时利用Django提供的模型和视图来管理和访问这些文件。 使用django-gridfs-storage主要包含以下几个步骤: 1. 安装和配置:使用pip命令安装django-gridfs-storage库,并在Django的设置文件中添加相关配置,包括MongoDB连接信息和GridFS的collection名称等。 2. 模型定义:定义一个继承django.db.models.FileField的字段,将其作为模型的一个属性。这个字段将用于存储文件在GridFS中的存储位置。 3. 视图和表单:在Django的视图中,使用GridFSStorage提供的一些方法来操作文件,比如保存文件、获取文件、删除文件等。同时,可以根据需要创建合适的表单来处理文件上传。 4. 文件访问:使用Django模板系统来展示文件或者生成文件的下载链接,可以通过模型实例的属性来获取文件的URL,然后在模板中使用该URL来创建适当的HTML链接标签。 使用django-gridfs-storage可以有效地管理大型文件的存储和访问,而无需担心文件大小限制等问题。同时,结合Django强大的开发框架,我们可以更加灵活和方便地处理文件的上传、下载和展示等操作。这使得django-gridfs-storage成为在Django项目中使用MongoDB存储文件的理想选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值