django book学习笔记——模板高级进阶

1.RequestContext和Context处理器

当你不想在一系例模板中都明确指定一些相同的变量时,你应该使用 RequestContext 。例如:

from django.template import loader, RequestContext

def custom_proc(request):
    "A context processor that provides ‘app‘, ‘user‘ and ‘ip_address‘."
    return {
        ‘app‘: ‘My app‘,
        ‘user‘: request.user,
        ‘ip_address‘: request.META[‘REMOTE_ADDR‘]
    }

def view_1(request):
    # ...
    t = loader.get_template(‘template1.html‘)
    c = RequestContext(request, {‘message‘: ‘I am view 1.‘},
            processors=[custom_proc])
    return HttpResponse(t.render(c))

def view_2(request):
    # ...
    t = loader.get_template(‘template2.html‘)
    c = RequestContext(request, {‘message‘: ‘I am the second view.‘},
            processors=[custom_proc])
    return HttpResponse(t.render(c))

RequestContext和Context在context对象的构建上有两个不同点。一, RequestContext 的第一个参数需要传递一个 HttpRequest 对象,就是传递给视图函数的第一个参数(request )。二, RequestContext 有一个可选的参数 processors ,这是一个包含context处理器函数的list或者tuple。

另外,Django还提供对 全局 context处理器的支持。 TEMPLATE_CONTEXT_PROCESSORS 指定了 总是 使用哪些 context processors 。这样就省去了每次使用 RequestContext 都指定 processors 的麻烦。例如:(/usr/lib/python2.6/site-packages/django/conf/global_settings.py)

TEMPLATE_CONTEXT_PROCESSORS = (
    ‘django.contrib.auth.context_processors.auth‘,
    ‘django.core.context_processors.debug‘,
    ‘django.core.context_processors.i18n‘,
    ‘django.core.context_processors.media‘,
    ‘django.core.context_processors.static‘,
    ‘django.core.context_processors.tz‘,
#    ‘django.core.context_processors.request‘,
    ‘django.contrib.messages.context_processors.messages‘,
)

2.html自动转义

从模板生成html的时候,总是有一个风险——变量包了含会影响结果html的字符。例如:

Hello, {{ name }}.

这看起来是显示用户名的一个无害的途径,但是考虑如果用户输入如下的名字将会发生什么:

<script>alert(‘hello‘)</script>

用这个用户名,模板将被翻译成:

Hello, <script>alert(‘hello‘)</script>

这意味着浏览器将弹出JavaScript警告框!

为了避免这个问题,你有两个选择:

一是你可以确保每一个不被信任的变量通过过滤器,它把潜在有害的html字符转换为无害的。

二是,你可以利用django的自动html转意。

在django里默认情况下,每一个模板自动转意每一个变量标签的输出。 尤其是这五个字符。

< 被转意为 &lt;

> 被转意为 &gt;

‘ (single quote) 被转意为 '

" (double quote) 被转意为 &quot;

& 被转意为 &amp;

注:自动转义默认是开启的。 如果你正在使用django的模板系统,那么你是被保护的。

3.如何关闭自动转义

1).用safe过滤器为单独的变量关闭自动转意:

This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}

2).为了控制模板的自动转意,用标签autoescape来包装整个模板:

{% autoescape off %}
    Hello {{ name }}
{% endautoescape %}

注:autoescape 标签有两个参数on和off

3.扩展模板系统

创建一个模板库:不管是写自定义标签还是过滤器,第一件要做的事是创建模板库(Django能够导入的基本结构)。

创建一个模板库分两步走:

第一,决定哪个Django应用应当拥有这个模板库。如果你通过 manage.py startapp 创建了一个应用,你可以把它放在那里,或者你可以为模板库单独创建一个应用。无论你采用何种方式,请确保把你的应用添加到 INSTALLED_APPS 中。

第二,在适当的Django应用包里创建一个 templatetags 目录。 这个目录应当和 models.pyviews.py 等处于同一层次。在 templatetags 中创建两个空文件: 一个 __init__.py (告诉Python这是
一个包含了Python代码的包)和一个用来存放你自定义的标签/过滤器定义的文件。 第二个文件 的名字稍后将用来加载标签。例如,如果你的自定义标签/过滤器在一个叫作 poll_extras.py 的文件中,你需要在模板中写入如下内容:

{% load poll_extras %}

注:{% load %} 标签检查 INSTALLED_APPS 中的设置,仅允许加载已安装的Django应用程序中的模板库。

作为合法的标签库,模块需要包含一个名为register的模块级变量。这个变量是template.Library的实例,是所有注册标签和过滤器的数据结构。

from django import template

register = template.Library()

1).自定义模板过滤器

自定义过滤器就是有一个或两个参数的Python函数。过滤器函数应该总有返回值,而且不能触发异常,它们都应该静静的失败。 如果有一个错误发生,它们要么返回原始的输入字符串,要么返回空的字符串,无论哪个都可以。例如:

