码迷,mamicode.com
首页 > 其他好文 > 详细

Django项目实践2 - Django模板

时间:2015-04-15 17:04:52      阅读:303      评论:0      收藏:0      [点我收藏+]

标签:python   django   model   模板   继承   

http://blog.csdn.net/pipisorry/article/details/45061511

上篇:Django项目实践1 - 创建Django项目

Django模板

{视图和模板对逻辑和显示进行了分隔}

上面是使用 django.http.HttpResponse() 来输出"Hello World!"。该方式将数据与视图混合在一起,不符合Django的MVC思想。或者HTML被直接硬编码在 Python 代码之中。

html = "<html><body>It is now %s.</body></html>" % now

return HttpResponse(html)

Django 模板:模板是一个文本,用于分离文档的表现形式和内容。 模板定义了占位符以及各种用于规范文档该如何显示的各部分基本逻辑(模板标签)。 模板通常用于产生HTML,但是Django的模板也能产生任何基于文本格式的文档。

这样做的好处:

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

ython 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。

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

将页面的设计和Python的代码分离开会更干净简洁更容易维护。 使用 Django的 模板系统 (Template System)来实现这种模式。

通常将模板和视图一起使用,但是模板系统是一个Python库,你可以在任何地方使用它,而不仅仅是在Django视图中。

模板系统的使用-Python解释器

在Python代码中使用Django模板的最基本方式:

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

调用模板对象的render方法,并且传入一套变量context。它将返回一个基于模板的展现字符串,模板中的变量和标签会被context值替换。

使用Python的解释器使用模板的示例

转到project目录(在第二章由 django-admin.pystartproject 命令创建), 输入命令pythonmanage.pyshell 启动交互界面。

使用Django模板系统的基本规则

写模板,创建 Template 对象,创建Context , 调用render() 方法。

>>> from django import template
>>> t = template.Template(‘My name is {{ name }}.\n‘)
>>> c = template.Context({‘name‘: ‘Adrian‘})
>>> t.render(c)
‘My name is Adrian.\n‘
>>> c = template.Context({‘name‘: ‘Fred‘})
>>> print t.render(c)
My name is Fred.
 
Note:

1. 我们运行python manage.py shell而不是python。这两个命令都会启动交互解释器,但是manage.pyshell命令有一个重要的不同: 在启动解释器之前,它告诉Django使用哪个设置文件。 Django框架的大部分子系统,包括模板系统,都依赖于配置文件;如果Django不知道使用哪个配置文件,这些系统将不能工作。Django搜索DJANGO_SETTINGS_MODULE环境变量,它被设置在settings.py中。例如,假设mysite在你的Python搜索路径中,那么DJANGO_SETTINGS_MODULE应该被设置为:’mysite.settings’。当你运行命令:python manage.py shell,它将自动帮你处理DJANGO_SETTINGS_MODULE。 使用`` python manage.pyshell``这个方法,这样可以免去配置那些环境变量。随着你越来越熟悉Django,你可能会偏向于废弃使用`` manage.py shell``,而是在你的配置文件.bash_profile中手动添加DJANGO_SETTINGS_MODULE这个环境变量。

2. 创建Template 对象最简单的方法就是直接实例化它。当你创建一个Template 对象,模板系统在内部编译这个模板到内部格式,并做优化,做好 渲染的准备。

3. 模板渲染:用 context 来传递数据给模板。 一个context是一系列变量和它们值的集合。context在Django里表现为 Context 类,在 django.template 模块里。 她的构造函数带有一个可选的参数: 一个字典映射变量和它们的值。 调用 Template 对象 的 render() 方法并传递context来填充模板。t.render(c)返回的值是一个Unicode对象,不是普通的Python字符串。 在框架中,Django会一直使用Unicode对象而不是普通的字符串。

4. 在模板对象上调用 render() 方法,传递 context参数给它。 这是返回渲染后的模板的方法,它会替换模板变量为真实的值和执行块标签。

5. 使用同一模板源渲染多个context,只进行 一次模板创建然后多次调用render()方法渲染会更为高效:

# Good
t = Template(‘Hello, {{ name }}‘)
for name in (‘John‘, ‘Julie‘, ‘Pat‘):
    print t.render(Context({‘name‘: name}))
