1
0
mirror of https://github.com/django/django.git synced 2025-07-05 10:19:20 +00:00

Merged to r670. Moved decorators.

git-svn-id: http://code.djangoproject.com/svn/django/branches/new-admin@876 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Robert Wittams 2005-10-14 23:53:03 +00:00
parent e15c4832f5
commit 930f8ee99f
25 changed files with 483 additions and 425 deletions

View File

@ -61,6 +61,14 @@ TEMPLATE_DIRS = ()
# Extension on all templates. # Extension on all templates.
TEMPLATE_FILE_EXTENSION = '.html' TEMPLATE_FILE_EXTENSION = '.html'
# List of callables that know how to import templates from various sources.
# See the comments in django/core/template/loader.py for interface
# documentation.
TEMPLATE_LOADERS = (
'django.core.template.loaders.filesystem.load_template_source',
# 'django.core.template.loaders.eggs.load_template_source',
)
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a # URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash. # trailing slash.
# Examples: "http://foo.com/media/", "/media/". # Examples: "http://foo.com/media/", "/media/".

View File

@ -2,14 +2,13 @@
# of MVC. In other words, these functions/classes introduce controlled coupling # of MVC. In other words, these functions/classes introduce controlled coupling
# for convenience's sake. # for convenience's sake.
from django.core import template_loader
from django.core.exceptions import Http404, ObjectDoesNotExist from django.core.exceptions import Http404, ObjectDoesNotExist
from django.core.template import Context from django.core.template import Context, loader
from django.conf.settings import DEBUG, INTERNAL_IPS from django.conf.settings import DEBUG, INTERNAL_IPS
from django.utils.httpwrappers import HttpResponse from django.utils.httpwrappers import HttpResponse
def render_to_response(*args, **kwargs): def render_to_response(*args, **kwargs):
return HttpResponse(template_loader.render_to_string(*args, **kwargs)) return HttpResponse(loader.render_to_string(*args, **kwargs))
load_and_render = render_to_response # For backwards compatibility. load_and_render = render_to_response # For backwards compatibility.
def get_object_or_404(mod, **kwargs): def get_object_or_404(mod, **kwargs):

View File

@ -1,6 +1,5 @@
from django.core import template_loader
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.core.template import Context from django.core.template import Context, loader
from django.models.core import sites from django.models.core import sites
from django.utils import feedgenerator from django.utils import feedgenerator
from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE
@ -28,7 +27,7 @@ class FeedConfiguration:
get_list_kwargs_cb -- Function that takes the param and returns a get_list_kwargs_cb -- Function that takes the param and returns a
dictionary to use in addition to get_list_kwargs (if applicable). dictionary to use in addition to get_list_kwargs (if applicable).
get_pubdate_cb -- Function that takes the object and returns a datetime get_pubdate_cb -- Function that takes the object and returns a datetime
to use as the publication date in the feed. to use as the publication date in the feed.
@ -49,7 +48,7 @@ class FeedConfiguration:
self.enc_url = enc_url self.enc_url = enc_url
self.enc_length = enc_length self.enc_length = enc_length
self.enc_mime_type = enc_mime_type self.enc_mime_type = enc_mime_type
def get_feed(self, param_slug=None): def get_feed(self, param_slug=None):
""" """
Returns a utils.feedgenerator.DefaultRssFeed object, fully populated, Returns a utils.feedgenerator.DefaultRssFeed object, fully populated,
@ -64,8 +63,8 @@ class FeedConfiguration:
param = None param = None
current_site = sites.get_current() current_site = sites.get_current()
f = self._get_feed_generator_object(param) f = self._get_feed_generator_object(param)
title_template = template_loader.get_template('rss/%s_title' % self.slug) title_template = loader.get_template('rss/%s_title' % self.slug)
description_template = template_loader.get_template('rss/%s_description' % self.slug) description_template = loader.get_template('rss/%s_description' % self.slug)
kwargs = self.get_list_kwargs.copy() kwargs = self.get_list_kwargs.copy()
if param and self.get_list_kwargs_cb: if param and self.get_list_kwargs_cb:
kwargs.update(self.get_list_kwargs_cb(param)) kwargs.update(self.get_list_kwargs_cb(param))
@ -102,7 +101,7 @@ class FeedConfiguration:
pubdate = self.get_pubdate_cb and self.get_pubdate_cb(obj) or None, pubdate = self.get_pubdate_cb and self.get_pubdate_cb(obj) or None,
) )
return f return f
def _get_feed_generator_object(self, param): def _get_feed_generator_object(self, param):
current_site = sites.get_current() current_site = sites.get_current()
link = self.link_cb(param).decode() link = self.link_cb(param).decode()

View File

@ -1,6 +1,7 @@
"Default variable filters" "Default variable filters"
import template, re from django.core.template import register_filter, resolve_variable
import re
import random as random_module import random as random_module
################### ###################
@ -196,7 +197,7 @@ def dictsort(value, arg):
Takes a list of dicts, returns that list sorted by the property given in Takes a list of dicts, returns that list sorted by the property given in
the argument. the argument.
""" """
decorated = [(template.resolve_variable('var.' + arg, {'var' : item}), item) for item in value] decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
decorated.sort() decorated.sort()
return [item[1] for item in decorated] return [item[1] for item in decorated]
@ -205,7 +206,7 @@ def dictsortreversed(value, arg):
Takes a list of dicts, returns that list sorted in reverse order by the Takes a list of dicts, returns that list sorted in reverse order by the
property given in the argument. property given in the argument.
""" """
decorated = [(template.resolve_variable('var.' + arg, {'var' : item}), item) for item in value] decorated = [(resolve_variable('var.' + arg, {'var' : item}), item) for item in value]
decorated.sort() decorated.sort()
decorated.reverse() decorated.reverse()
return [item[1] for item in decorated] return [item[1] for item in decorated]
@ -414,51 +415,52 @@ def pprint(value, _):
from pprint import pformat from pprint import pformat
return pformat(value) return pformat(value)
# Syntax: template.register_filter(name of filter, callback, has_argument) # Syntax: register_filter(name of filter, callback, has_argument)
template.register_filter('add', add, True) register_filter('add', add, True)
template.register_filter('addslashes', addslashes, False) register_filter('addslashes', addslashes, False)
template.register_filter('capfirst', capfirst, False) register_filter('capfirst', capfirst, False)
template.register_filter('center', center, True) register_filter('center', center, True)
template.register_filter('cut', cut, True) register_filter('cut', cut, True)
template.register_filter('date', date, True) register_filter('date', date, True)
template.register_filter('default', default, True) register_filter('default', default, True)
template.register_filter('dictsort', dictsort, True) register_filter('default_if_none', default_if_none, True)
template.register_filter('dictsortreversed', dictsortreversed, True) register_filter('dictsort', dictsort, True)
template.register_filter('divisibleby', divisibleby, True) register_filter('dictsortreversed', dictsortreversed, True)
template.register_filter('escape', escape, False) register_filter('divisibleby', divisibleby, True)
template.register_filter('filesizeformat', filesizeformat, False) register_filter('escape', escape, False)
template.register_filter('first', first, False) register_filter('filesizeformat', filesizeformat, False)
template.register_filter('fix_ampersands', fix_ampersands, False) register_filter('first', first, False)
template.register_filter('floatformat', floatformat, False) register_filter('fix_ampersands', fix_ampersands, False)
template.register_filter('get_digit', get_digit, True) register_filter('floatformat', floatformat, False)
template.register_filter('join', join, True) register_filter('get_digit', get_digit, True)
template.register_filter('length', length, False) register_filter('join', join, True)
template.register_filter('length_is', length_is, True) register_filter('length', length, False)
template.register_filter('linebreaks', linebreaks, False) register_filter('length_is', length_is, True)
template.register_filter('linebreaksbr', linebreaksbr, False) register_filter('linebreaks', linebreaks, False)
template.register_filter('linenumbers', linenumbers, False) register_filter('linebreaksbr', linebreaksbr, False)
template.register_filter('ljust', ljust, True) register_filter('linenumbers', linenumbers, False)
template.register_filter('lower', lower, False) register_filter('ljust', ljust, True)
template.register_filter('make_list', make_list, False) register_filter('lower', lower, False)
template.register_filter('phone2numeric', phone2numeric, False) register_filter('make_list', make_list, False)
template.register_filter('pluralize', pluralize, False) register_filter('phone2numeric', phone2numeric, False)
template.register_filter('pprint', pprint, False) register_filter('pluralize', pluralize, False)
template.register_filter('removetags', removetags, True) register_filter('pprint', pprint, False)
template.register_filter('random', random, False) register_filter('removetags', removetags, True)
template.register_filter('rjust', rjust, True) register_filter('random', random, False)
template.register_filter('slice', slice_, True) register_filter('rjust', rjust, True)
template.register_filter('slugify', slugify, False) register_filter('slice', slice_, True)
template.register_filter('stringformat', stringformat, True) register_filter('slugify', slugify, False)
template.register_filter('striptags', striptags, False) register_filter('stringformat', stringformat, True)
template.register_filter('time', time, True) register_filter('striptags', striptags, False)
template.register_filter('timesince', timesince, False) register_filter('time', time, True)
template.register_filter('title', title, False) register_filter('timesince', timesince, False)
template.register_filter('truncatewords', truncatewords, True) register_filter('title', title, False)
template.register_filter('unordered_list', unordered_list, False) register_filter('truncatewords', truncatewords, True)
template.register_filter('upper', upper, False) register_filter('unordered_list', unordered_list, False)
template.register_filter('urlencode', urlencode, False) register_filter('upper', upper, False)
template.register_filter('urlize', urlize, False) register_filter('urlencode', urlencode, False)
template.register_filter('urlizetrunc', urlizetrunc, True) register_filter('urlize', urlize, False)
template.register_filter('wordcount', wordcount, False) register_filter('urlizetrunc', urlizetrunc, True)
template.register_filter('wordwrap', wordwrap, True) register_filter('wordcount', wordcount, False)
template.register_filter('yesno', yesno, True) register_filter('wordwrap', wordwrap, True)
register_filter('yesno', yesno, True)