def cut(value, arg):
    "Removes all values of arg from the given string"
    return value.replace(arg, ‘‘)

当你在定义你的过滤器时,你需要用 Library 实例来注册它,这样就能通过Django的模板语言来使用了:

register.filter(‘cut‘, cut)

如果你使用的是Python 2.4或更新,你可以使用 register.filter() 作为一个装饰器:

from django import template

register = template.Library()

@register.filter(name=‘cut‘)
def cut(value, arg):
    return value.replace(arg, ‘‘)

2).自定义模板标签

模板系统的两步处理过程:编译和呈现。当Django编译一个模板时,它将原始模板分成一个个 节点 。每个节点都是 django.template.Node 的一个实例,并且具备 render() 方法。当你调用一个已编译模板的 render() 方法时,模板就会用给定的context来调用每个在它的节点列表上的节点的 render() 方法。

(a).编写编译函数:当遇到一个模板标签(template
tag)时,模板解析器就会把标签包含的内容,以及模板解析器自己作为参数调用一个python函数。
这个函数负责返回一个和当前模板标签内容相对应的节点(Node)的实例。例如,写一个显示当前日期的模板标签:

<p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>

这个函数的分析器会获取参数并创建一个 Node 对象:

from django import template

register = template.Library()

def do_current_time(parser, token):
    try:
        # split_contents() knows not to split quoted strings.
        tag_name, format_string = token.split_contents()
    except ValueError:
        msg = ‘%r tag requires a single argument‘ % token.split_contents()[0]
        raise template.TemplateSyntaxError(msg)
    return CurrentTimeNode(format_string[1:-1])

注:token.contents 是包含有标签原始内容的字符串。模板标签编译函数 必须 返回一个 Node 子类,返回其它值都是错的。

(b).编写模板节点:编写自定义标签的第二步就是定义一个拥有 render() 方法的 Node 子类。

import datetime

class CurrentTimeNode(template.Node):
    def __init__(self, format_string):
        self.format_string = str(format_string)

    def render(self, context):
        now = datetime.datetime.now()
        return now.strftime(self.format_string)

这两个函数( __init__render )与模板处理中的两步(编译与渲染)直接对应。 这样,初始化函数仅仅需要存储后面要用到的格式字符串,而
render() 函数才做真正的工作。

(c).注册标签

register.tag(‘current_time‘, do_current_time)

和注册过滤器类似,也可以在Python2.4及其以上版本中使用 register.tag 修饰:

@register.tag(name="current_time")
def do_current_time(parser, token):
    # ...

4.简单标签

许多模板标签接收单一的字符串参数或者一个模板变量 引用,然后独立地根据输入变量和一些其它外部信息进行处理并返回一个字符串.为了简化这类标签,Django提供了一个帮助函数simple_tag。这个函数是django.template.Library的一个方法,它接受一个只有一个参数的函数作参数。

我们之前的的 current_time 函数于是可以写成这样:

def current_time(format_string):
    try:
        return datetime.datetime.now().strftime(str(format_string))
    except UnicodeEncodeError:
        return ‘‘

register.simple_tag(current_time)

在Python 2.4中,也可以使用修饰语法:

@register.simple_tag
def current_time(string):
    # ...

有关 simple_tag 辅助函数,需要注意下面一些事情:

  • 传递给我们的函数的只有(单个)参数。
  • 在我们的函数被调用的时候,检查必需参数个数的工作已经完成了,所以我们不需要再做这个工作。
  • 参数两边的引号(如果有的话)已经被截掉了,所以我们会接收到一个普通字符串。

5.包含标签

另外一类常用的模板标签是通过渲染 其他 模板显示数据的。意思就是说在一个模板中通过调用另一个模板显示数据。

首先,我们定义一个函数,通过给定的参数生成一个字典形式的结果。 需要注意的是,我们只需要返回字典类型的结果就行了,它将被用做模板片断的context。

from books.models import Book

@register.inclusion_tag(‘book_snippet.html‘)
def books_for_author(author):
    books = Book.objects.filter(authors__id=author.id)
    return {‘books‘: books}

接下来,我们创建用于渲染标签输出的模板book_snippet.html。

<ul>
{% for book in books %}
    <li>{{ book.title }}</li>
{% endfor %}
</ul>

最后,创建主模板result_snippet.html并调用。

# view.py
from django.http import HttpResponse
from django.template import loader, RequestContext
from books.models import Author

def view_2(request):
    # ...
    author = Author.objects.get(first_name="wang",last_name="yongbin")
    t = loader.get_template(‘result_snippet.html‘)
    c = RequestContext(request, {‘author‘: author},
            processors=[custom_proc])
    return HttpResponse(t.render(c))
    
# url.py
urlpatterns = patterns(‘‘,
    (r‘^inclusion/$‘,view_2),
)

# result_snippet.html

{% load mytag %}
{% books_for_author author %}

