一、上下文管理
- 阶段一:原始方法,手动构造上下文
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)
- 阶段二:优化,使用上下文管理器
from django.shortcuts import render
from django.template import RequestContext
#定义上下文管理器
def custom_proc(request):
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])
)
- 最终版:Django提供全局上下文管理器
Django 提供了全局上下文处理 器。context_processors 设置(在 settings.py 文件中)指明始终提供给 RequestContext 的上下文处理器。 这样便不用每次使用 RequestContext 时都指定 processors 参数了。
from django.shortcuts import render
def view_1(request):
return render(request, 'template1.html',{'message': 'I am view 1.'})
- 自定义上下文处理器
上下文处理器的接口十分简单,它就是普通的 Python 函数,有一个参数,是一个 HttpRequest 对象,返回一 个字典,用于添加到模板上下文中。上下文处理器必须返回一个字典。
-
自定义的上下文处理器可以放在代码基的任何位置。Django 只关心 TEMPLATES 设置中的 ‘con- text_processors’ 选项或者 Engine 的 context_processors 参数(直接使用 Engine 时)有没有指向你 的上下文处理器。尽管如此,约定的做法是把上下文处理器保存在应用或项目中一个名为 con- text_processors.py 的文件中。
二、模板加载机制
Django 在多个位置搜索模板目录,具体是哪些取决于模板加载设置,指定模板目录最基本的方式是使用 DIRS 选项。DIRS告诉 Django 模板目录有哪些的方法是使用设置文件中 TEMPLATES 设置的 DIRS 选项,或者是 Engine 的 dirs 参数。这个选项的值是一个字符串列表,包含指向模板目录的完整路径
- myblog/settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# 系统加载,'DIRS'是一个字符串列表,包含指向模板目录的完整路径
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
],
# 应用目录加载 自动查找/myblogs/books/templtates下的模板
'APP_DIRS': True,
}, ]
三、扩展模板系统
对模板系统的定制,基本上是自 定义模板标签和(或)过滤器。
-
自定义的模板标签和过滤器必须放在一个 Django 应用中。如果与现有应用有关,可以放在现有应用中;否 则,应该专门创建一个应用存放。应用中应该有个 templatetags 目录,与 models.py、views.py 等文件放在 同一级。如果没有这个目录,创建一个,别忘了 init.py 文件,这样才能保证所在目录是一个 Python 包.
代码布局
- 创建模板标签和过滤器
假如自定义的标签(过滤器)放在 review_extras.py 文件中,应用的布局可能是下面这样:
books/
__init__.py
models.py
templatetags/
__init__.py
review_extras.py
views.py
- 在模板中使用
{% load review_extras %}
包含自定义标签的应用必须在 INSTALLED_APPS 中列出,这样 {% load %} 标签才能起作用。
自定义模板过滤器实例
- 定义并注册过滤器:myblog/books/templatetags/review_extras.py
方式一:
from django import template
register = template.Library()
#定义过滤器函数
def cut(value, arg):
"""Removes all values of arg from the given string"""
return value.replace(arg, '')
#注册过滤器:第一个参数为过滤器名,第二个参数为对应的函数
register.filter('cut', cut)
register.filter('lower', lower)
方式二:
from django import template
register = template.Library()
@register.filter
def cut(value, arg):
"""Removes all values of arg from the given string"""
return value.replace(arg, '')
- 使用
{{ value|cut:"arg" }}
- 定义期待字符串的模板过滤器时,需使用@stringfilter
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
@register.filter
@stringfilter #参数在传给过滤器之前会先转换成字符串值
def lower(value):
return value.lower()
- 定义处理 datetime 对象的过滤器时,需使设置expects_localtime 旗标参数为 True
@register.filter(expects_localtime=True)
def businesshours(value):
try:
return 9 <= value.hour < 17
except AttributeError:
return ''
自定义模板标签
- 一、简单实例
current_time 标签,它接受一个格式字符串,返回格式化后的时间字符串
import datetime
from django import template
register = template.Library()
@register.simple_tag
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
- 二、模板标签需要使用上下文
如果模板标签需要访问当前上下文,注册标签时指定 takes_context 参数:
@register.simple_tag(takes_context=True)
def current_time(context, format_string):
timezone = context['timezone']
return your_get_current_time_method(timezone, format_string)
- 三、为标签起别名
方式一:
register.simple_tag(lambda x: x - 1, name='minusone')
方式二:
@register.simple_tag(name='minustwo')
def some_function(value):
return value - 2
- 四、接收参数
定义标签
@register.simple_tag
def my_tag(a, b, *args, **kwargs):
warning = kwargs['warning']
profile = kwargs['profile']
...
return ...
使用
{% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}
- 五、引入标签(模板标签用于渲染另一个模板)
需求:编写一个标签,生成指定Author 对象名下的图书列表
#使用:
{% books_for_author author %}
#结果:
<ul>
<li>The Cat In The Hat</li>
<li>Hop On Pop</li>
<li>Green Eggs And Ham</li>
</ul>
实现:
#定义一个接受参数的函数,生成一个字典,为结果提供数据
def books_for_author(author):
books = Book.objects.filter(authors__id=author.id)
return {'books': books}
books/templates/book_snippet.html
#创建用于渲染标签输出的模板,需放在模板目录下
<ul>
{% for book in books %}
<li>{{ book.title }}</li>
{% endfor %}
</ul>
#创建并注册引入标签
@register.inclusion_tag('book_snippet.html')
def show_reviews(review):
...