View File

@ -1,14 +1,14 @@
"Default tags used by the template system, available to all templates." "Default tags used by the template system, available to all templates."
from django.core.template import Node, NodeList, Template, Context, resolve_variable, resolve_variable_with_filters, get_filters_from_token, registered_filters
from django.core.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, register_tag
import sys import sys
import template
import template_loader
class CommentNode(template.Node): class CommentNode(Node):
def render(self, context): def render(self, context):
return '' return ''
class CycleNode(template.Node): class CycleNode(Node):
def __init__(self, cyclevars): def __init__(self, cyclevars):
self.cyclevars = cyclevars self.cyclevars = cyclevars
self.cyclevars_len = len(cyclevars) self.cyclevars_len = len(cyclevars)
@ -18,7 +18,7 @@ class CycleNode(template.Node):
self.counter += 1 self.counter += 1
return self.cyclevars[self.counter % self.cyclevars_len] return self.cyclevars[self.counter % self.cyclevars_len]
class DebugNode(template.Node): class DebugNode(Node):
def render(self, context): def render(self, context):
from pprint import pformat from pprint import pformat
output = [pformat(val) for val in context] output = [pformat(val) for val in context]
@ -26,7 +26,7 @@ class DebugNode(template.Node):
output.append(pformat(sys.modules)) output.append(pformat(sys.modules))
return ''.join(output) return ''.join(output)
class FilterNode(template.Node): class FilterNode(Node):
def __init__(self, filters, nodelist): def __init__(self, filters, nodelist):
self.filters, self.nodelist = filters, nodelist self.filters, self.nodelist = filters, nodelist
@ -34,21 +34,21 @@ class FilterNode(template.Node):
output = self.nodelist.render(context) output = self.nodelist.render(context)
# apply filters # apply filters
for f in self.filters: for f in self.filters:
output = template.registered_filters[f[0]][0](output, f[1]) output = registered_filters[f[0]][0](output, f[1])
return output return output
class FirstOfNode(template.Node): class FirstOfNode(Node):
def __init__(self, vars): def __init__(self, vars):
self.vars = vars self.vars = vars
def render(self, context): def render(self, context):
for var in self.vars: for var in self.vars:
value = template.resolve_variable(var, context) value = resolve_variable(var, context)
if value: if value:
return str(value) return str(value)
return '' return ''
class ForNode(template.Node): class ForNode(Node):
def __init__(self, loopvar, sequence, reversed, nodelist_loop): def __init__(self, loopvar, sequence, reversed, nodelist_loop):
self.loopvar, self.sequence = loopvar, sequence self.loopvar, self.sequence = loopvar, sequence
self.reversed = reversed self.reversed = reversed
@ -74,15 +74,15 @@ class ForNode(template.Node):
return nodes return nodes
def render(self, context): def render(self, context):
nodelist = template.NodeList() nodelist = NodeList()
if context.has_key('forloop'): if context.has_key('forloop'):
parentloop = context['forloop'] parentloop = context['forloop']
else: else:
parentloop = {} parentloop = {}
context.push() context.push()
try: try:
values = template.resolve_variable_with_filters(self.sequence, context) values = resolve_variable_with_filters(self.sequence, context)
except template.VariableDoesNotExist: except VariableDoesNotExist:
values = [] values = []
if values is None: if values is None:
values = [] values = []
@ -112,7 +112,7 @@ class ForNode(template.Node):
context.pop() context.pop()
return nodelist.render(context) return nodelist.render(context)
class IfChangedNode(template.Node): class IfChangedNode(Node):
def __init__(self, nodelist): def __init__(self, nodelist):
self.nodelist = nodelist self.nodelist = nodelist
self._last_seen = None self._last_seen = None
@ -130,7 +130,7 @@ class IfChangedNode(template.Node):
else: else:
return '' return ''
class IfEqualNode(template.Node): class IfEqualNode(Node):
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
self.var1, self.var2 = var1, var2 self.var1, self.var2 = var1, var2
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@ -140,13 +140,13 @@ class IfEqualNode(template.Node):
return "<IfEqualNode>" return "<IfEqualNode>"
def render(self, context): def render(self, context):
val1 = template.resolve_variable(self.var1, context) val1 = resolve_variable(self.var1, context)
val2 = template.resolve_variable(self.var2, context) val2 = resolve_variable(self.var2, context)
if (self.negate and val1 != val2) or (not self.negate and val1 == val2): if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
return self.nodelist_true.render(context) return self.nodelist_true.render(context)
return self.nodelist_false.render(context) return self.nodelist_false.render(context)
class IfNode(template.Node): class IfNode(Node):
def __init__(self, boolvars, nodelist_true, nodelist_false): def __init__(self, boolvars, nodelist_true, nodelist_false):
self.boolvars = boolvars self.boolvars = boolvars
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
@ -171,27 +171,27 @@ class IfNode(template.Node):
def render(self, context): def render(self, context):
for ifnot, boolvar in self.boolvars: for ifnot, boolvar in self.boolvars:
try: try:
value = template.resolve_variable_with_filters(boolvar, context) value = resolve_variable_with_filters(boolvar, context)
except template.VariableDoesNotExist: except VariableDoesNotExist:
value = None value = None
if (value and not ifnot) or (ifnot and not value): if (value and not ifnot) or (ifnot and not value):
return self.nodelist_true.render(context) return self.nodelist_true.render(context)
return self.nodelist_false.render(context) return self.nodelist_false.render(context)
class RegroupNode(template.Node): class RegroupNode(Node):
def __init__(self, target_var, expression, var_name): def __init__(self, target_var, expression, var_name):
self.target_var, self.expression = target_var, expression self.target_var, self.expression = target_var, expression
self.var_name = var_name self.var_name = var_name
def render(self, context): def render(self, context):
obj_list = template.resolve_variable_with_filters(self.target_var, context) obj_list = resolve_variable_with_filters(self.target_var, context)
if obj_list == '': # target_var wasn't found in context; fail silently if obj_list == '': # target_var wasn't found in context; fail silently
context[self.var_name] = [] context[self.var_name] = []
return '' return ''
output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]}
for obj in obj_list: for obj in obj_list:
grouper = template.resolve_variable_with_filters('var.%s' % self.expression, \ grouper = resolve_variable_with_filters('var.%s' % self.expression, \
template.Context({'var': obj})) Context({'var': obj}))
if output and repr(output[-1]['grouper']) == repr(grouper): if output and repr(output[-1]['grouper']) == repr(grouper):
output[-1]['list'].append(obj) output[-1]['list'].append(obj)
else: else:
@ -206,7 +206,7 @@ def include_is_allowed(filepath):
return True return True
return False return False
class SsiNode(template.Node): class SsiNode(Node):
def __init__(self, filepath, parsed): def __init__(self, filepath, parsed):
self.filepath, self.parsed = filepath, parsed self.filepath, self.parsed = filepath, parsed
@ -221,42 +221,14 @@ class SsiNode(template.Node):
output = '' output = ''
if self.parsed: if self.parsed:
try: try:
t = template.Template(output) t = Template(output)
return t.render(context) return t.render(context)
except template.TemplateSyntaxError: except TemplateSyntaxError:
return '' # Fail silently for invalid included templates. return '' # Fail silently for invalid included templates.
return output return output
class ConstantIncludeNode(template.Node): class LoadNode(Node):
def __init__(self, template_path):
try:
t = template_loader.get_template(template_path)
self.nodelist = t.nodelist
except Exception, e:
self.nodelist = None
def render(self, context):
if self.nodelist:
return self.nodelist.render(context)
else:
return ''
class IncludeNode(template.Node):
def __init__(self, template_path_var):
self.template_path_var = template_path_var
def render(self, context):
try:
template_path = template.resolve_variable(self.template_path_var, context)
print "IncludeNode rendering %s" % template_path
t = template_loader.get_template(template_path)
return t.render(context)
except Exception, e:
return '' # Fail silently for invalid included templates.
class LoadNode(template.Node):
def __init__(self, taglib): def __init__(self, taglib):
self.taglib = taglib self.taglib = taglib
@ -274,7 +246,7 @@ class LoadNode(template.Node):
pass # Fail silently for invalid loads. pass # Fail silently for invalid loads.
return '' return ''
class NowNode(template.Node): class NowNode(Node):
def __init__(self, format_string): def __init__(self, format_string):
self.format_string = format_string self.format_string = format_string
@ -284,11 +256,11 @@ class NowNode(template.Node):
df = DateFormat(datetime.now()) df = DateFormat(datetime.now())
return df.format(self.format_string) return df.format(self.format_string)
class TemplateTagNode(template.Node): class TemplateTagNode(Node):
mapping = {'openblock': template.BLOCK_TAG_START, mapping = {'openblock': BLOCK_TAG_START,
'closeblock': template.BLOCK_TAG_END, 'closeblock': BLOCK_TAG_END,
'openvariable': template.VARIABLE_TAG_START, 'openvariable': VARIABLE_TAG_START,
'closevariable': template.VARIABLE_TAG_END} 'closevariable': VARIABLE_TAG_END}
def __init__(self, tagtype): def __init__(self, tagtype):
self.tagtype = tagtype self.tagtype = tagtype
@ -296,7 +268,7 @@ class TemplateTagNode(template.Node):
def render(self, context): def render(self, context):
return self.mapping.get(self.tagtype, '') return self.mapping.get(self.tagtype, '')
class WidthRatioNode(template.Node): class WidthRatioNode(Node):
def __init__(self, val_var, max_var, max_width): def __init__(self, val_var, max_var, max_width):
self.val_var = val_var self.val_var = val_var
self.max_var = max_var self.max_var = max_var
@ -304,9 +276,9 @@ class WidthRatioNode(template.Node):
def render(self, context): def render(self, context):
try: try:
value = template.resolve_variable_with_filters(self.val_var, context) value = resolve_variable_with_filters(self.val_var, context)
maxvalue = template.resolve_variable_with_filters(self.max_var, context) maxvalue = resolve_variable_with_filters(self.max_var, context)
except template.VariableDoesNotExist: except VariableDoesNotExist:
return '' return ''
try: try:
value = float(value) value = float(value)
@ -360,7 +332,7 @@ def do_cycle(parser, token):
args = token.contents.split() args = token.contents.split()
if len(args) < 2: if len(args) < 2:
raise template.TemplateSyntaxError("'Cycle' statement requires at least two arguments") raise TemplateSyntaxError("'Cycle' statement requires at least two arguments")
elif len(args) == 2 and "," in args[1]: elif len(args) == 2 and "," in args[1]:
# {% cycle a,b,c %} # {% cycle a,b,c %}
@ -371,13 +343,13 @@ def do_cycle(parser, token):
elif len(args) == 2: elif len(args) == 2:
name = args[1] name = args[1]
if not parser._namedCycleNodes.has_key(name): if not parser._namedCycleNodes.has_key(name):
raise template.TemplateSyntaxError("Named cycle '%s' does not exist" % name) raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
return parser._namedCycleNodes[name] return parser._namedCycleNodes[name]
elif len(args) == 4: elif len(args) == 4:
# {% cycle a,b,c as name %} # {% cycle a,b,c as name %}
if args[2] != 'as': if args[2] != 'as':
raise template.TemplateSyntaxError("Second 'cycle' argument must be 'as'") raise TemplateSyntaxError("Second 'cycle' argument must be 'as'")
cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks cyclevars = [v for v in args[1].split(",") if v] # split and kill blanks
name = args[3] name = args[3]
node = CycleNode(cyclevars) node = CycleNode(cyclevars)
@ -389,7 +361,7 @@ def do_cycle(parser, token):
return node return node
else: else:
raise template.TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args) raise TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args)
def do_debug(parser, token): def do_debug(parser, token):
"Print a whole load of debugging information, including the context and imported modules" "Print a whole load of debugging information, including the context and imported modules"
@ -409,7 +381,7 @@ def do_filter(parser, token):
{% endfilter %} {% endfilter %}
""" """
_, rest = token.contents.split(None, 1) _, rest = token.contents.split(None, 1)
_, filters = template.get_filters_from_token('var|%s' % rest) _, filters = get_filters_from_token('var|%s' % rest)
nodelist = parser.parse(('endfilter',)) nodelist = parser.parse(('endfilter',))
parser.delete_first_token() parser.delete_first_token()
return FilterNode(filters, nodelist) return FilterNode(filters, nodelist)
@ -438,7 +410,7 @@ def do_firstof(parser, token):
""" """
bits = token.contents.split()[1:] bits = token.contents.split()[1:]
if len(bits) < 1: if len(bits) < 1:
raise template.TemplateSyntaxError, "'firstof' statement requires at least one argument" raise TemplateSyntaxError, "'firstof' statement requires at least one argument"
return FirstOfNode(bits) return FirstOfNode(bits)
@ -464,9 +436,9 @@ def do_for(parser, token):
========================== ================================================ ========================== ================================================
``forloop.counter`` The current iteration of the loop (1-indexed) ``forloop.counter`` The current iteration of the loop (1-indexed)
``forloop.counter0`` The current iteration of the loop (0-indexed) ``forloop.counter0`` The current iteration of the loop (0-indexed)
``forloop.revcounter`` The number of iterations from the end of the ``forloop.revcounter`` The number of iterations from the end of the
loop (1-indexed) loop (1-indexed)
``forloop.revcounter0`` The number of iterations from the end of the ``forloop.revcounter0`` The number of iterations from the end of the
loop (0-indexed) loop (0-indexed)
``forloop.first`` True if this is the first time through the loop ``forloop.first`` True if this is the first time through the loop
``forloop.last`` True if this is the last time through the loop ``forloop.last`` True if this is the last time through the loop
@ -477,11 +449,11 @@ def do_for(parser, token):
""" """
bits = token.contents.split() bits = token.contents.split()
if len(bits) == 5 and bits[4] != 'reversed': if len(bits) == 5 and bits[4] != 'reversed':
raise template.TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents raise TemplateSyntaxError, "'for' statements with five words should end in 'reversed': %s" % token.contents
if len(bits) not in (4, 5): if len(bits) not in (4, 5):
raise template.TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents raise TemplateSyntaxError, "'for' statements should have either four or five words: %s" % token.contents
if bits[2] != 'in': if bits[2] != 'in':
raise template.TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents raise TemplateSyntaxError, "'for' statement must contain 'in' as the second word: %s" % token.contents
loopvar = bits[1] loopvar = bits[1]
sequence = bits[3] sequence = bits[3]
reversed = (len(bits) == 5) reversed = (len(bits) == 5)
@ -507,7 +479,7 @@ def do_ifequal(parser, token, negate):
""" """
bits = token.contents.split() bits = token.contents.split()
if len(bits) != 3: if len(bits) != 3:
raise template.TemplateSyntaxError, "%r takes two arguments" % bits[0] raise TemplateSyntaxError, "%r takes two arguments" % bits[0]
end_tag = 'end' + bits[0] end_tag = 'end' + bits[0]
nodelist_true = parser.parse(('else', end_tag)) nodelist_true = parser.parse(('else', end_tag))
token = parser.next_token() token = parser.next_token()
@ -515,7 +487,7 @@ def do_ifequal(parser, token, negate):
nodelist_false = parser.parse((end_tag,)) nodelist_false = parser.parse((end_tag,))
parser.delete_first_token() parser.delete_first_token()
else: else:
nodelist_false = template.NodeList() nodelist_false = NodeList()
return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate) return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate)
def do_if(parser, token): def do_if(parser, token):
@ -568,7 +540,7 @@ def do_if(parser, token):
bits = token.contents.split() bits = token.contents.split()
del bits[0] del bits[0]
if not bits: if not bits:
raise template.TemplateSyntaxError, "'if' statement requires at least one argument" raise TemplateSyntaxError, "'if' statement requires at least one argument"
# bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d'] # bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']
boolpairs = ' '.join(bits).split(' or ') boolpairs = ' '.join(bits).split(' or ')
boolvars = [] boolvars = []
@ -576,7 +548,7 @@ def do_if(parser, token):
if ' ' in boolpair: if ' ' in boolpair:
not_, boolvar = boolpair.split() not_, boolvar = boolpair.split()
if not_ != 'not': if not_ != 'not':
raise template.TemplateSyntaxError, "Expected 'not' in if statement" raise TemplateSyntaxError, "Expected 'not' in if statement"
boolvars.append((True, boolvar)) boolvars.append((True, boolvar))
else: else:
boolvars.append((False, boolpair)) boolvars.append((False, boolpair))
@ -586,7 +558,7 @@ def do_if(parser, token):
nodelist_false = parser.parse(('endif',)) nodelist_false = parser.parse(('endif',))
parser.delete_first_token() parser.delete_first_token()
else: else:
nodelist_false = template.NodeList() nodelist_false = NodeList()
return IfNode(boolvars, nodelist_true, nodelist_false) return IfNode(boolvars, nodelist_true, nodelist_false)
def do_ifchanged(parser, token): def do_ifchanged(parser, token):
@ -606,7 +578,7 @@ def do_ifchanged(parser, token):
""" """
bits = token.contents.split() bits = token.contents.split()
if len(bits) != 1: if len(bits) != 1:
raise template.TemplateSyntaxError, "'ifchanged' tag takes no arguments" raise TemplateSyntaxError, "'ifchanged' tag takes no arguments"
nodelist = parser.parse(('endifchanged',)) nodelist = parser.parse(('endifchanged',))
parser.delete_first_token() parser.delete_first_token()
return IfChangedNode(nodelist) return IfChangedNode(nodelist)
@ -629,28 +601,14 @@ def do_ssi(parser, token):
bits = token.contents.split() bits = token.contents.split()
parsed = False parsed = False
if len(bits) not in (2, 3): if len(bits) not in (2, 3):
raise template.TemplateSyntaxError, "'ssi' tag takes one argument: the path to the file to be included" raise TemplateSyntaxError, "'ssi' tag takes one argument: the path to the file to be included"
if len(bits) == 3: if len(bits) == 3:
if bits[2] == 'parsed': if bits[2] == 'parsed':
parsed = True parsed = True
else: else:
raise template.TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0] raise TemplateSyntaxError, "Second (optional) argument to %s tag must be 'parsed'" % bits[0]
return SsiNode(bits[1], parsed) return SsiNode(bits[1], parsed)
def do_include(parser, token):
"""
Loads a template using standard resolution mechanisms, and renders it in the current context.
"""
bits = token.contents.split()
parsed = False
if len(bits) != 2:
raise template.TemplateSyntaxError, "'include' tag takes one argument: the path to the template to be included"
path = bits[1]
if path[0] in ('"', "'") and path[-1] == path[0]:
return ConstantIncludeNode(path[1:-1])
return IncludeNode(bits[1])
def do_load(parser, token): def do_load(parser, token):
""" """
Load a custom template tag set. Load a custom template tag set.
@ -661,13 +619,13 @@ def do_load(parser, token):
""" """
bits = token.contents.split() bits = token.contents.split()
if len(bits) != 2: if len(bits) != 2:
raise template.TemplateSyntaxError, "'load' statement takes one argument" raise TemplateSyntaxError, "'load' statement takes one argument"
taglib = bits[1] taglib = bits[1]
# check at compile time that the module can be imported # check at compile time that the module can be imported
try: try:
LoadNode.load_taglib(taglib) LoadNode.load_taglib(taglib)
except ImportError, e: except ImportError, e:
raise template.TemplateSyntaxError, "'%s' is not a valid tag library, %s" % (taglib, e) raise TemplateSyntaxError, "'%s' is not a valid tag library: %s" % (taglib, e)
return LoadNode(taglib) return LoadNode(taglib)
def do_now(parser, token): def do_now(parser, token):
@ -683,7 +641,7 @@ def do_now(parser, token):
""" """
bits = token.contents.split('"') bits = token.contents.split('"')
if len(bits) != 3: if len(bits) != 3:
raise template.TemplateSyntaxError, "'now' statement takes one argument" raise TemplateSyntaxError, "'now' statement takes one argument"
format_string = bits[1] format_string = bits[1]
return NowNode(format_string) return NowNode(format_string)
@ -735,13 +693,13 @@ def do_regroup(parser, token):
""" """
firstbits = token.contents.split(None, 3) firstbits = token.contents.split(None, 3)
if len(firstbits) != 4: if len(firstbits) != 4:
raise template.TemplateSyntaxError, "'regroup' tag takes five arguments" raise TemplateSyntaxError, "'regroup' tag takes five arguments"
target_var = firstbits[1] target_var = firstbits[1]
if firstbits[2] != 'by': if firstbits[2] != 'by':
raise template.TemplateSyntaxError, "second argument to 'regroup' tag must be 'by'" raise TemplateSyntaxError, "second argument to 'regroup' tag must be 'by'"
lastbits_reversed = firstbits[3][::-1].split(None, 2) lastbits_reversed = firstbits[3][::-1].split(None, 2)
if lastbits_reversed[1][::-1] != 'as': if lastbits_reversed[1][::-1] != 'as':
raise template.TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'" raise TemplateSyntaxError, "next-to-last argument to 'regroup' tag must be 'as'"
expression = lastbits_reversed[2][::-1] expression = lastbits_reversed[2][::-1]
var_name = lastbits_reversed[0][::-1] var_name = lastbits_reversed[0][::-1]
return RegroupNode(target_var, expression, var_name) return RegroupNode(target_var, expression, var_name)
@ -766,10 +724,10 @@ def do_templatetag(parser, token):
""" """
bits = token.contents.split() bits = token.contents.split()
if len(bits) != 2: if len(bits) != 2:
raise template.TemplateSyntaxError, "'templatetag' statement takes one argument" raise TemplateSyntaxError, "'templatetag' statement takes one argument"
tag = bits[1] tag = bits[1]
if not TemplateTagNode.mapping.has_key(tag): if not TemplateTagNode.mapping.has_key(tag):
raise template.TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \ raise TemplateSyntaxError, "Invalid templatetag argument: '%s'. Must be one of: %s" % \
(tag, TemplateTagNode.mapping.keys()) (tag, TemplateTagNode.mapping.keys())
return TemplateTagNode(tag) return TemplateTagNode(tag)
@ -788,28 +746,27 @@ def do_widthratio(parser, token):
""" """
bits = token.contents.split() bits = token.contents.split()
if len(bits) != 4: if len(bits) != 4:
raise template.TemplateSyntaxError("widthratio takes three arguments") raise TemplateSyntaxError("widthratio takes three arguments")
tag, this_value_var, max_value_var, max_width = bits tag, this_value_var, max_value_var, max_width = bits
try: try:
max_width = int(max_width) max_width = int(max_width)
except ValueError: except ValueError:
raise template.TemplateSyntaxError("widthratio final argument must be an integer") raise TemplateSyntaxError("widthratio final argument must be an integer")
return WidthRatioNode(this_value_var, max_value_var, max_width) return WidthRatioNode(this_value_var, max_value_var, max_width)
template.register_tag('comment', do_comment) register_tag('comment', do_comment)
template.register_tag('cycle', do_cycle) register_tag('cycle', do_cycle)
template.register_tag('debug', do_debug) register_tag('debug', do_debug)
template.register_tag('filter', do_filter) register_tag('filter', do_filter)
template.register_tag('firstof', do_firstof) register_tag('firstof', do_firstof)
template.register_tag('for', do_for) register_tag('for', do_for)
template.register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False)) register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False))
template.register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True)) register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True))
template.register_tag('if', do_if) register_tag('if', do_if)
template.register_tag('ifchanged', do_ifchanged) register_tag('ifchanged', do_ifchanged)
template.register_tag('include', do_include) register_tag('regroup', do_regroup)
template.register_tag('regroup', do_regroup) register_tag('ssi', do_ssi)
template.register_tag('ssi', do_ssi) register_tag('load', do_load)
template.register_tag('load', do_load) register_tag('now', do_now)
template.register_tag('now', do_now) register_tag('templatetag', do_templatetag)
template.register_tag('templatetag', do_templatetag) register_tag('widthratio', do_widthratio)
template.register_tag('widthratio', do_widthratio)

