以下代碼節錄自
Django Book - Chapter 4 & 9
# Missing comma!
TEMPLATE_DIRS = (
'/home/django/mysite/templates'
)
dynamic path, more flexible and decoupled
import os.path
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)
locals() trick
It returns a dictionary mapping all local variable names to their values, where “local” means all variables that have been defined within the current scope.
def current_datetime(request):
current_date = datetime.datetime.now()
return render_to_response('current_datetime.html', locals())
include Template Tag
# mypage.html
<html>
<body>
{% include "includes/nav.html" %}
<h1>{{ title }}</h1>
</body>
</html>
# includes/nav.html
<div id="nav">
You are in: {{ current_section }}
</div>
Template Inheritance
base template
# base template
<!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>
# extend template
{% extends "base.html" %}
{% block title %}The current time{% endblock %}
{% block content %}
<p>It is now {{ current_date }}.</p>
{% endblock %}
Default TEMPLATE_CONTEXT_PROCESSORS
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
)
disable auto-escaping for an individual variable
This will be escaped: {{ data }}
This will not be escaped: {{ data|safe }}
disable auto-escaping for template block
{% autoescape off %}
Hello {{ name }}
{% endautoescape %}
template loading: TEMPLATE_LOADERS
django.template.loader.get_template(template_name)
django.template.loader.select_template(template_name_list)
# If the template doesn’t exist, a TemplateDoesNotExist exception will be raised
template loader
django.template.loaders.filesystem.load_template_source
#This loader loads templates from the filesystem, according to TEMPLATE_DIRS. It is enabled by default.
django.template.loaders.app_directories.load_template_source
#This loader loads templates from Django applications on the filesystem. For each application in INSTALLED_APPS, the loader looks for a templates subdirectory. If the directory exists, Django looks for templates there.
django.template.loaders.eggs.load_template_source
#This loader is just like app_directories, except it loads templates from Python eggs rather than from the filesystem. This loader is disabled by default; you’ll need to enable it if you’re using eggs to distribute your application. (Python eggs are a way of compressing Python code into a single file.)
Extending the Template System
Writing Custom Template Filters
from django import template
register = template.Library()
def cut(value, arg):
"Removes all values of arg from the given string"
return value.replace(arg, '')
def lower(value): # Only one argument.
"Converts a string into all lowercase"
return value.lower()
register.filter('cut', cut)
register.filter('lower', lower)
# in template:
# {{ somevariable|cut:" " }}
Python 2.4 above
from django import template
register = template.Library()
@register.filter(name='cut')
def cut(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
Writing Custom Template Tags
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])
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)
register.tag('current_time', do_current_time)
# python 2.4 above
@register.tag(name="current_time")
def do_current_time(parser, token):
# ...
Setting a Variable in the Context
class CurrentTimeNode2(template.Node):
def __init__(self, format_string):
self.format_string = str(format_string)
def render(self, context):
now = datetime.datetime.now()
context['current_time'] = now.strftime(self.format_string)
return ''
# in template:
# {% current_time2 "%Y-%M-%d %I:%M %p" %}
# <p>The time is {{ current_time }}.</p>
Setting a Variable in the Context - cleaner solution
# in template:
# {% get_current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
# <p>The current time is {{ my_current_time }}.</p>
import re
class CurrentTimeNode3(template.Node):
def __init__(self, format_string, var_name):
self.format_string = str(format_string)
self.var_name = var_name
def render(self, context):
now = datetime.datetime.now()
context[self.var_name] = now.strftime(self.format_string)
return ''
def do_current_time(parser, token):
# This version uses a regular expression to parse tag contents.
try:
# Splitting by None == splitting by spaces.
tag_name, arg = token.contents.split(None, 1)
except ValueError:
msg = '%r tag requires arguments' % token.contents[0]
raise template.TemplateSyntaxError(msg)
m = re.search(r'(.*?) as (\w+)', arg)
if m:
fmt, var_name = m.groups()
else:
msg = '%r tag had invalid arguments' % tag_name
raise template.TemplateSyntaxError(msg)
if not (fmt[0] == fmt[-1] and fmt[0] in ('"', "'")):
msg = "%r tag's argument should be in quotes" % tag_name
raise template.TemplateSyntaxError(msg)
return CurrentTimeNode3(fmt[1:-1], var_name)
Parsing Until Another Template Tag
# in template:
# {% comment %}
def do_comment(parser, token):
nodelist = parser.parse(('endcomment',))
parser.delete_first_token()
return CommentNode()
class CommentNode(template.Node):
def render(self, context):
return ''
Parsing Until Another Template Tag and Saving Contents
# in template:
# {% upper %}
This will appear in uppercase, {{ user_name }}.
# {% endupper %}
def do_upper(parser, token):
nodelist = parser.parse(('endupper',))
parser.delete_first_token()
return UpperNode(nodelist)
class UpperNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
output = self.nodelist.render(context)
return output.upper()
For more examples of complex rendering, see the source code for {% if %}, {% for %}, {% ifequal %}, and {% ifchanged %}. They live in django/template/defaulttags.py
Shortcut for Simple Tags
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 above
@register.simple_tag
def current_time(token):
# ...
Inclusion Tags
# inclusion tag using in template:
# {% books_for_author author %}
# template using by inclusion tag:
# <ul>
# {% for book in books %}
# <li>{{ book.title }}</li>
# {% endfor %}
# </ul>
def books_for_author(author):
books = Book.objects.filter(authors__id=author.id)
return {'books': books}
register.inclusion_tag('book_snippet.html')(books_for_author)
# python 2.4 above
@register.inclusion_tag('book_snippet.html')
def books_for_author(author):
# ...
Inclusion tags access to values from the parent template’s context
@register.inclusion_tag('link.html', takes_context=True)
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
# in link.html
# Jump directly to <a href="{{ link }}">{{ title }}</a>.
# tag usage:
# {% jump_link %}
Writing Custom Template Loaders