第四章:模板系统篇

如果HTML被硬性地直接写入 Python 代码之中,这种处理会导致一些问题:

  • 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。站点设计的修改往往比底层 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。

  • Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。设计人员和 HTML/CSS 编写人员都不应该通过编辑 Python 代码来完成自己的工作;他们应该处理的是 HTML。

  • 同理,程序员编写 Python 代码和设计人员制作模板同时进行的工作方式效率是最高的,远胜于让一个人等待另一个人完成对某个既包含 Python 又包含 HTML 的文件的编辑工作。

  解决方案,使用模板就可以解决

模板系统基本知识

1、模板系统基本知识

   

6

<html>
<head><title>Ordering notice</title></head>

<body>

<p>Dear {{ person_name }},</p>

<p>Thanks for placing an order from {{ company }}. It's scheduled to
ship on {{ ship_date|date:"F j, Y" }}.</p>

<p>Here are the items you've ordered:</p>

<ul>
{% for item in item_list %}
<li>{{ item }}</li>
{% endfor %}
</ul>

{% if ordered_warranty %}
<p>Your warranty information will be included in the packaging.</p>
{% endif %}

<p>Sincerely,<br />{{ company }}</p>

</body>
</html>

 

Django 模板含有很多内置的tags和filters,我们将陆续进行学习. 附录F列出了很多的tags和filters的列表,熟悉这些列表对你来说是个好建议. 学习完第十章,你就明白怎么去创建自己的filters和tags了.

2、如何使用模板系统

   两个步骤:

  1. 可以用原始的模板代码字符串创建一个 Template 对象, Django同样支持用指定模板文件路径的方式来创建 Template 对象;

  1. 调用 Template 对象的 render() 方法并提供给他变量(i.e., 内容). 它将返回一个完整的模板字符串内容,包含了所有标签块与变量解析后的内容

3、创建模板对象

创建一个 Template 对象最简单的方法就是直接实例化它。 Template 类就在 django.template 模块中,构造函数接受一个参数,原始模板代码。

>>> from django.template import Template
>>> t = Template("My name is {{ name }}.")
>>> print t

 

4、模板渲染

一旦你创建一个 Template 对象,你可以用 context 来传递数据给它。一个context是一系列变量和它们值的集合。模板使用它来赋值模板变量标签和执行块标签。

context在Django里表现为 Context 类,在 django.template 模块里。它构造是有一个可选参数:一个字典映射变量和它们的值。调用 Template 对象的 render() 方法并传递context来填充模板:

 

>>> from django.template import Context, Template
>>> t = Template("My name is {{ name }}.")
>>> c = Context({"name": "Stephane"})
>>> t.render(c)
'My name is Stephane.'

 

基本的模板标签和过滤器

1、标签 if/else  :  {%  if   %} {% else %}  {% endif %}

{% if today_is_weekend %}
<p>Welcome to the weekend</p>
{% endif %}
{% if today_is_weekend %}
<p>Welcome to the weekend!</p>
{% else %}
<p>Get back to work.</p>
{% endif %}

 

2、标签for :{% for  n in list %} {% endfor %}

<ul>
{% for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{% endfor %}
</ul>

 

{% for country in countries %}
<h1>{{ country.name }}</h1>
<ul>
{% for city in country.city_list %}
<li>{{ city }}</li>
{% endfor %}
</ul>
{% endfor %}


3、标签ifequal/ifnotequal:

 {% ifequal  %}  {% else %} {% endifqual %}   

 {% ifnotequal%}  {% else %}  {% endifnotequal %}  

{% ifequal user currentuser %}
<h1>Welcome!</h1>
{% endifequal %}

 

{% ifequal section 'sitenews' %}
<h1>Site News</h1>
{% else %}
<h1>No News Here</h1>
{% endifequal %}

 

4、注释

象HTML和其他的语言例如python一样,Django模板系统也允许注释。注释使用 {# #}

{# This is a comment #}


5、过滤器

模板过滤器是在变量被显示前修改它的值的一个简单方法

#显示的内容是变量 {{ name }} 被过滤器 lower 处理后的结果,它功能是转换文
#本为小写。使用 | 来应用过滤器。
{{ name|lower }}
#date : 按指定的格式字符串参数格式化 date 或者 datetime 对象
{{ pub_date|date:"F j, Y" }}

 

在视图中使用模板

 1、简单模版使用

 

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 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() ,还不如做出更佳选择。

2、加载模版

为了减少模板加载调用过程及模板本身的冗余代码,Django 提供了一种使用方便且功能强大的 API ,用于从磁盘中加载模板,要使用此模板加载API,首先你必须将模板的保存位置告诉框架

修改settings.py文件中的配置

 查看下面配置

DEBUG = True
TIME_ZONE = 'America/Chicago'
USE_I18N = True
ROOT_URLCONF = 'mysite.urls'

配置模版参数 TEMPLATE_DIRS

注意:如果使用的是 Windows 平台,请包含驱动器符号并使用Unix风格的斜杠(/)而不是反斜杠(\)

方式一:

TEMPLATE_DIRS = (
'/mysite/templates',
)

方式二:

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

方式三:

import os.path

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

返回 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)

 

3、 找不到给定名称的模板

  出现TemplateDoesNotExist 错误信息页面。

 

 

 


 

 

4、render_to_response()

由于加载模板、填充 context 、将经解析的模板结果返回为 HttpResponse 对象这一系列操作实在太常用了,Django 提供了一条仅用一行代码就完成所有这些工作的捷径。该捷径就是位于 django.shortcuts 模块中名为 render_to_response() 的函数。大多数时候,你将使用 render_to_response() ,而不是手动加载模板、创建 ContextHttpResponse 对象。

下面就是使用 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_templateTemplateContextHttpResponse 。相反,我们导入 django.shortcuts.render_to_responseimport datetime 继续保留.

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

5、locals() 技巧

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

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


6、get_template()中使用子目录

把所有的模板都存放在一个目录下可能会让事情变得难以掌控。你可能会考虑把模板存放在你模板目录的子目录中,这非常好。事实上,我们推荐这样做;一些Django的高级特性(例如将在第九章讲到的通用视图系统)的缺省约定就是期望使用这种模板布局。

 

7、include 模板标签

 内建模板标签: {% include %} 

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

{% include 'nav.html' %}
{% include "nav.html" %}

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

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

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

{% include template_name %}

 8、模板继承

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

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

 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>

 base.html  

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

<!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>

 

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

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

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

 

我们可以修改 current_datetime.html 模板来使用它:

{% extends "base.html" %}

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

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

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

 

使用继承的一种常见方式是下面的三层法:

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

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

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

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

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

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

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

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

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

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

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

 

 

 


 

 

 

 

原文地址:https://www.cnblogs.com/lhj588/p/2231277.html