View File

@ -0,0 +1,254 @@
# Wrapper for loading templates from storage of some sort (e.g. filesystem, database).
#
# This uses the TEMPLATE_LOADERS setting, which is a list of loaders to use.
# Each loader is expected to have this interface:
#
# callable(name, dirs=[])
#
# name is the template name.
# dirs is an optional list of directories to search instead of TEMPLATE_DIRS.
# The loader should return a tuple of (template_source, path). The path returned
# will be shown to the user for debugging purposes, so it should identify where the template
# was loaded from.
#
# Each loader should have an "is_usable" attribute set. This is a boolean that
# specifies whether the loader can be used in this Python installation. Each
# loader is responsible for setting this when it's initialized.
#
# For example, the eggs loader (which is capable of loading templates from
# Python eggs) sets is_usable to False if the "pkg_resources" module isn't
# installed, because pkg_resources is necessary to read eggs.
from django.core.exceptions import ImproperlyConfigured
from django.core.template import Template, Context, Node, TemplateDoesNotExist, TemplateSyntaxError, resolve_variable_with_filters, register_tag, UNKNOWN_SOURCE
from django.conf.settings import TEMPLATE_LOADERS
template_source_loaders = []
for path in TEMPLATE_LOADERS:
i = path.rfind('.')
module, attr = path[:i], path[i+1:]
try:
mod = __import__(module, globals(), locals(), [attr])
except ImportError, e:
raise ImproperlyConfigured, 'Error importing template source loader %s: "%s"' % (module, e)
try:
func = getattr(mod, attr)
except AttributeError:
raise ImproperlyConfigured, 'Module "%s" does not define a "%s" callable template source loader' % (module, attr)
if not func.is_usable:
import warnings
warnings.warn("Your TEMPLATE_LOADERS setting includes %r, but your Python installation doesn't support that type of template loading. Consider removing that line from TEMPLATE_LOADERS." % path)
else:
template_source_loaders.append(func)
def find_template_source(name, dirs=None):
for loader in template_source_loaders:
try:
return loader(name, dirs)
except TemplateDoesNotExist:
pass
raise TemplateDoesNotExist, name
def load_template_source(name, dirs=None):
find_template_source(name, dirs)[0]
class ExtendsError(Exception):
pass
def get_template(template_name):
"""
Returns a compiled Template object for the given template name,
handling template inheritance recursively.
"""
return get_template_from_string(*find_template_source(template_name))
def get_template_from_string(source, filename=UNKNOWN_SOURCE):
"""
Returns a compiled Template object for the given template code,
handling template inheritance recursively.
"""
return Template(source, filename)
def render_to_string(template_name, dictionary=None, context_instance=None):
"""
Loads the given template_name and renders it with the given dictionary as
context. The template_name may be a string to load a single template using
get_template, or it may be a tuple to use select_template to find one of
the templates in the list. Returns a string.
"""
dictionary = dictionary or {}
if isinstance(template_name, (list, tuple)):
t = select_template(template_name)
else:
t = get_template(template_name)
if context_instance:
context_instance.update(dictionary)
else:
context_instance = Context(dictionary)
return t.render(context_instance)
def select_template(template_name_list):
"Given a list of template names, returns the first that can be loaded."
for template_name in template_name_list:
try:
return get_template(template_name)
except TemplateDoesNotExist:
continue
# If we get here, none of the templates could be loaded
raise TemplateDoesNotExist, ', '.join(template_name_list)
class BlockNode(Node):
def __init__(self, name, nodelist, parent=None):
self.name, self.nodelist, self.parent = name, nodelist, parent
def __repr__(self):
return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist)
def render(self, context):
context.push()
# Save context in case of block.super().
self.context = context
context['block'] = self
result = self.nodelist.render(context)
context.pop()
return result
def super(self):
if self.parent:
return self.parent.render(self.context)
return ''
def add_parent(self, nodelist):
if self.parent:
self.parent.add_parent(nodelist)
else:
self.parent = BlockNode(self.name, nodelist)
class ExtendsNode(Node):
def __init__(self, nodelist, parent_name, parent_name_var, template_dirs=None):
self.nodelist = nodelist
self.parent_name, self.parent_name_var = parent_name, parent_name_var
self.template_dirs = template_dirs
def get_parent(self, context):
if self.parent_name_var:
self.parent_name = resolve_variable_with_filters(self.parent_name_var, context)
parent = self.parent_name
if not parent:
error_msg = "Invalid template name in 'extends' tag: %r." % parent
if self.parent_name_var:
error_msg += " Got this from the %r variable." % self.parent_name_var
raise TemplateSyntaxError, error_msg
try:
return get_template_from_string(*find_template_source(parent, self.template_dirs))
except TemplateDoesNotExist:
raise TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
def render(self, context):
compiled_parent = self.get_parent(context)
parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode)
parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
for block_node in self.nodelist.get_nodes_by_type(BlockNode):
# Check for a BlockNode with this node's name, and replace it if found.
try:
parent_block = parent_blocks[block_node.name]
except KeyError:
# This BlockNode wasn't found in the parent template, but the
# parent block might be defined in the parent's *parent*, so we
# add this BlockNode to the parent's ExtendsNode nodelist, so
# it'll be checked when the parent node's render() is called.
if parent_is_child:
compiled_parent.nodelist[0].nodelist.append(block_node)
else:
# Keep any existing parents and add a new one. Used by BlockNode.
parent_block.parent = block_node.parent
parent_block.add_parent(parent_block.nodelist)
parent_block.nodelist = block_node.nodelist
return compiled_parent.render(context)
class ConstantIncludeNode(Node):
def __init__(self, template_path):
try:
t = get_template(template_path)
self.nodelist = t.nodelist
except Exception, e:
self.nodelist = None
def render(self, context):
if self.nodelist:
return self.nodelist.render(context)
else:
return ''
class IncludeNode(Node):
def __init__(self, template_path_var):
self.template_path_var = template_path_var
def render(self, context):
try:
template_path = resolve_variable(self.template_path_var, context)
print "IncludeNode rendering %s" % template_path
t = template_loader.get_template(template_path)
return t.render(context)
except Exception, e:
return '' # Fail silently for invalid included templates.
def do_block(parser, token):
"""
Define a block that can be overridden by child templates.
"""
bits = token.contents.split()
if len(bits) != 2:
raise TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0]
block_name = bits[1]
# Keep track of the names of BlockNodes found in this template, so we can
# check for duplication.
try:
if block_name in parser.__loaded_blocks:
raise TemplateSyntaxError, "'%s' tag with name '%s' appears more than once" % (bits[0], block_name)
parser.__loaded_blocks.append(block_name)
except AttributeError: # parser._loaded_blocks isn't a list yet
parser.__loaded_blocks = [block_name]
nodelist = parser.parse(('endblock',))
parser.delete_first_token()
return BlockNode(block_name, nodelist)
def do_extends(parser, token):
"""
Signal that this template extends a parent template.
This tag may be used in two ways: ``{% extends "base" %}`` (with quotes)
uses the literal value "base" as the name of the parent template to extend,
or ``{% extends variable %}`` uses the value of ``variable`` as the name
of the parent template to extend.
"""
bits = token.contents.split()
if len(bits) != 2:
raise TemplateSyntaxError, "'%s' takes one argument" % bits[0]
parent_name, parent_name_var = None, None
if (bits[1].startswith('"') and bits[1].endswith('"')) or (bits[1].startswith("'") and bits[1].endswith("'")):
parent_name = bits[1][1:-1]
else:
parent_name_var = bits[1]
nodelist = parser.parse()
if nodelist.get_nodes_by_type(ExtendsNode):
raise TemplateSyntaxError, "'%s' cannot appear more than once in the same template" % bits[0]
return ExtendsNode(nodelist, parent_name, parent_name_var)
def do_include(parser, token):
"""
Loads a template using standard resolution mechanisms, and renders it in the current context.
"""
bits = token.contents.split()
if len(bits) != 2:
raise TemplateSyntaxError, "'include' tag takes one argument: the path to the template to be included"
path = bits[1]
if path[0] in ('"', "'") and path[-1] == path[0]:
return ConstantIncludeNode(path[1:-1])
return IncludeNode(bits[1])
register_tag('block', do_block)
register_tag('extends', do_extends)
register_tag('include', do_include)