Django 模板解析非常快捷。 大部分的解析工作都是在后台通过对简短正则表达式一次性调用来完成。 这和基于 XML 的模板引擎形成鲜明对比,那些引擎承担了 XML 解析器的开销,且往往比 Django 模板渲染引擎要慢上几个数量级。

6. 输出里有回车换行的字符(‘\n‘ )而不是 显示回车换行? 因为这是Python交互解释器的缘故: 调用 t.render(c) 返回字符串, 解释器缺省显示这些字符串的 真实内容呈现 ,而不是打印这个变量的值。 要显示换行而不是 ‘\n‘ ,使用 print 语句: print t.render(c)上下文(context)对象

可以通过传递一个完全填充(full populated)的字典给 Context() 来初始化 上下文(Context) 。 但是初始化以后,你也可以使用标准的Python字典语法(syntax)向``上下文(Context)`` 对象添加或者删除条目:

>>> from django.template import Context
>>> c = Context({"foo": "bar"})
>>> c[‘foo‘]
‘bar‘
>>> del c[‘foo‘]
>>> c[‘foo‘]
Traceback (most recent call last):
  ...
KeyError: ‘foo‘
>>> c[‘newvariable‘] = ‘hello‘
深度变量的查找

Django 模板中遍历复杂数据结构的关键是句点字符 (.)。

通过实例变量加一点(dots)来访问它的属性,这个方法适用于任意的对象:

>>> person = {‘name‘: ‘Sally‘, ‘age‘: ‘43‘}
>>> t = Template(‘{{ person.name }} is {{ person.age }} years old.‘)
>>> d = datetime.date(1993, 5, 2)
>>> t = Template(‘The month is {{ date.month }} and the year is {{ date.year }}.‘)
点语法也可以用来引用对象的* 方法*:
>>> t = Template(‘{{ var }} -- {{ var.upper }} -- {{ var.isdigit }}‘)
>>> t.render(Context({‘var‘: ‘hello‘}))
u‘hello -- HELLO -- False‘
Note:
1. 这里调用方法时并* 没有* 使用圆括号 而且也无法给该方法传递参数;你只能调用不需参数的方法。
2. 仅在方法无需传入参数时,其调用才有效。 否则,系统将会转移到下一个查找类型(列表索引查找)。
句点也可用于访问列表索引:
>>> t = Template(‘Item 2 is {{ items.2 }}.‘)
>>> c = Context({‘items‘: [‘apples‘, ‘bananas‘, ‘carrots‘]})
Note:不允许使用负数列表索引。

句点查找规则概括:

当模板系统在变量名中遇到点时,按照以下顺序尝试进行查找:

  • 字典类型查找 (比如 foo["bar"] )

  • 属性查找 (比如 foo.bar )

  • 方法调用 (比如 foo.bar() )

  • 列表类型索引查找 (比如 foo[bar] )

系统使用找到的第一个有效类型。 这是一种短路逻辑。

句点查找可以多级深度嵌套。 例如在下面这个例子中 {{person.name.upper}} 会转换成字典类型查找(person[‘name‘] ) 然后是方法调用(upper() ):

>>> from django.template import Template, Context
>>> person = {‘name‘: ‘Sally‘, ‘age‘: ‘43‘}
>>> t = Template(‘{{ person.name.upper }} is {{ person.age }} years old.‘)

方法调用行为

方法调用比其他类型的查找略为复杂一点。 注意事项:

在方法查找过程中,如果某方法抛出一个异常,除非该异常有一个 silent_variable_failure 属性并且值为 True ,否则的话它将被传播。如果异常被传播,模板里的指定变量会被置为空字符串,比如:

>>> t = Template("My name is {{ person.first_name }}.")
>>> class PersonClass3:
...     def first_name(self):
...         raise AssertionError, "foo"
>>> p = PersonClass3()
>>> t.render(Context({"person": p}))
Traceback (most recent call last):
...
AssertionError: foo

>>> class SilentAssertionError(AssertionError):
...     silent_variable_failure = True
>>> class PersonClass4:
...     def first_name(self):
...         raise SilentAssertionError
>>> p = PersonClass4()
>>> t.render(Context({"person": p}))
u‘My name is .‘

