Python 学习笔记

高级模板

2018-02-04  本文已影响2人  大爷的二舅

虽然大部分与Django模板语言的交互都是模板作者的角色,但您可能需要自定义和扩展模板引擎 - 要么做一些它还没有做的事情,要么用另一种方式让你的工作更轻松一些。

本章深入研究了Django模板系统的内涵。 它涵盖了如果您计划扩展系统或者只是对其工作原理感到好奇,您需要知道的内容。 它还涵盖了自动转义功能,在您继续使用Django时,您将毫无疑问地注意到一个安全措施。

模板语言回顾

首先,让我们快速回顾一下第3章中介绍的一些术语:

{% if is_logged_in %}           
  Thanks for logging in!
  {% else %}           
  Please log in.
  {% endif %}

变量是输出值的模板中的符号。可变标签由{{and}}包围:

 My first name is {{ first_name }}. My last name is {{ last_name }}.

有关这些术语的基本知识的更多详细信息,请参阅第3章。本章其余部分讨论扩展模板引擎的方法。 首先,为了简单起见,我们快速浏览第3章中的一些内部部分。

RequestContext和上下文处理器

渲染模板时,需要一个上下文。 这可以是django.template.Context的一个实例,但是Django也带有一个子类django.template.RequestContext,它的行为稍有不同。

RequestContext默认将一堆变量添加到模板上下文中 - 例如HttpRequest对象或当前登录用户的信息。

render()快捷方式创建一个RequestContext,除非它明确地传递了一个不同的上下文实例。 例如,考虑这两个观点:

from django.template import loader, Context

def view_1(request):
    # ...
    t = loader.get_template('template1.html')
    c = Context({
        'app': 'My app',
        'user': request.user,
        'ip_address': request.META['REMOTE_ADDR'],
        'message': 'I am view 1.'
    })
    return t.render(c)

def view_2(request):
    # ...
    t = loader.get_template('template2.html')
    c = Context({
        'app': 'My app',
        'user': request.user,
        'ip_address': request.META['REMOTE_ADDR'],
        'message': 'I am the second view.'
    })
    return t.render(c)

(请注意,在这些示例中我故意不使用render()快捷方式 - 我们正在手动加载模板,构建上下文对象并呈现模板,我正在“拼出”所有步骤 明晰。)

每个视图将相同的三个变量--app,user和ip_address - 传递给它的模板。 如果我们可以删除冗余,不是很好吗? 创建RequestContext和上下文处理器来解决这个问题。 上下文处理器允许您指定一些变量,这些变量在每个上下文中自动设置,而不必在每个render()调用中指定变量。

问题在于,当您呈现模板时,您必须使用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 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 t.render(c)

我们来看看这个代码:

为了演示上下文处理器的低级工作,上面的例子没有使用render()。 但是可能的 - 也是可取的 - 通过render()使用上下文处理器。 使用context_instance参数执行此操作,如下所示:

from django.shortcuts import render
from django.template import 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):
    # ...
    return render(request, 'template1.html',
                  {'message': 'I am view 1.'},
                  context_instance=RequestContext(
                  request, processors=[custom_proc]
                  )
    )

def view_2(request):
    # ...
    return render(request, 'template2.html', 
                  {'message': 'I am the second view.'},
                  context_instance=RequestContext(
                  request, processors=[custom_proc]
                  )
)

在这里,我们已经将每个视图的模板渲染代码修剪成单个(包装)线。 这是一个改进,但是,为了评估这个代码的简洁性,我们不得不承认,我们现在几乎已经过剩了。 我们已经删除了冗余数据(我们的模板变量),代价是在代码中添加冗余(在处理器调用中)。

如果您必须始终键入处理器,则使用上下文处理器并不会节省您太多的打字时间。 出于这个原因,Django提供了对全局上下文处理器的支持。 context_processors设置(在您的settings.py中)指定应始终将哪个上下文处理器应用于RequestContext。 这消除了每次使用RequestContext时都需要指定处理器的情况。

默认情况下,context_processors被设置为以下内容:

'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',
            'django.contrib.messages.context_processors.messages',
        ],

这个设置是一个使用与我们上面的custom_proc函数相同的接口的可调用列表 - 将请求对象作为参数的函数,并返回要合并到上下文中的项目字典。 请注意,context_processors中的值被指定为字符串,这意味着处理器需要位于Python路径的某处(所以您可以从设置中引用它们)。

每个处理器按顺序应用。 也就是说,如果一个处理器将一个变量添加到上下文中,并且第二个处理器添加一个具有相同名称的变量,则第二个处理器将覆盖第一个。 Django提供了许多简单的上下文处理器,包括默认启用的处理器:

AUTH

django.contrib.auth.context_processors.auth

如果此处理器已启用,则每个RequestContext都将包含这些变量:

DEBUG

django.template.context_processors.debug

如果此处理器已启用,则每个RequestContext都将包含这两个变量 - 但仅当您的DEBUG设置设置为True且请求的IP地址(request.META ['REMOTE_ADDR'])处于INTERNAL_IPS设置时:

国际化

django.template.context_processors.i18n

如果启用这个处理器,每个RequestContext将包含这两个变量:

媒体

django.template.context_processors.media

如果启用此处理器,则每个RequestContext都将包含一个变量MEDIA_URL,提供MEDIA_URL设置的值。

静态的

django.template.context_processors.static

如果启用此处理器,则每个RequestContext都将包含一个变量STATIC_URL,提供STATIC_URL设置的值。

CSRF

django.template.context_processors.csrf

这个处理器增加了一个csrf_token模板标签所需要的标记来保护跨站请求伪造(见第19章)。

请求

django.template.context_processors.request

如果启用了这个处理器,每个RequestContext将包含一个变量请求,它是当前的HttpRequest。

消息

django.contrib.messages.context_processors.messages

如果启用这个处理器,每个RequestContext将包含这两个变量:

上一篇下一篇

猜你喜欢

热点阅读