View File

View File

@ -0,0 +1,25 @@
# Wrapper for loading templates from eggs via pkg_resources.resource_string.
try:
from pkg_resources import resource_string
except ImportError:
resource_string = None
from django.core.template import TemplateDoesNotExist
from django.conf.settings import INSTALLED_APPS, TEMPLATE_FILE_EXTENSION
def load_template_source(name, dirs=None):
"""
Loads templates from Python eggs via pkg_resource.resource_string.
For every installed app, it tries to get the resource (app, name).
"""
if resource_string is not None:
pkg_name = 'templates/' + name + TEMPLATE_FILE_EXTENSION
for app in INSTALLED_APPS:
try:
return (resource_string(app, pkg_name), 'egg:%s:%s ' % (app, pkg_name))
except:
pass
raise TemplateDoesNotExist, name
load_template_source.is_usable = resource_string is not None

View File

@ -1,12 +1,10 @@
# Wrapper for loading templates from files # Wrapper for loading templates from the filesystem.
from django.conf.settings import TEMPLATE_DIRS, TEMPLATE_FILE_EXTENSION from django.conf.settings import TEMPLATE_DIRS, TEMPLATE_FILE_EXTENSION
from django.core.template import TemplateDoesNotExist from django.core.template import TemplateDoesNotExist
import os import os
def load_template_source(template_name, template_dirs=None):
def find_template_source(template_name, template_dirs=None):
"Returns a tuple of (template_string, filepath)."
if not template_dirs: if not template_dirs:
template_dirs = TEMPLATE_DIRS template_dirs = TEMPLATE_DIRS
tried = [] tried = []
@ -21,7 +19,4 @@ def find_template_source(template_name, template_dirs=None):
else: else:
error_msg = "Your TEMPLATE_DIRS settings is empty. Change it to point to at least one template directory." error_msg = "Your TEMPLATE_DIRS settings is empty. Change it to point to at least one template directory."
raise TemplateDoesNotExist, error_msg raise TemplateDoesNotExist, error_msg
load_template_source.is_usable = True
def load_template_source(template_name, template_dirs=None):
return find_template_source(template_name, template_dirs)[0]

