zoukankan      html  css  js  c++  java
  • 第四章:模板系统篇

    如果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 %} 的参数应该是字符串,但是如果直到运行时方能确定父模板名,这个参数也可以是个变量。这使得你能够实现一些很酷的动态功能。

     

     

     


     

     

     

     

  • 相关阅读:
    Autodesk Infrastructure Map Server(AIMS)/MapGuide API 培训材料第6章
    安装Vault Professional Server的一些问题
    Autodesk Infrastructure Map Server(AIMS)/MapGuide API 培训材料第2章
    C++的构造函数和析构函数
    一些常用的字符串hash函数
    类的operator new与operator delete的重载
    计算字符串的相似度(编辑距离)
    C++的重载(overload)与重写(override)
    穷举法解24点游戏
    C语言字符串库函数的实现
  • 原文地址:https://www.cnblogs.com/lhj588/p/2231277.html
Copyright © 2011-2022 走看看