最后显示作者为wang yongbin的书籍的列表。

时间: 2024-11-17 11:09:28

django book学习笔记——模板高级进阶的相关文章

django book学习笔记——模型高级进阶

1.访问外键(Foreign Key)值 当你获取一个为ForeignKey 字段时,你会得到相关的数据模型对象. 例如: >>> b = Book.objects.get(id=50) >>> b.publisher <Publisher: Apress Publishing> >>> b.publisher.website u'http://www.apress.com/' 对于用 ForeignKey 来定义的关系来说,在关系的另一端

django book学习笔记——模板

1.模板系统的基本知识 模板是一个文本,用于分离文档的表现形式和内容. 模板定义了占位符以及各种用于规范文档该如何显示的各部分基本逻辑(模板标签). 模板通常用于产生HTML,但是Django的模板也能产生任何基于文本格式的文档. 2.如何使用模板系统 在Python代码中使用Django模板的最基本方式如下: 1).可以用原始的模板代码字符串创建一个 Template 对象, Django同样支持用指定模板文件路径的方式来创建 Template 对象; 2).调用模板对象的render方法,并

Hadoop学习笔记(7) ——高级编程

Hadoop学习笔记(7) ——高级编程 从前面的学习中,我们了解到了MapReduce整个过程需要经过以下几个步骤: 1.输入(input):将输入数据分成一个个split,并将split进一步拆成<key, value>. 2.映射(map):根据输入的<key, value>进生处理, 3.合并(combiner):合并中间相两同的key值. 4.分区(Partition):将<key, value>分成N分,分别送到下一环节. 5.化简(Reduce):将中间结

APUE 学习笔记(九) 高级I/O

1. 非阻塞I/O 低速系统调用时可能会使进程永远阻塞的一类系统调用,包括以下调用: (1)某些文件类型你(网络socket套接字.终端设备.管道)暂无可使用数据,则读操作可能会使调用者永远阻塞 (2)如果数据不能立即被(1)中文件类型接受,则写操作会使调用者永远阻塞 (3)某些进程间通信函数 非阻塞I/O使我们可以调用open.read.write这样的I/O操作,并使这些操作不会永远阻塞,如果这种操作不能完成,则调用立即出错返回 对于一个给定的文件有两种方法对其指定非阻塞I/O: (1)调用

APUE 学习笔记(十) 高级I/O

1. Unix IPC(InterProcess Communication) 同一主机的各个进程间的IPC:管道.FIFO.消息队列.信号量.共享存储器 不同主机上的各个进程间IPC:socket套接字 2. 管道 管道进行IPC有两个局限: (1) 半双工,即数据只能在一个方向上流动 (2) 只能在具有公共祖先的进程之间使用.通常,一个管道由一个进程创建,然后该进程调用fork,此后 父子进程之间可以使用该管道 fstat函数对管道的每一端都返回一个FIFO类型的文件描述符,可以用S_ISF

Linux System Programming 学习笔记(四) 高级I/O

1. Scatter/Gather I/O a single system call  to  read or write data between single data stream and multiple buffers This type of I/O is so named because the data is scattered into or gathered from the given vector of buffers Scatter/Gather I/O 相比于 C标准

django book学习笔记——高级视图和URL配置

1.URLconf技巧 1).流线型化函数导入 在 URLconf 中的每一个入口包括了它所联系的视图函数,直接传入了一个函数对象. 这就意味着需要在模块开始处导入视图函数.但随着 Django 应用变得复杂,它的 URLconf 也在增长,并且维护这些导入可能使得管理变麻烦. 为了避免这种麻烦,Django 提供了一种方法可以在 URLconf 中为某个特别的模式指定视图函数: 你可以传入一个包含模块名和函数名的字符串,而不是函数对象本身.例如: from django.conf.urls.d

django+mysql学习笔记

这段时间在学习mysql+django的知识点.借此记录以下学习过程遇到的坑以及心得. 使用的工具是navicat for mysql python 2.7.12 mysql-python 1.2.3 . 首先在次目录下新建一个数据库(students_info),记下用户名,密码,端口......此数据库后续会在settings.py中进行对接. django与database对接的操作流程: 1.你得先告诉django数据库的相关信息,后续框架会自动去根据这些信息访问数据库不用你操心了. 代

学习笔记——模板模式Template

模板模式,主要是利用多态来实现具体算法和父类逻辑的松耦合.父类中TemplateMethod内部定义了相应的算法操作顺序,子类负责实现相应的具体实现. 举例: 项目中曾遇到过一个需求,叫做高级价格体系.它对外的调用接口一致,只是在不同的应用场景下(比如普通消费和会员卡消费)计算方法有差异,简化计算流程: 1.初始化相应数据A() 2.执行价格计算B() 3.计算完成后的提示C() 等. 父类中的接口函数Run()将此顺序固定为: Run() { A(); B(); C(); } 不同场景下的子类