View File

@ -1,162 +1,7 @@
"Wrapper for loading templates from storage of some sort (e.g. files or db)" # This module is DEPRECATED!
import template #
from template_file import find_template_source # You should no longer be using django.core.template_loader.
#
# Use django.core.template.loader instead.
class ExtendsError(Exception): from django.core.template.loader import *
pass
def get_template(template_name):
"""
Returns a compiled template.Template object for the given template name,
handling template inheritance recursively.
"""
return get_template_from_string(*find_template_source(template_name))
def get_template_from_string(source, filename=template.UNKNOWN_SOURCE):
"""
Returns a compiled template.Template object for the given template code,
handling template inheritance recursively.
"""
return template.Template(source, filename)
def render_to_string(template_name, dictionary=None, context_instance=None):
"""
Loads the given template_name and renders it with the given dictionary as
context. The template_name may be a string to load a single template using
get_template, or it may be a tuple to use select_template to find one of
the templates in the list. Returns a string.
"""
dictionary = dictionary or {}
if isinstance(template_name, (list, tuple)):
t = select_template(template_name)
else:
t = get_template(template_name)
if context_instance:
context_instance.update(dictionary)
else:
context_instance = template.Context(dictionary)
return t.render(context_instance)
def select_template(template_name_list):
"Given a list of template names, returns the first that can be loaded."
for template_name in template_name_list:
try:
return get_template(template_name)
except template.TemplateDoesNotExist:
continue
# If we get here, none of the templates could be loaded
raise template.TemplateDoesNotExist, ', '.join(template_name_list)
class BlockNode(template.Node):
def __init__(self, name, nodelist, parent=None):
self.name, self.nodelist, self.parent = name, nodelist, parent
def __repr__(self):
return "<Block Node: %s. Contents: %r>" % (self.name, self.nodelist)
def render(self, context):
context.push()
# Save context in case of block.super().
self.context = context
context['block'] = self
result = self.nodelist.render(context)
context.pop()
return result
def super(self):
if self.parent:
return self.parent.render(self.context)
return ''
def add_parent(self, nodelist):
if self.parent:
self.parent.add_parent(nodelist)
else:
self.parent = BlockNode(self.name, nodelist)
class ExtendsNode(template.Node):
def __init__(self, nodelist, parent_name, parent_name_var, template_dirs=None):
self.nodelist = nodelist
self.parent_name, self.parent_name_var = parent_name, parent_name_var
self.template_dirs = template_dirs
def get_parent(self, context):
if self.parent_name_var:
self.parent_name = template.resolve_variable_with_filters(self.parent_name_var, context)
parent = self.parent_name
if not parent:
error_msg = "Invalid template name in 'extends' tag: %r." % parent
if self.parent_name_var:
error_msg += " Got this from the %r variable." % self.parent_name_var
raise template.TemplateSyntaxError, error_msg
try:
return get_template_from_string(*find_template_source(parent, self.template_dirs))
except template.TemplateDoesNotExist:
raise template.TemplateSyntaxError, "Template %r cannot be extended, because it doesn't exist" % parent
def render(self, context):
compiled_parent = self.get_parent(context)
parent_is_child = isinstance(compiled_parent.nodelist[0], ExtendsNode)
parent_blocks = dict([(n.name, n) for n in compiled_parent.nodelist.get_nodes_by_type(BlockNode)])
for block_node in self.nodelist.get_nodes_by_type(BlockNode):
# Check for a BlockNode with this node's name, and replace it if found.
try:
parent_block = parent_blocks[block_node.name]
except KeyError:
# This BlockNode wasn't found in the parent template, but the
# parent block might be defined in the parent's *parent*, so we
# add this BlockNode to the parent's ExtendsNode nodelist, so
# it'll be checked when the parent node's render() is called.
if parent_is_child:
compiled_parent.nodelist[0].nodelist.append(block_node)
else:
# Keep any existing parents and add a new one. Used by BlockNode.
parent_block.parent = block_node.parent
parent_block.add_parent(parent_block.nodelist)
parent_block.nodelist = block_node.nodelist
return compiled_parent.render(context)
def do_block(parser, token):
"""
Define a block that can be overridden by child templates.
"""
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError, "'%s' tag takes only one argument" % bits[0]
block_name = bits[1]
# Keep track of the names of BlockNodes found in this template, so we can
# check for duplication.
try:
if block_name in parser.__loaded_blocks:
raise template.TemplateSyntaxError, "'%s' tag with name '%s' appears more than once" % (bits[0], block_name)
parser.__loaded_blocks.append(block_name)
except AttributeError: # parser._loaded_blocks isn't a list yet
parser.__loaded_blocks = [block_name]
nodelist = parser.parse(('endblock',))
parser.delete_first_token()
return BlockNode(block_name, nodelist)
def do_extends(parser, token):
"""
Signal that this template extends a parent template.
This tag may be used in two ways: ``{% extends "base" %}`` (with quotes)
uses the literal value "base" as the name of the parent template to extend,
or ``{% extends variable %}`` uses the value of ``variable`` as the name
of the parent template to extend.
"""
bits = token.contents.split()
if len(bits) != 2:
raise template.TemplateSyntaxError, "'%s' takes one argument" % bits[0]
parent_name, parent_name_var = None, None
if (bits[1].startswith('"') and bits[1].endswith('"')) or (bits[1].startswith("'") and bits[1].endswith("'")):
parent_name = bits[1][1:-1]
else:
parent_name_var = bits[1]
nodelist = parser.parse()
if nodelist.get_nodes_by_type(ExtendsNode):
raise template.TemplateSyntaxError, "'%s' cannot appear more than once in the same template" % bits[0]
return ExtendsNode(nodelist, parent_name, parent_name_var)
template.register_tag('block', do_block)
template.register_tag('extends', do_extends)

