diff --git a/django/core/extensions.py b/django/core/extensions.py index 6909ace33d..a7eaf3b06f 100644 --- a/django/core/extensions.py +++ b/django/core/extensions.py @@ -2,14 +2,13 @@ # of MVC. In other words, these functions/classes introduce controlled coupling # for convenience's sake. -from django.core import template_loader 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.utils.httpwrappers import HttpResponse 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. def get_object_or_404(mod, **kwargs): diff --git a/django/core/rss.py b/django/core/rss.py index cd2bcf4ad1..7563d2ea82 100644 --- a/django/core/rss.py +++ b/django/core/rss.py @@ -1,6 +1,5 @@ -from django.core import template_loader 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.utils import feedgenerator 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 dictionary to use in addition to get_list_kwargs (if applicable). - + get_pubdate_cb -- Function that takes the object and returns a datetime to use as the publication date in the feed. @@ -49,7 +48,7 @@ class FeedConfiguration: self.enc_url = enc_url self.enc_length = enc_length self.enc_mime_type = enc_mime_type - + def get_feed(self, param_slug=None): """ Returns a utils.feedgenerator.DefaultRssFeed object, fully populated, @@ -64,8 +63,8 @@ class FeedConfiguration: param = None current_site = sites.get_current() f = self._get_feed_generator_object(param) - title_template = template_loader.get_template('rss/%s_title' % self.slug) - description_template = template_loader.get_template('rss/%s_description' % self.slug) + title_template = loader.get_template('rss/%s_title' % self.slug) + description_template = loader.get_template('rss/%s_description' % self.slug) kwargs = self.get_list_kwargs.copy() if param and self.get_list_kwargs_cb: 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, ) return f - + def _get_feed_generator_object(self, param): current_site = sites.get_current() link = self.link_cb(param).decode() diff --git a/django/core/template.py b/django/core/template/__init__.py similarity index 100% rename from django/core/template.py rename to django/core/template/__init__.py diff --git a/django/core/defaultfilters.py b/django/core/template/defaultfilters.py similarity index 80% rename from django/core/defaultfilters.py rename to django/core/template/defaultfilters.py index b9e0e67745..9ef367ee52 100644 --- a/django/core/defaultfilters.py +++ b/django/core/template/defaultfilters.py @@ -1,6 +1,7 @@ "Default variable filters" -import template, re +from django.core.template import register_filter, resolve_variable +import re 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 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() 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 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.reverse() return [item[1] for item in decorated] @@ -414,52 +415,51 @@ def pprint(value, _): from pprint import pformat return pformat(value) -# Syntax: template.register_filter(name of filter, callback, has_argument) -template.register_filter('add', add, True) -template.register_filter('addslashes', addslashes, False) -template.register_filter('capfirst', capfirst, False) -template.register_filter('center', center, True) -template.register_filter('cut', cut, True) -template.register_filter('date', date, True) -template.register_filter('default', default, True) -template.register_filter('default_if_none', default_if_none, True) -template.register_filter('dictsort', dictsort, True) -template.register_filter('dictsortreversed', dictsortreversed, True) -template.register_filter('divisibleby', divisibleby, True) -template.register_filter('escape', escape, False) -template.register_filter('filesizeformat', filesizeformat, False) -template.register_filter('first', first, False) -template.register_filter('fix_ampersands', fix_ampersands, False) -template.register_filter('floatformat', floatformat, False) -template.register_filter('get_digit', get_digit, True) -template.register_filter('join', join, True) -template.register_filter('length', length, False) -template.register_filter('length_is', length_is, True) -template.register_filter('linebreaks', linebreaks, False) -template.register_filter('linebreaksbr', linebreaksbr, False) -template.register_filter('linenumbers', linenumbers, False) -template.register_filter('ljust', ljust, True) -template.register_filter('lower', lower, False) -template.register_filter('make_list', make_list, False) -template.register_filter('phone2numeric', phone2numeric, False) -template.register_filter('pluralize', pluralize, False) -template.register_filter('pprint', pprint, False) -template.register_filter('removetags', removetags, True) -template.register_filter('random', random, False) -template.register_filter('rjust', rjust, True) -template.register_filter('slice', slice_, True) -template.register_filter('slugify', slugify, False) -template.register_filter('stringformat', stringformat, True) -template.register_filter('striptags', striptags, False) -template.register_filter('time', time, True) -template.register_filter('timesince', timesince, False) -template.register_filter('title', title, False) -template.register_filter('truncatewords', truncatewords, True) -template.register_filter('unordered_list', unordered_list, False) -template.register_filter('upper', upper, False) -template.register_filter('urlencode', urlencode, False) -template.register_filter('urlize', urlize, False) -template.register_filter('urlizetrunc', urlizetrunc, True) -template.register_filter('wordcount', wordcount, False) -template.register_filter('wordwrap', wordwrap, True) -template.register_filter('yesno', yesno, True) +# Syntax: register_filter(name of filter, callback, has_argument) +register_filter('add', add, True) +register_filter('addslashes', addslashes, False) +register_filter('capfirst', capfirst, False) +register_filter('center', center, True) +register_filter('cut', cut, True) +register_filter('date', date, True) +register_filter('default', default, True) +register_filter('dictsort', dictsort, True) +register_filter('dictsortreversed', dictsortreversed, True) +register_filter('divisibleby', divisibleby, True) +register_filter('escape', escape, False) +register_filter('filesizeformat', filesizeformat, False) +register_filter('first', first, False) +register_filter('fix_ampersands', fix_ampersands, False) +register_filter('floatformat', floatformat, False) +register_filter('get_digit', get_digit, True) +register_filter('join', join, True) +register_filter('length', length, False) +register_filter('length_is', length_is, True) +register_filter('linebreaks', linebreaks, False) +register_filter('linebreaksbr', linebreaksbr, False) +register_filter('linenumbers', linenumbers, False) +register_filter('ljust', ljust, True) +register_filter('lower', lower, False) +register_filter('make_list', make_list, False) +register_filter('phone2numeric', phone2numeric, False) +register_filter('pluralize', pluralize, False) +register_filter('pprint', pprint, False) +register_filter('removetags', removetags, True) +register_filter('random', random, False) +register_filter('rjust', rjust, True) +register_filter('slice', slice_, True) +register_filter('slugify', slugify, False) +register_filter('stringformat', stringformat, True) +register_filter('striptags', striptags, False) +register_filter('time', time, True) +register_filter('timesince', timesince, False) +register_filter('title', title, False) +register_filter('truncatewords', truncatewords, True) +register_filter('unordered_list', unordered_list, False) +register_filter('upper', upper, False) +register_filter('urlencode', urlencode, False) +register_filter('urlize', urlize, False) +register_filter('urlizetrunc', urlizetrunc, True) +register_filter('wordcount', wordcount, False) +register_filter('wordwrap', wordwrap, True) +register_filter('yesno', yesno, True) diff --git a/django/core/defaulttags.py b/django/core/template/defaulttags.py similarity index 81% rename from django/core/defaulttags.py rename to django/core/template/defaulttags.py index e86b385f9c..ea21ebafce 100644 --- a/django/core/defaulttags.py +++ b/django/core/template/defaulttags.py @@ -1,13 +1,14 @@ "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 template -class CommentNode(template.Node): +class CommentNode(Node): def render(self, context): return '' -class CycleNode(template.Node): +class CycleNode(Node): def __init__(self, cyclevars): self.cyclevars = cyclevars self.cyclevars_len = len(cyclevars) @@ -17,7 +18,7 @@ class CycleNode(template.Node): self.counter += 1 return self.cyclevars[self.counter % self.cyclevars_len] -class DebugNode(template.Node): +class DebugNode(Node): def render(self, context): from pprint import pformat output = [pformat(val) for val in context] @@ -25,7 +26,7 @@ class DebugNode(template.Node): output.append(pformat(sys.modules)) return ''.join(output) -class FilterNode(template.Node): +class FilterNode(Node): def __init__(self, filters, nodelist): self.filters, self.nodelist = filters, nodelist @@ -33,21 +34,21 @@ class FilterNode(template.Node): output = self.nodelist.render(context) # apply 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 -class FirstOfNode(template.Node): +class FirstOfNode(Node): def __init__(self, vars): self.vars = vars def render(self, context): for var in self.vars: - value = template.resolve_variable(var, context) + value = resolve_variable(var, context) if value: return str(value) return '' -class ForNode(template.Node): +class ForNode(Node): def __init__(self, loopvar, sequence, reversed, nodelist_loop): self.loopvar, self.sequence = loopvar, sequence self.reversed = reversed @@ -73,15 +74,15 @@ class ForNode(template.Node): return nodes def render(self, context): - nodelist = template.NodeList() + nodelist = NodeList() if context.has_key('forloop'): parentloop = context['forloop'] else: parentloop = {} context.push() try: - values = template.resolve_variable_with_filters(self.sequence, context) - except template.VariableDoesNotExist: + values = resolve_variable_with_filters(self.sequence, context) + except VariableDoesNotExist: values = [] if values is None: values = [] @@ -111,7 +112,7 @@ class ForNode(template.Node): context.pop() return nodelist.render(context) -class IfChangedNode(template.Node): +class IfChangedNode(Node): def __init__(self, nodelist): self.nodelist = nodelist self._last_seen = None @@ -129,7 +130,7 @@ class IfChangedNode(template.Node): else: return '' -class IfEqualNode(template.Node): +class IfEqualNode(Node): def __init__(self, var1, var2, nodelist_true, nodelist_false, negate): self.var1, self.var2 = var1, var2 self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false @@ -139,13 +140,13 @@ class IfEqualNode(template.Node): return "" def render(self, context): - val1 = template.resolve_variable(self.var1, context) - val2 = template.resolve_variable(self.var2, context) + val1 = resolve_variable(self.var1, context) + val2 = resolve_variable(self.var2, context) if (self.negate and val1 != val2) or (not self.negate and val1 == val2): return self.nodelist_true.render(context) return self.nodelist_false.render(context) -class IfNode(template.Node): +class IfNode(Node): def __init__(self, boolvars, nodelist_true, nodelist_false): self.boolvars = boolvars self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false @@ -170,27 +171,27 @@ class IfNode(template.Node): def render(self, context): for ifnot, boolvar in self.boolvars: try: - value = template.resolve_variable_with_filters(boolvar, context) - except template.VariableDoesNotExist: + value = resolve_variable_with_filters(boolvar, context) + except VariableDoesNotExist: value = None if (value and not ifnot) or (ifnot and not value): return self.nodelist_true.render(context) return self.nodelist_false.render(context) -class RegroupNode(template.Node): +class RegroupNode(Node): def __init__(self, target_var, expression, var_name): self.target_var, self.expression = target_var, expression self.var_name = var_name 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 context[self.var_name] = [] return '' output = [] # list of dictionaries in the format {'grouper': 'key', 'list': [list of contents]} for obj in obj_list: - grouper = template.resolve_variable_with_filters('var.%s' % self.expression, \ - template.Context({'var': obj})) + grouper = resolve_variable_with_filters('var.%s' % self.expression, \ + Context({'var': obj})) if output and repr(output[-1]['grouper']) == repr(grouper): output[-1]['list'].append(obj) else: @@ -205,7 +206,7 @@ def include_is_allowed(filepath): return True return False -class SsiNode(template.Node): +class SsiNode(Node): def __init__(self, filepath, parsed): self.filepath, self.parsed = filepath, parsed @@ -220,13 +221,13 @@ class SsiNode(template.Node): output = '' if self.parsed: try: - t = template.Template(output) + t = Template(output) return t.render(context) - except template.TemplateSyntaxError: + except TemplateSyntaxError: return '' # Fail silently for invalid included templates. return output -class LoadNode(template.Node): +class LoadNode(Node): def __init__(self, taglib): self.taglib = taglib @@ -244,7 +245,7 @@ class LoadNode(template.Node): pass # Fail silently for invalid loads. return '' -class NowNode(template.Node): +class NowNode(Node): def __init__(self, format_string): self.format_string = format_string @@ -254,11 +255,11 @@ class NowNode(template.Node): df = DateFormat(datetime.now()) return df.format(self.format_string) -class TemplateTagNode(template.Node): - mapping = {'openblock': template.BLOCK_TAG_START, - 'closeblock': template.BLOCK_TAG_END, - 'openvariable': template.VARIABLE_TAG_START, - 'closevariable': template.VARIABLE_TAG_END} +class TemplateTagNode(Node): + mapping = {'openblock': BLOCK_TAG_START, + 'closeblock': BLOCK_TAG_END, + 'openvariable': VARIABLE_TAG_START, + 'closevariable': VARIABLE_TAG_END} def __init__(self, tagtype): self.tagtype = tagtype @@ -266,7 +267,7 @@ class TemplateTagNode(template.Node): def render(self, context): return self.mapping.get(self.tagtype, '') -class WidthRatioNode(template.Node): +class WidthRatioNode(Node): def __init__(self, val_var, max_var, max_width): self.val_var = val_var self.max_var = max_var @@ -274,9 +275,9 @@ class WidthRatioNode(template.Node): def render(self, context): try: - value = template.resolve_variable_with_filters(self.val_var, context) - maxvalue = template.resolve_variable_with_filters(self.max_var, context) - except template.VariableDoesNotExist: + value = resolve_variable_with_filters(self.val_var, context) + maxvalue = resolve_variable_with_filters(self.max_var, context) + except VariableDoesNotExist: return '' try: value = float(value) @@ -330,7 +331,7 @@ def do_cycle(parser, token): args = token.contents.split() 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]: # {% cycle a,b,c %} @@ -341,13 +342,13 @@ def do_cycle(parser, token): elif len(args) == 2: name = args[1] 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] elif len(args) == 4: # {% cycle a,b,c as name %} 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 name = args[3] node = CycleNode(cyclevars) @@ -359,7 +360,7 @@ def do_cycle(parser, token): return node else: - raise template.TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args) + raise TemplateSyntaxError("Invalid arguments to 'cycle': %s" % args) def do_debug(parser, token): "Print a whole load of debugging information, including the context and imported modules" @@ -379,7 +380,7 @@ def do_filter(parser, token): {% endfilter %} """ _, 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',)) parser.delete_first_token() return FilterNode(filters, nodelist) @@ -408,7 +409,7 @@ def do_firstof(parser, token): """ bits = token.contents.split()[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) @@ -434,9 +435,9 @@ def do_for(parser, token): ========================== ================================================ ``forloop.counter`` The current iteration of the loop (1-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) - ``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) ``forloop.first`` True if this is the first time through the loop ``forloop.last`` True if this is the last time through the loop @@ -447,11 +448,11 @@ def do_for(parser, token): """ bits = token.contents.split() 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): - 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': - 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] sequence = bits[3] reversed = (len(bits) == 5) @@ -477,7 +478,7 @@ def do_ifequal(parser, token, negate): """ bits = token.contents.split() 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] nodelist_true = parser.parse(('else', end_tag)) token = parser.next_token() @@ -485,7 +486,7 @@ def do_ifequal(parser, token, negate): nodelist_false = parser.parse((end_tag,)) parser.delete_first_token() else: - nodelist_false = template.NodeList() + nodelist_false = NodeList() return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate) def do_if(parser, token): @@ -538,7 +539,7 @@ def do_if(parser, token): bits = token.contents.split() del bits[0] 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'] boolpairs = ' '.join(bits).split(' or ') boolvars = [] @@ -546,7 +547,7 @@ def do_if(parser, token): if ' ' in boolpair: not_, boolvar = boolpair.split() if not_ != 'not': - raise template.TemplateSyntaxError, "Expected 'not' in if statement" + raise TemplateSyntaxError, "Expected 'not' in if statement" boolvars.append((True, boolvar)) else: boolvars.append((False, boolpair)) @@ -556,7 +557,7 @@ def do_if(parser, token): nodelist_false = parser.parse(('endif',)) parser.delete_first_token() else: - nodelist_false = template.NodeList() + nodelist_false = NodeList() return IfNode(boolvars, nodelist_true, nodelist_false) def do_ifchanged(parser, token): @@ -576,7 +577,7 @@ def do_ifchanged(parser, token): """ bits = token.contents.split() if len(bits) != 1: - raise template.TemplateSyntaxError, "'ifchanged' tag takes no arguments" + raise TemplateSyntaxError, "'ifchanged' tag takes no arguments" nodelist = parser.parse(('endifchanged',)) parser.delete_first_token() return IfChangedNode(nodelist) @@ -599,12 +600,12 @@ def do_ssi(parser, token): bits = token.contents.split() parsed = False 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 bits[2] == 'parsed': parsed = True 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) def do_load(parser, token): @@ -617,13 +618,13 @@ def do_load(parser, token): """ bits = token.contents.split() if len(bits) != 2: - raise template.TemplateSyntaxError, "'load' statement takes one argument" + raise TemplateSyntaxError, "'load' statement takes one argument" taglib = bits[1] # check at compile time that the module can be imported try: LoadNode.load_taglib(taglib) except ImportError: - raise template.TemplateSyntaxError, "'%s' is not a valid tag library" % taglib + raise TemplateSyntaxError, "'%s' is not a valid tag library" % taglib return LoadNode(taglib) def do_now(parser, token): @@ -639,7 +640,7 @@ def do_now(parser, token): """ bits = token.contents.split('"') if len(bits) != 3: - raise template.TemplateSyntaxError, "'now' statement takes one argument" + raise TemplateSyntaxError, "'now' statement takes one argument" format_string = bits[1] return NowNode(format_string) @@ -691,13 +692,13 @@ def do_regroup(parser, token): """ firstbits = token.contents.split(None, 3) if len(firstbits) != 4: - raise template.TemplateSyntaxError, "'regroup' tag takes five arguments" + raise TemplateSyntaxError, "'regroup' tag takes five arguments" target_var = firstbits[1] 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) 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] var_name = lastbits_reversed[0][::-1] return RegroupNode(target_var, expression, var_name) @@ -722,10 +723,10 @@ def do_templatetag(parser, token): """ bits = token.contents.split() if len(bits) != 2: - raise template.TemplateSyntaxError, "'templatetag' statement takes one argument" + raise TemplateSyntaxError, "'templatetag' statement takes one argument" tag = bits[1] 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()) return TemplateTagNode(tag) @@ -744,27 +745,27 @@ def do_widthratio(parser, token): """ bits = token.contents.split() 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 try: max_width = int(max_width) 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) -template.register_tag('comment', do_comment) -template.register_tag('cycle', do_cycle) -template.register_tag('debug', do_debug) -template.register_tag('filter', do_filter) -template.register_tag('firstof', do_firstof) -template.register_tag('for', do_for) -template.register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False)) -template.register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True)) -template.register_tag('if', do_if) -template.register_tag('ifchanged', do_ifchanged) -template.register_tag('regroup', do_regroup) -template.register_tag('ssi', do_ssi) -template.register_tag('load', do_load) -template.register_tag('now', do_now) -template.register_tag('templatetag', do_templatetag) -template.register_tag('widthratio', do_widthratio) +register_tag('comment', do_comment) +register_tag('cycle', do_cycle) +register_tag('debug', do_debug) +register_tag('filter', do_filter) +register_tag('firstof', do_firstof) +register_tag('for', do_for) +register_tag('ifequal', lambda parser, token: do_ifequal(parser, token, False)) +register_tag('ifnotequal', lambda parser, token: do_ifequal(parser, token, True)) +register_tag('if', do_if) +register_tag('ifchanged', do_ifchanged) +register_tag('regroup', do_regroup) +register_tag('ssi', do_ssi) +register_tag('load', do_load) +register_tag('now', do_now) +register_tag('templatetag', do_templatetag) +register_tag('widthratio', do_widthratio) diff --git a/django/core/template/loader.py b/django/core/template/loader.py new file mode 100644 index 0000000000..65a6c735b3 --- /dev/null +++ b/django/core/template/loader.py @@ -0,0 +1,163 @@ +"Wrapper for loading templates from storage of some sort (e.g. files or db)" + +from django.core.template import Template, Context, Node, TemplateDoesNotExist, TemplateSyntaxError, resolve_variable_with_filters, register_tag +from django.core.template.loaders.filesystem import load_template_source + +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(load_template_source(template_name)) + +def get_template_from_string(source): + """ + Returns a compiled Template object for the given template code, + handling template inheritance recursively. + """ + return Template(source) + +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 "" % (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(load_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) + +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 ``{% entends 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) + +register_tag('block', do_block) +register_tag('extends', do_extends) diff --git a/django/core/template/loaders/__init__.py b/django/core/template/loaders/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/django/core/template_file.py b/django/core/template/loaders/filesystem.py similarity index 93% rename from django/core/template_file.py rename to django/core/template/loaders/filesystem.py index 6f5a324d61..849f62b94e 100644 --- a/django/core/template_file.py +++ b/django/core/template/loaders/filesystem.py @@ -1,4 +1,4 @@ -# 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.core.template import TemplateDoesNotExist diff --git a/django/core/template_loader.py b/django/core/template_loader.py index 7c26cf0faa..e268c390e1 100644 --- a/django/core/template_loader.py +++ b/django/core/template_loader.py @@ -1,162 +1,7 @@ -"Wrapper for loading templates from storage of some sort (e.g. files or db)" -import template -from template_file import load_template_source +# This module is DEPRECATED! +# +# You should no longer be using django.core.template_loader. +# +# Use django.core.template.loader instead. -class ExtendsError(Exception): - 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(load_template_source(template_name)) - -def get_template_from_string(source): - """ - Returns a compiled template.Template object for the given template code, - handling template inheritance recursively. - """ - return template.Template(source) - -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 "" % (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(load_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 ``{% entends 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) +from django.core.template.loader import * diff --git a/django/middleware/admin.py b/django/middleware/admin.py index ff21689646..9c20cfc31c 100644 --- a/django/middleware/admin.py +++ b/django/middleware/admin.py @@ -1,6 +1,6 @@ from django.utils import httpwrappers -from django.core import template_loader -from django.core.extensions import DjangoContext as Context +from django.core.extensions import DjangoContext +from django.core.extensions import render_to_response from django.models.auth import users from django.views.registration import passwords from django.views.auth.login import logout @@ -96,14 +96,12 @@ class AdminUserRequired: post_data = encode_post_data(request.POST) else: post_data = encode_post_data({}) - t = template_loader.get_template(self.get_login_template_name()) - c = Context(request, { + return render_to_response(self.get_login_template_name(), { 'title': 'Log in', 'app_path': request.path, 'post_data': post_data, 'error_message': error_message - }) - return httpwrappers.HttpResponse(t.render(c)) + }, context_instance=DjangoContext(request)) def authenticate_user(self, user, password): return user.check_password(password) and user.is_staff diff --git a/django/views/admin/doc.py b/django/views/admin/doc.py index 38d7fdc572..64785385c4 100644 --- a/django/views/admin/doc.py +++ b/django/views/admin/doc.py @@ -4,7 +4,8 @@ from django.conf import settings from django.models.core import sites from django.core.extensions import DjangoContext, render_to_response 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: from django.parts.admin import doc except ImportError: diff --git a/django/views/admin/template.py b/django/views/admin/template.py index 2bf4f1a1d8..c35770178e 100644 --- a/django/views/admin/template.py +++ b/django/views/admin/template.py @@ -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.template import loader from django.core.extensions import DjangoContext, render_to_response from django.models.core import sites 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 # for "extends" that uses the site's TEMPLATE_DIR instead 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 return node 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 error = None try: - tmpl = template_loader.get_template_from_string(field_data) + tmpl = loader.get_template_from_string(field_data) tmpl.render(template.Context({})) except template.TemplateSyntaxError, e: error = e - template.register_tag('extends', template_loader.do_extends) + template.register_tag('extends', loader.do_extends) if error: raise validators.ValidationError, e.args diff --git a/django/views/auth/login.py b/django/views/auth/login.py index 75a80c7907..6950ad7efe 100644 --- a/django/views/auth/login.py +++ b/django/views/auth/login.py @@ -1,5 +1,5 @@ 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.models.auth import users from django.models.core import sites diff --git a/django/views/defaults.py b/django/views/defaults.py index c75bc6880e..d283e54c1b 100644 --- a/django/views/defaults.py +++ b/django/views/defaults.py @@ -1,6 +1,5 @@ -from django.core import template_loader 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.utils import httpwrappers @@ -56,7 +55,7 @@ def page_not_found(request): if r == '': return httpwrappers.HttpResponseGone() return httpwrappers.HttpResponseRedirect(r.new_path) - t = template_loader.get_template('404') + t = loader.get_template('404') c = Context() return httpwrappers.HttpResponseNotFound(t.render(c)) @@ -67,6 +66,6 @@ def server_error(request): Templates: `500` Context: None """ - t = template_loader.get_template('500') + t = loader.get_template('500') c = Context() return httpwrappers.HttpResponseServerError(t.render(c)) diff --git a/django/views/registration/passwords.py b/django/views/registration/passwords.py index 662490eec7..09d3037560 100644 --- a/django/views/registration/passwords.py +++ b/django/views/registration/passwords.py @@ -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.template import loader from django.models.auth import users from django.views.decorators.auth import login_required from django.utils.httpwrappers import HttpResponseRedirect @@ -32,7 +33,7 @@ class PasswordResetForm(formfields.Manipulator): domain = current_site.domain else: site_name = domain = domain_override - t = template_loader.get_template('registration/password_reset_email') + t = loader.get_template('registration/password_reset_email') c = { 'new_password': new_pass, 'email': self.user_cache.email, diff --git a/docs/forms.txt b/docs/forms.txt index c93db95bcd..969ebd428d 100644 --- a/docs/forms.txt +++ b/docs/forms.txt @@ -65,9 +65,8 @@ Using the ``AddManipulator`` 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:: - from django.core import template_loader 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.models.places import places 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 # the last two arguments to FormWrapper for now. form = formfields.FormWrapper(places.AddManipulator(), {}, {}) - - # 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)) + return render_to_response('places/naive_create_form', {'form': form}) (This view, as well as all the following ones, has the same imports as in the first example above.) @@ -169,11 +162,7 @@ creation view that takes validation into account:: # Check for validation errors errors = manipulator.get_validation_errors(new_data) if errors: - t = template_loader.get_template('places/errors') - c = Context(request, { - 'errors': errors - } - return HttpResponse(t.render(c)) + return render_to_response('places/errors', {'errors': errors}) else: manipulator.do_html2python(request.POST) new_place = manipulator.save(request.POST) @@ -245,11 +234,7 @@ Below is the finished view:: # Create the FormWrapper, template, context, response. form = formfields.FormWrapper(manipulator, new_data, errors) - t = template_loader.get_template("places/create_form") - c = Context(request, { - 'form': form, - }) - return HttpResponse(t.render(c)) + return render_to_response('places/create_form', {'form': form}) 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__ form = formfields.FormWrapper(manipulator, new_data, errors) - t = template_loader.get_template("places/edit_form") - c = Context(request, { - 'form': form, - 'place': place, - }) - return HttpResponse(t.render(c)) + return render_to_response('places/edit_form', {'form': form, 'place': place}) The only real differences are: @@ -422,11 +402,7 @@ Here's a simple function that might drive the above form:: else: errors = new_data = {} form = formfields.FormWrapper(manipulator, new_data, errors) - t = template_loader.get_template("contact_form") - c = Context(request, { - 'form': form, - }) - return HttpResponse(t.render(c)) + return render_to_response('contact_form', {'form': form}) Validators ========== diff --git a/docs/sessions.txt b/docs/sessions.txt index 22d06fdedd..b18ca25a2c 100644 --- a/docs/sessions.txt +++ b/docs/sessions.txt @@ -136,9 +136,7 @@ Here's a typical usage example:: else: return HttpResponse("Please enable cookies and try again.") request.session.set_test_cookie() - t = template_loader.get_template("foo/login_form") - c = Context(request) - return HttpResponse(t.render(c)) + return render_to_response('foo/login_form') Using sessions out of views =========================== diff --git a/docs/templates_python.txt b/docs/templates_python.txt index 39b768429b..bd8aea62c7 100644 --- a/docs/templates_python.txt +++ b/docs/templates_python.txt @@ -307,12 +307,12 @@ The Python API 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 the template with the given name. If the template doesn't exist, it raises ``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 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 For a ton of examples, read the source code for Django's default filters - and tags. They're in ``django/core/defaultfilters.py`` and - ``django/core/defaulttags.py``, respectively. + and tags. They're in ``django/core/template/defaultfilters.py`` and + ``django/core/template/defaulttags.py``, respectively. 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 %}``, ``{% ifequal %}`` and ``{% ifchanged %}``. They live in -``django/core/defaulttags.py``. +``django/core/template/defaulttags.py``. diff --git a/docs/tutorial03.txt b/docs/tutorial03.txt index 84fb64abfe..f602bf2ebd 100644 --- a/docs/tutorial03.txt +++ b/docs/tutorial03.txt @@ -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. 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 + from django.core.template import Context, loader from django.models.polls import polls from django.utils.httpwrappers import HttpResponse def index(request): 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({ '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. Within that, create a file called ``index.html``. Django requires that 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. 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) 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``. The ``render_to_response()`` function takes a template name as its first diff --git a/docs/tutorial04.txt b/docs/tutorial04.txt index 3e6d6205bb..737d8deb1f 100644 --- a/docs/tutorial04.txt +++ b/docs/tutorial04.txt @@ -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 ``/_detail``. In our case, it'll use the template ``"polls/polls_detail"``. Thus, rename your ``polls/detail.html`` template to -``polls/polls_detail.html``, and change the ``template_loader.get_template()`` -line in ``vote()``. +``polls/polls_detail.html``, and change the ``render_to_response()`` line in +``vote()``. Similarly, the ``object_list`` generic view uses a template called ``/_list``. Thus, rename ``polls/index.html`` to diff --git a/tests/othertests/templates.py b/tests/othertests/templates.py index fb96cfeadd..f2da069ea2 100644 --- a/tests/othertests/templates.py +++ b/tests/othertests/templates.py @@ -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 class SomeClass: @@ -216,7 +217,7 @@ TEMPLATE_TESTS = { '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): try: return TEMPLATE_TESTS[template_name][0] @@ -224,13 +225,13 @@ def test_template_loader(template_name, template_dirs=None): raise template.TemplateDoesNotExist, template_name 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 = [] tests = TEMPLATE_TESTS.items() tests.sort() for name, vals in tests: 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: if e.__class__ == vals[2]: if verbosity: @@ -247,7 +248,7 @@ def run_tests(verbosity=0, standalone=False): if verbosity: print "Template test: %s -- FAILED. Expected %r, got %r" % (name, vals[2], output) 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: msg = "Template tests %s failed." % failed_tests