显然,有些方法是有副作用的,好的情况下允许模板系统访问它们可能只是干件蠢事,坏的情况下甚至会引发安全漏洞。

例如,你的一个 BankAccount 对象有一个delete() 方法。如果某个模板中包含了像{{account.delete}}这样的标签,其中`` account`` 又是BankAccount 的一个实例,请注意在这个模板载入时,account对象将被删除。要防止这样的事情发生,必须设置该方法的alters_data 函数属性:

def delete(self):
    # Delete the account
delete.alters_data = True
模板系统不会执行任何以该方式进行标记的方法。 接上面的例子,如果模板文件里包含了 {{account.delete}} ,对象又具有 delete()方法,而且delete()alters_data=True这个属性,那么在模板载入时,delete()方法将不会被执行。 它将静静地错误退出。
处理无效变量

默认情况下,如果一个变量不存在,模板系统会把它展示为空字符串,不做任何事情来表示失败。 例如:

>>> from django.template import Template, Context
>>> t = Template(‘Your name is {{ name }}.‘)
>>> t.render(Context())
u‘Your name is .‘
>>> t.render(Context({‘var‘: ‘hello‘}))
u‘Your name is .‘
>>> t.render(Context({‘NAME‘: ‘hello‘}))
u‘Your name is .‘
对于一个web站点来说,如果仅仅因为一个小的模板语法错误而造成无法访问,这是不可接受的。

模板系统的使用-视图中的应用

重新打开前面VoteSite.views 中创建的current_datetime 视图:

def current_datetime(request):
    now = datetime.datetime.now()
    html = "<html><body>It is now %s.</body></html>" % now
    return HttpResponse(html)

让我们用 Django 模板系统来修改该视图,可能的修改:

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)
Note:上面确实使用了模板系统,但是并没有解决我们在本章开头所指出的问题。 也就是说,模板仍然嵌入在Python代码里,并未真正的实现数据与表现的分离。

下面采用模板自加载 跟 模板目录 的技巧:

模板加载

为了减少模板加载调用过程及模板本身的冗余代码,Django 提供了一种使用方便且功能强大的 API ,用于从磁盘中加载模板,要使用此模板加载API,首先你必须将模板的保存位置告诉框架。 设置的保存文件就是我们前一章节讲述ROOT_URLCONF配置的时候提到的settings.py。找到TEMPLATE_DIRS这项设置吧。 它的默认设置是一个空元组(tuple),加上一些自动生成的注释。

选择一个目录用于存放模板并将其添加到 TEMPLATE_DIRS 中:

TEMPLATE_DIRS = (
    ‘/home/django/mysite/templates‘,
)

Note:

1. 建议在 Django 项目中创建一个 templates 目录。如果你的TEMPLATE_DIRS只包含一个目录,别忘了在该目录后加上个逗号。Python 要求单元素元组中必须使用逗号,以此消除与圆括号表达式之间的歧义。

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

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

import os.path
TEMPLATE_DIRS = (
    os.path.join(os.path.dirname(__file__), ‘templates‘).replace(‘\\‘,‘/‘),
)
Note:这个例子使用了神奇的 Python 内部变量 __file__ ,该变量被自动设置为代码所在的 Python 模块文件名。 `` os.path.dirname(__file__)`` 将会获取自身所在的文件,即settings.py 所在的目录,然后由os.path.join 这个方法将这目录与 templates 进行连接。如果在windows下,它会智能地选择正确的后向斜杠”“进行连接,而不是前向斜杠”/”。

我们接着上面项目将在 HelloWorld 目录底下创建 templates 目录并建立 hello.html文件,整个目录结构如下:

HelloWorld/
|-- HelloWorld
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- settings.py
|   |-- settings.pyc
|   |-- urls.py
|   |-- urls.pyc
|   |-- view.py
|   |-- view.pyc
|   |-- wsgi.py
|   `-- wsgi.pyc
|-- manage.py
`-- templates
    `-- hello.html

hello.html 文件代码如下:

<h1>{{ hello }}</h1>
Note:关于html标签参阅[HTML教程 - 基本元素/标签及属性]
Django 视图(view.py)和Django 模板(templates中的html)

templates中的html文件决定了数据怎么显示(如上面的hello是以大标题的形式显示的),只是一个模板(没有真实数据),用于渲染数据。

下面修改后的view.py决定视图/html中要显示的数据/变量(模板中变量使用了双括号)是什么(如上面html中的hello代表‘Hello World!‘)。

Note:需要注意的是,不能简单的把 Django 视图认为是MVC控制器,把 Django 模板认为MVC视图。 区别在于:
     Django 视图 不处理用户输入,而仅仅决定要展现哪些数据给用户;
     Django 模板 仅仅决定如何展现Django视图指定的数据。

或者说, Django将MVC中的视图进一步分解为 Django视图 和 Django模板两个部分,分别决定 “展现哪些数据” 和 “如何展现”,使得Django的模板可以根据需要随时替换,而不仅仅限制于内置的模板。

改 views.py,增加一个新的对象,用于向html模板提交数据
# -*- coding: utf-8 -*-
from django.shortcuts import render

def hello(request):
    context          = {}
    context[‘hello‘] = ‘Hello pipi!‘
    return render(request, ‘hello.html‘, context)

Note:

1. 这里使用render来替代之前使用的HttpResponse。render还使用了一个字典context作为参数。 render_to_response() 只是对 get_template() 的简单封装。可以把模板存放在你模板目录的子目录中。注意:Windows用户必须使用斜杠而不是反斜杠。get_template() 假定的是 Unix 风格的文件名符号约定。

2. context 字典中元素的键值 "hello" 对应了模板中的变量 "{{ hello }}"。

3. 以上代码比较low的写法:

def current_datetime(request):
    now = datetime.datetime.now()
    t = get_template(‘current_datetime.html‘)
    html = t.render(Context({‘current_date‘: now}))

4.另一种更高大上的写法

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

在此,我们没有像之前那样手工指定 context 字典,而是传入了 locals() 的值,它囊括了函数执行到该时间点时所定义的一切变量。 因此,我们将 now 变量重命名为 current_date ,因为那才是模板所预期的变量名称。 在本例中,locals() 并没有带来多 的改进,但是如果有多个模板变量要界定而你又想偷懒,这种技术可以减少一些键盘输入。

使用 locals() 时要注意是它将包括 所有 的局部变量,它们可能比你想让模板访问的要多。 在前例中, locals() 还包含了request 。对此如何取舍取决你的应用程序。

浏览器中查看结果

在浏览器访问打开浏览器并访问:192.168.*.*:8000/hello/

输出:Hello pipi!

这样我们就完成了使用模板来输出数据,从而实现数据(view中的数据)与视图(html文件)分离。

模板中常用的语法规则

{最新版本的Django语法可能有改变,不支持的操作可能支持了。[HTML教程 - 基本元素/标签及属性]}
Django 模板标签
if/else 标签
1. 基本语法格式如下:
{% if condition %}
     ... display
{% endif %}

或者:

{% if condition1 %}
   ... display 1
{% elif condiiton2 %}
   ... display 2
{% else %}
   ... display 3
{% endif %}

根据条件判断是否输出。if/else 支持嵌套。

Note:模板标签中的变量是不用{{}}包含的。

2. {% if %} 标签接受 and , or 或者 not 关键字来对多个变量做判断 ,或者对变量取反( not ),例如:

{% if athlete_list and coach_list %}
     athletes 和 coaches 变量都是可用的。
{% endif %}

Note:

1. {% if %} 标签不允许在同一个标签中同时使用 andor ,因为逻辑上可能模糊的,这样的代码是不合法的:

{% if athlete_list and coach_list or cheerleader_list %}
2. 系统不支持用圆括号来组合比较操作。 如果你确实需要用到圆括号来组合表达你的逻辑式,考虑将它移到模板之外处理,然后以模板变量的形式传入结果吧。 或者,仅仅用嵌套的{%if%}标签替换

for 标签

1. {% for %} 允许我们在一个序列上迭代。与Python的 for 语句的情形类似,循环语法是 for X in Y ,Y是要迭代的序列而X是在每一个特定的循环中使用的变量名称。

每一次循环中,模板系统会渲染在 {% for %} 和 {% endfor %} 之间的所有内容。

例如,给定一个运动员列表 athlete_list 变量,我们可以使用下面的代码来显示这个列表:
<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

2. 给标签增加一个 reversed 使得该列表被反向迭代:

{% for athlete in athlete_list reversed %}

3. 可以嵌套使用 {% for %} 标签。

在执行循环之前先检测列表的大小是一个通常的做法,当列表为空时输出一些特别的提示。`` for`` 标签支持一个可选的`` {% empty %}`` 分句,通过它我们可以定义当列表为空时的输出内容 下面的例子与用if-else实现等价:

{% for athlete in athlete_list %}
    <p>{{ athlete.name }}</p>
{% empty %}
    <p>There are no athletes. Only computer programmers.</p>
{% endfor %}

4. Django不支持退出循环操作。 如果我们想退出循环,可以改变正在迭代的变量,让其仅仅包含需要迭代的项目。 同理,Django也不支持continue语句,我们无法让当前迭代操作跳回到循环头部。

5.在每个`` {% for %}``循环里有一个称为`` forloop`` 的模板变量。这个变量有一些提示循环进度信息的属性。

forloop.counter 总是一个表示当前循环的执行次数的整数计数器。 这个计数器是从1开始的,所以在第一次循环时forloop.counter 将会被设置为1。

{% for item in todo_list %}
    <p>{{ forloop.counter }}: {{ item }}</p>
{% endfor %}

forloop.counter0 类似于forloop.counter ,但是它是从0计数的。 第一次执行循环时这个变量会被设置为0。

forloop.revcounter 是表示循环中剩余项的整型变量。 在循环初次执行时forloop.revcounter 将被设置为序列中项的总数。 最后一次循环执行中,这个变量将被置1。

forloop.revcounter0 类似于forloop.revcounter ,但它以0做为结束索引。在第一次执行循环时,该变量会被置为序列的项的个数减1。

forloop.first 是一个布尔值,如果该迭代是第一次执行,那么它被置为```` 在下面的情形中这个变量是很有用的:

System Message: WARNING/2 (<string>, line 1071);backlink

Inline literal start-string without end-string.

{% for object in objects %}
    {% if forloop.first %}<li class="first">{% else %}<li>{% endif %}
    {{ object }}
    </li>
{% endfor %}

forloop.last 是一个布尔值;在最后一次执行循环时被置为True。 一个常见的用法是在一系列的链接之间放置管道符(|),另一个常见的用途是为列表的每个单词的加上逗号。

{% for link in links %}{{ link }}{% if not forloop.last %} | {% endif %}{% endfor %}

上面的模板可能会产生如下的结果:

Link1 | Link2 | Link3 | Link4
      forloop.parentloop 是一个指向当前循环的上一级循环的forloop 对象的引用(在嵌套循环的情况下)。
{% for country in countries %}
    <table>
    {% for city in country.city_list %}
        <tr>
        <td>Country #{{ forloop.parentloop.counter }}</td>
        <td>City #{{ forloop.counter }}</td>
        <td>{{ city }}</td>
        </tr>
    {% endfor %}
    </table>
{% endfor %}

forloop 变量仅仅能够在循环中使用。 在模板解析器碰到{%endfor%}标签后,forloop就不可访问了。

6. Context和forloop变量

在一个 {% for%} 块中,已存在的变量会被移除,以避免forloop 变量被覆盖。 Django会把这个变量移动到forloop.parentloop 中。通常我们不用担心这个问题,但是一旦我们在模板中定义了forloop 这个变量(当然我们反对这样做),在{% for%} 块中它会在 forloop.parentloop 被重新命名。

ifequal/ifnotequal 标签

1. {% ifequal %} 标签比较两个值,当他们相等时,显示在 {% ifequal %} 和 {% endifequal %} 之中所有的值。

下面的例子比较两个模板变量 user 和 currentuser :

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

Note:只有模板变量,字符串,整数和小数可以作为 {% ifequal %} 标签的参数。其他任何类型,例如Python的字典类型、列表类型、布尔类型,不能用在{%ifequal%} 中。

2. {% ifequal %} 支持可选的 {% else%} 标签:8

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

注释标签

1. Django单行注释使用 {# #}。

{# 这是一个注释 #}

用这种语法的注释不能跨越多行。 这个限制是为了提高模板解析的性能。 在下面这个模板中,输出结果和模板本身是 完全一样的(也就是说,注释标签并没有被解析为注释):

This is a {# this is not
a comment #}
test.

2. 实现多行注释,可以使用`` {% comment %}`` 模板标签

{% comment %}
This is a
multi-line comment.
{% endcomment %}
过滤器

1. 模板过滤器可以在变量被显示前修改它,过滤器使用管道字符,如下所示:

{{ name|lower }}

{{ name }} 变量被过滤器 lower 处理后,文档大写转换文本为小写。

2. 过滤管道可以被* 套接* ,既是说,一个过滤器管道的输出又可以作为下一个管道的输入:

{{ my_list|first|upper }}

以上实例将第一个元素并将其转化为大写。

3. 有些过滤器有参数。 过滤器的参数跟随冒号之后并且总是以双引号包含。 例如:

{{ bio|truncatewords:"30" }}

这个将显示变量 bio 的前30个词。

4. 其他过滤器:

  • addslashes : 添加反斜杠到任何反斜杠、单引号或者双引号前面。
  • date : 按指定的格式字符串参数格式化 date 或者 datetime 对象,实例:
    {{ pub_date|date:"F j, Y" }}     #将变量ship_date传递给date过滤器,同时指定参数”F j,Y”。date过滤器根据参数进行格式输出。如时间的显示 April 2, 2009 是按 ‘F j, Y‘ 格式显示的。
  • length : 返回变量的长度。你可以对列表或者字符串,或者任何知道怎么测定长度的Python 对象使用这个方法(也就是说,有 __len__() 方法的对象)。
Note:过滤器是用管道符(|)来调用的,具体可以参见Unix管道符。
include 标签
该标签允许在(模板中)包含其它的模板的内容。 标签的参数是所要包含的模板名称,可以是一个变量,也可以是用单/双引号硬编码的字符串。 每当在多个模板中出现相同的代码时,就应该考虑是否要使用{% include%} 来减少重复。

下面这两个例子都包含了 nav.html 模板:

{% include "nav.html" %}

Note:

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

2.如果{%include %}标签指定的模板没找到,Django将会在下面两个处理方法中选择一个:

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

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


模板继承

模板可以用继承的方式来实现复用。在整个网站中,如何减少共用页面区域(比如站点导航)所引起的重复和冗余代码?

解决该问题的传统做法是使用 服务器端的 includes ,你可以在 HTML 页面中使用该指令将一个网页嵌入到另一个中。 事实上, Django 通过刚才讲述的 {% include %} 支持了这种方法。 但是用 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>
Note:

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

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

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

4. 你可以根据需要使用任意多的继承次数。

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

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

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

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

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

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

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

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

  • 如果你需要访问父模板中的块的内容,使用 {{block.super}}这个标签吧,这一个魔法变量将会表现出父模板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。

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

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

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

实例:创建之前项目的 templates 目录中添加 base.html 文件
<html>
  <head>
    <title>Title pipi!</title>
  </head>

  <body>
    <h1>Hello pipi!</h1>
    {% block mainbody %}
       <p>original</p>
    {% endblock %}
  </body>
</html>

hello.html中继承base.html,并替换特定block,hello.html修改后的代码如下:

{% extends "base.html" %}

{% block mainbody %}
<p>继承base.html文件, 替换original</p>
{% endblock %}

Note:第一行代码说明hello.html继承了 base.html 文件。可以看到,这里相同名字的block标签用以替换base.html的相应block。

重新访问地址http://192.168.*.*:8000/hello/

输出:

技术分享

下篇:Django项目实践3 - Django模型

from:http://blog.csdn.net/pipisorry/article/details/45061511


Django项目实践2 - Django模板

标签:python   django   model   模板   继承   

原文地址:http://blog.csdn.net/pipisorry/article/details/45061511

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!