View File

@ -1,6 +1,6 @@
from django.utils import httpwrappers from django.utils import httpwrappers
from django.core import template_loader from django.core.extensions import DjangoContext
from django.core.extensions import DjangoContext as Context from django.core.extensions import render_to_response
from django.models.auth import users from django.models.auth import users
from django.views.registration import passwords from django.views.registration import passwords
from django.views.auth.login import logout from django.views.auth.login import logout
@ -96,14 +96,12 @@ class AdminUserRequired:
post_data = encode_post_data(request.POST) post_data = encode_post_data(request.POST)
else: else:
post_data = encode_post_data({}) post_data = encode_post_data({})
t = template_loader.get_template(self.get_login_template_name()) return render_to_response(self.get_login_template_name(), {
c = Context(request, {
'title': 'Log in', 'title': 'Log in',
'app_path': request.path, 'app_path': request.path,
'post_data': post_data, 'post_data': post_data,
'error_message': error_message 'error_message': error_message
}) }, context_instance=DjangoContext(request))
return httpwrappers.HttpResponse(t.render(c))
def authenticate_user(self, user, password): def authenticate_user(self, user, password):
return user.check_password(password) and user.is_staff return user.check_password(password) and user.is_staff

View File

@ -5,7 +5,7 @@ from django.utils.text import capfirst
from django.utils.html import escape from django.utils.html import escape
from django.utils.functional import curry from django.utils.functional import curry
from django.core.template_decorators import simple_tag, inclusion_tag from django.core.template.decorators import simple_tag, inclusion_tag
from django.views.admin.main import AdminBoundField from django.views.admin.main import AdminBoundField
from django.core.meta.fields import BoundField, Field from django.core.meta.fields import BoundField, Field

View File

@ -4,7 +4,8 @@ from django.conf import settings
from django.models.core import sites from django.models.core import sites
from django.core.extensions import DjangoContext, render_to_response from django.core.extensions import DjangoContext, render_to_response
from django.core.exceptions import Http404, ViewDoesNotExist from django.core.exceptions import Http404, ViewDoesNotExist
from django.core import template, template_loader, defaulttags, defaultfilters, urlresolvers from django.core import template, template_loader, urlresolvers
from django.core.template import defaulttags, defaultfilters
try: try:
from django.parts.admin import doc from django.parts.admin import doc
except ImportError: except ImportError:

View File

@ -1,5 +1,6 @@
from django.core import formfields, template_loader, validators from django.core import formfields, validators
from django.core import template from django.core import template
from django.core.template import loader
from django.core.extensions import DjangoContext, render_to_response from django.core.extensions import DjangoContext, render_to_response
from django.models.core import sites from django.models.core import sites
from django.conf import settings from django.conf import settings
@ -49,7 +50,7 @@ class TemplateValidator(formfields.Manipulator):
# so that inheritance works in the site's context, register a new function # so that inheritance works in the site's context, register a new function
# for "extends" that uses the site's TEMPLATE_DIR instead # for "extends" that uses the site's TEMPLATE_DIR instead
def new_do_extends(parser, token): def new_do_extends(parser, token):
node = template_loader.do_extends(parser, token) node = loader.do_extends(parser, token)
node.template_dirs = settings_module.TEMPLATE_DIRS node.template_dirs = settings_module.TEMPLATE_DIRS
return node return node
template.register_tag('extends', new_do_extends) template.register_tag('extends', new_do_extends)
@ -58,10 +59,10 @@ class TemplateValidator(formfields.Manipulator):
# making sure to reset the extends function in any case # making sure to reset the extends function in any case
error = None error = None
try: try:
tmpl = template_loader.get_template_from_string(field_data) tmpl = loader.get_template_from_string(field_data)
tmpl.render(template.Context({})) tmpl.render(template.Context({}))
except template.TemplateSyntaxError, e: except template.TemplateSyntaxError, e:
error = e error = e
template.register_tag('extends', template_loader.do_extends) template.register_tag('extends', loader.do_extends)
if error: if error:
raise validators.ValidationError, e.args raise validators.ValidationError, e.args

View File

@ -1,5 +1,5 @@
from django.parts.auth.formfields import AuthenticationForm from django.parts.auth.formfields import AuthenticationForm
from django.core import formfields, template_loader from django.core import formfields
from django.core.extensions import DjangoContext, render_to_response from django.core.extensions import DjangoContext, render_to_response
from django.models.auth import users from django.models.auth import users
from django.models.core import sites from django.models.core import sites

View File

@ -1,6 +1,5 @@
from django.core import template_loader
from django.core.exceptions import Http404, ObjectDoesNotExist from django.core.exceptions import Http404, ObjectDoesNotExist
from django.core.template import Context from django.core.template import Context, loader
from django.models.core import sites from django.models.core import sites
from django.utils import httpwrappers from django.utils import httpwrappers
@ -56,7 +55,7 @@ def page_not_found(request):
if r == '': if r == '':
return httpwrappers.HttpResponseGone() return httpwrappers.HttpResponseGone()
return httpwrappers.HttpResponseRedirect(r.new_path) return httpwrappers.HttpResponseRedirect(r.new_path)
t = template_loader.get_template('404') t = loader.get_template('404')
c = Context() c = Context()
return httpwrappers.HttpResponseNotFound(t.render(c)) return httpwrappers.HttpResponseNotFound(t.render(c))
@ -67,6 +66,6 @@ def server_error(request):
Templates: `500` Templates: `500`
Context: None Context: None
""" """
t = template_loader.get_template('500') t = loader.get_template('500')
c = Context() c = Context()
return httpwrappers.HttpResponseServerError(t.render(c)) return httpwrappers.HttpResponseServerError(t.render(c))

View File

@ -1,5 +1,6 @@
from django.core import formfields, template_loader, validators from django.core import formfields, validators
from django.core.extensions import DjangoContext, render_to_response from django.core.extensions import DjangoContext, render_to_response
from django.core.template import loader
from django.models.auth import users from django.models.auth import users
from django.views.decorators.auth import login_required from django.views.decorators.auth import login_required
from django.utils.httpwrappers import HttpResponseRedirect from django.utils.httpwrappers import HttpResponseRedirect
@ -32,7 +33,7 @@ class PasswordResetForm(formfields.Manipulator):
domain = current_site.domain domain = current_site.domain
else: else:
site_name = domain = domain_override site_name = domain = domain_override
t = template_loader.get_template('registration/password_reset_email') t = loader.get_template('registration/password_reset_email')
c = { c = {
'new_password': new_pass, 'new_password': new_pass,
'email': self.user_cache.email, 'email': self.user_cache.email,

View File

@ -65,9 +65,8 @@ Using the ``AddManipulator``
We'll start with the ``AddManipulator``. Here's a very simple view that takes We'll start with the ``AddManipulator``. Here's a very simple view that takes
POSTed data from the browser and creates a new ``Place`` object:: POSTed data from the browser and creates a new ``Place`` object::
from django.core import template_loader
from django.core.exceptions import Http404 from django.core.exceptions import Http404
from django.core.extensions import DjangoContext as Context from django.core.extensions import render_to_response
from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect from django.utils.httpwrappers import HttpResponse, HttpResponseRedirect
from django.models.places import places from django.models.places import places
from django.core import formfields from django.core import formfields
@ -112,13 +111,7 @@ view with a form that submits to this flawed creation view::
# Create a FormWrapper object that the template can use. Ignore # Create a FormWrapper object that the template can use. Ignore
# the last two arguments to FormWrapper for now. # the last two arguments to FormWrapper for now.
form = formfields.FormWrapper(places.AddManipulator(), {}, {}) form = formfields.FormWrapper(places.AddManipulator(), {}, {})
return render_to_response('places/naive_create_form', {'form': form})
# Create a template, context and response.
t = template_loader.get_template('places/naive_create_form')
c = Context(request, {
'form': form
})
return HttpResponse(t.render(c))
(This view, as well as all the following ones, has the same imports as in the (This view, as well as all the following ones, has the same imports as in the
first example above.) first example above.)
@ -169,11 +162,7 @@ creation view that takes validation into account::
# Check for validation errors # Check for validation errors
errors = manipulator.get_validation_errors(new_data) errors = manipulator.get_validation_errors(new_data)
if errors: if errors:
t = template_loader.get_template('places/errors') return render_to_response('places/errors', {'errors': errors})
c = Context(request, {
'errors': errors
}
return HttpResponse(t.render(c))
else: else:
manipulator.do_html2python(request.POST) manipulator.do_html2python(request.POST)
new_place = manipulator.save(request.POST) new_place = manipulator.save(request.POST)
@ -245,11 +234,7 @@ Below is the finished view::
# Create the FormWrapper, template, context, response. # Create the FormWrapper, template, context, response.
form = formfields.FormWrapper(manipulator, new_data, errors) form = formfields.FormWrapper(manipulator, new_data, errors)
t = template_loader.get_template("places/create_form") return render_to_response('places/create_form', {'form': form})
c = Context(request, {
'form': form,
})
return HttpResponse(t.render(c))
and here's the ``create_form`` template:: and here's the ``create_form`` template::
@ -338,12 +323,7 @@ about editing an existing one? It's shockingly similar to creating a new one::
new_data = place.__dict__ new_data = place.__dict__
form = formfields.FormWrapper(manipulator, new_data, errors) form = formfields.FormWrapper(manipulator, new_data, errors)
t = template_loader.get_template("places/edit_form") return render_to_response('places/edit_form', {'form': form, 'place': place})
c = Context(request, {
'form': form,
'place': place,
})
return HttpResponse(t.render(c))
The only real differences are: The only real differences are:
@ -422,11 +402,7 @@ Here's a simple function that might drive the above form::
else: else:
errors = new_data = {} errors = new_data = {}
form = formfields.FormWrapper(manipulator, new_data, errors) form = formfields.FormWrapper(manipulator, new_data, errors)
t = template_loader.get_template("contact_form") return render_to_response('contact_form', {'form': form})
c = Context(request, {
'form': form,
})
return HttpResponse(t.render(c))
Validators Validators
========== ==========

View File

@ -136,9 +136,7 @@ Here's a typical usage example::
else: else:
return HttpResponse("Please enable cookies and try again.") return HttpResponse("Please enable cookies and try again.")
request.session.set_test_cookie() request.session.set_test_cookie()
t = template_loader.get_template("foo/login_form") return render_to_response('foo/login_form')
c = Context(request)
return HttpResponse(t.render(c))
Using sessions out of views Using sessions out of views
=========================== ===========================

View File

@ -307,12 +307,12 @@ The Python API
Django has two ways to load templates from files: Django has two ways to load templates from files:
``django.core.template_loader.get_template(template_name)`` ``django.core.template.loader.get_template(template_name)``
``get_template`` returns the compiled template (a ``Template`` object) for ``get_template`` returns the compiled template (a ``Template`` object) for
the template with the given name. If the template doesn't exist, it raises the template with the given name. If the template doesn't exist, it raises
``django.core.template.TemplateDoesNotExist``. ``django.core.template.TemplateDoesNotExist``.
``django.core.template_loader.select_template(template_name_list)`` ``django.core.template.loader.select_template(template_name_list)``
``select_template`` is just like ``get_template``, except it takes a list ``select_template`` is just like ``get_template``, except it takes a list
of template names. Of the list, it returns the first template that exists. of template names. Of the list, it returns the first template that exists.
@ -398,8 +398,8 @@ Python code, depending on whether you're writing filters or tags.
.. admonition:: Behind the scenes .. admonition:: Behind the scenes
For a ton of examples, read the source code for Django's default filters For a ton of examples, read the source code for Django's default filters
and tags. They're in ``django/core/defaultfilters.py`` and and tags. They're in ``django/core/template/defaultfilters.py`` and
``django/core/defaulttags.py``, respectively. ``django/core/template/defaulttags.py``, respectively.
Writing custom template filters Writing custom template filters
------------------------------- -------------------------------
@ -710,4 +710,4 @@ The only new concept here is the ``self.nodelist.render(context)`` in
For more examples of complex rendering, see the source code for ``{% if %}``, For more examples of complex rendering, see the source code for ``{% if %}``,
``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in ``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in
``django/core/defaulttags.py``. ``django/core/template/defaulttags.py``.

View File

@ -191,14 +191,13 @@ There's a problem here, though: The page's design is hard-coded in the view. If
you want to change the way the page looks, you'll have to edit this Python code. you want to change the way the page looks, you'll have to edit this Python code.
So let's use Django's template system to separate the design from Python:: So let's use Django's template system to separate the design from Python::
from django.core import template_loader from django.core.template import Context, loader
from django.core.template import Context
from django.models.polls import polls from django.models.polls import polls
from django.utils.httpwrappers import HttpResponse from django.utils.httpwrappers import HttpResponse
def index(request): def index(request):
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5) latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
t = template_loader.get_template('polls/index') t = loader.get_template('polls/index')
c = Context({ c = Context({
'latest_poll_list': latest_poll_list, 'latest_poll_list': latest_poll_list,
}) })
@ -224,7 +223,7 @@ and feel" section of Tutorial 2.
When you've done that, create a directory ``polls`` in your template directory. When you've done that, create a directory ``polls`` in your template directory.
Within that, create a file called ``index.html``. Django requires that Within that, create a file called ``index.html``. Django requires that
templates have ".html" extension. Note that our templates have ".html" extension. Note that our
``template_loader.get_template('polls/index')`` code from above maps to ``loader.get_template('polls/index')`` code from above maps to
"[template_directory]/polls/index.html" on the filesystem. "[template_directory]/polls/index.html" on the filesystem.
Put the following code in that template:: Put the following code in that template::
@ -256,7 +255,7 @@ provides a shortcut. Here's the full ``index()`` view, rewritten::
latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5) latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
return render_to_response('polls/index', {'latest_poll_list': latest_poll_list}) return render_to_response('polls/index', {'latest_poll_list': latest_poll_list})
Note that we no longer need to import ``template_loader``, ``Context`` or Note that we no longer need to import ``loader``, ``Context`` or
``HttpResponse``. ``HttpResponse``.
The ``render_to_response()`` function takes a template name as its first The ``render_to_response()`` function takes a template name as its first

View File

@ -197,8 +197,8 @@ objects" and "display a detail page for a particular type of object."
By default, the ``object_detail`` generic view uses a template called By default, the ``object_detail`` generic view uses a template called
``<app_label>/<module_name>_detail``. In our case, it'll use the template ``<app_label>/<module_name>_detail``. In our case, it'll use the template
``"polls/polls_detail"``. Thus, rename your ``polls/detail.html`` template to ``"polls/polls_detail"``. Thus, rename your ``polls/detail.html`` template to
``polls/polls_detail.html``, and change the ``template_loader.get_template()`` ``polls/polls_detail.html``, and change the ``render_to_response()`` line in
line in ``vote()``. ``vote()``.
Similarly, the ``object_list`` generic view uses a template called Similarly, the ``object_list`` generic view uses a template called
``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to ``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to

View File

@ -1,4 +1,5 @@
from django.core import template, template_loader from django.core import template
from django.core.template import loader
# Helper objects for template tests # Helper objects for template tests
class SomeClass: class SomeClass:
@ -216,7 +217,7 @@ TEMPLATE_TESTS = {
'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError), 'exception04': ("{% extends 'inheritance17' %}{% block first %}{% echo 400 %}5678{% endblock %}", {}, template.TemplateSyntaxError),
} }
# This replaces the standard template_loader. # This replaces the standard template loader.
def test_template_loader(template_name, template_dirs=None): def test_template_loader(template_name, template_dirs=None):
try: try:
return TEMPLATE_TESTS[template_name][0] return TEMPLATE_TESTS[template_name][0]
@ -224,13 +225,13 @@ def test_template_loader(template_name, template_dirs=None):
raise template.TemplateDoesNotExist, template_name raise template.TemplateDoesNotExist, template_name
def run_tests(verbosity=0, standalone=False): def run_tests(verbosity=0, standalone=False):
template_loader.load_template_source, old_template_loader = test_template_loader, template_loader.load_template_source loader.load_template_source, old_template_loader = test_template_loader, loader.load_template_source
failed_tests = [] failed_tests = []
tests = TEMPLATE_TESTS.items() tests = TEMPLATE_TESTS.items()
tests.sort() tests.sort()
for name, vals in tests: for name, vals in tests:
try: try:
output = template_loader.get_template(name).render(template.Context(vals[1])) output = loader.get_template(name).render(template.Context(vals[1]))
except Exception, e: except Exception, e:
if e.__class__ == vals[2]: if e.__class__ == vals[2]:
if verbosity: if verbosity:
@ -247,7 +248,7 @@ def run_tests(verbosity=0, standalone=False):
if verbosity: if verbosity:
print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output) print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output)
failed_tests.append(name) failed_tests.append(name)
template_loader.load_template_source = old_template_loader loader.load_template_source = old_template_loader
if failed_tests and not standalone: if failed_tests and not standalone:
msg = "Template tests %s failed." % failed_tests msg = "Template tests %s failed." % failed_tests