--- a/app/django/template/defaulttags.py Tue Oct 14 12:36:55 2008 +0000
+++ b/app/django/template/defaulttags.py Tue Oct 14 16:00:59 2008 +0000
@@ -39,12 +39,11 @@
class CycleNode(Node):
def __init__(self, cyclevars, variable_name=None):
- self.cycle_iter = itertools_cycle(cyclevars)
+ self.cycle_iter = itertools_cycle([Variable(v) for v in cyclevars])
self.variable_name = variable_name
def render(self, context):
- value = self.cycle_iter.next()
- value = Variable(value).resolve(context)
+ value = self.cycle_iter.next().resolve(context)
if self.variable_name:
context[self.variable_name] = value
return value
@@ -158,34 +157,37 @@
return nodelist.render(context)
class IfChangedNode(Node):
- def __init__(self, nodelist, *varlist):
- self.nodelist = nodelist
+ def __init__(self, nodelist_true, nodelist_false, *varlist):
+ self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self._last_seen = None
self._varlist = map(Variable, varlist)
+ self._id = str(id(self))
def render(self, context):
- if 'forloop' in context and context['forloop']['first']:
+ if 'forloop' in context and self._id not in context['forloop']:
self._last_seen = None
+ context['forloop'][self._id] = 1
try:
if self._varlist:
# Consider multiple parameters. This automatically behaves
# like an OR evaluation of the multiple variables.
compare_to = [var.resolve(context) for var in self._varlist]
else:
- compare_to = self.nodelist.render(context)
+ compare_to = self.nodelist_true.render(context)
except VariableDoesNotExist:
compare_to = None
- if compare_to != self._last_seen:
+ if compare_to != self._last_seen:
firstloop = (self._last_seen == None)
self._last_seen = compare_to
context.push()
context['ifchanged'] = {'firstloop': firstloop}
- content = self.nodelist.render(context)
+ content = self.nodelist_true.render(context)
context.pop()
return content
- else:
- return ''
+ elif self.nodelist_false:
+ return self.nodelist_false.render(context)
+ return ''
class IfEqualNode(Node):
def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
@@ -349,25 +351,40 @@
return self.mapping.get(self.tagtype, '')
class URLNode(Node):
- def __init__(self, view_name, args, kwargs):
+ def __init__(self, view_name, args, kwargs, asvar):
self.view_name = view_name
self.args = args
self.kwargs = kwargs
+ self.asvar = asvar
def render(self, context):
from django.core.urlresolvers import reverse, NoReverseMatch
args = [arg.resolve(context) for arg in self.args]
kwargs = dict([(smart_str(k,'ascii'), v.resolve(context))
for k, v in self.kwargs.items()])
+
+
+ # Try to look up the URL twice: once given the view name, and again
+ # relative to what we guess is the "main" app. If they both fail,
+ # re-raise the NoReverseMatch unless we're using the
+ # {% url ... as var %} construct in which cause return nothing.
+ url = ''
try:
- return reverse(self.view_name, args=args, kwargs=kwargs)
+ url = reverse(self.view_name, args=args, kwargs=kwargs)
except NoReverseMatch:
+ project_name = settings.SETTINGS_MODULE.split('.')[0]
try:
- project_name = settings.SETTINGS_MODULE.split('.')[0]
- return reverse(project_name + '.' + self.view_name,
- args=args, kwargs=kwargs)
+ url = reverse(project_name + '.' + self.view_name,
+ args=args, kwargs=kwargs)
except NoReverseMatch:
- return ''
+ if self.asvar is None:
+ raise
+
+ if self.asvar:
+ context[self.asvar] = url
+ return ''
+ else:
+ return url
class WidthRatioNode(Node):
def __init__(self, val_expr, max_expr, max_width):
@@ -452,17 +469,17 @@
<tr class="{% cycle rowcolors %}">...</tr>
<tr class="{% cycle rowcolors %}">...</tr>
- You can use any number of values, seperated by spaces. Commas can also
+ You can use any number of values, separated by spaces. Commas can also
be used to separate values; if a comma is used, the cycle values are
interpreted as literal strings.
"""
# Note: This returns the exact same node on each {% cycle name %} call;
# that is, the node object returned from {% cycle a b c as name %} and the
- # one returned from {% cycle name %} are the exact same object. This
+ # one returned from {% cycle name %} are the exact same object. This
# shouldn't cause problems (heh), but if it does, now you know.
#
- # Ugly hack warning: this stuffs the named template dict into parser so
+ # Ugly hack warning: This stuffs the named template dict into parser so
# that names are only unique within each template (as opposed to using
# a global variable, which would make cycle names have to be unique across
# *all* templates.
@@ -481,8 +498,7 @@
# {% cycle foo %} case.
name = args[1]
if not hasattr(parser, '_namedCycleNodes'):
- raise TemplateSyntaxError("No named cycles in template."
- " '%s' is not defined" % name)
+ raise TemplateSyntaxError("No named cycles in template. '%s' is not defined" % name)
if not name in parser._namedCycleNodes:
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
return parser._namedCycleNodes[name]
@@ -682,8 +698,10 @@
def do_if(parser, token):
"""
The ``{% if %}`` tag evaluates a variable, and if that variable is "true"
- (i.e. exists, is not empty, and is not a false boolean value) the contents
- of the block are output::
+ (i.e., exists, is not empty, and is not a false boolean value), the
+ contents of the block are output:
+
+ ::
{% if athlete_list %}
Number of athletes: {{ athlete_list|count }}
@@ -801,9 +819,14 @@
{% endfor %}
"""
bits = token.contents.split()
- nodelist = parser.parse(('endifchanged',))
- parser.delete_first_token()
- return IfChangedNode(nodelist, *bits[1:])
+ nodelist_true = parser.parse(('else', 'endifchanged'))
+ token = parser.next_token()
+ if token.contents == 'else':
+ nodelist_false = parser.parse(('endifchanged',))
+ parser.delete_first_token()
+ else:
+ nodelist_false = NodeList()
+ return IfChangedNode(nodelist_true, nodelist_false, *bits[1:])
ifchanged = register.tag(ifchanged)
#@register.tag
@@ -1036,21 +1059,30 @@
The URL will look like ``/clients/client/123/``.
"""
- bits = token.contents.split(' ', 2)
+ bits = token.contents.split(' ')
if len(bits) < 2:
raise TemplateSyntaxError("'%s' takes at least one argument"
" (path to a view)" % bits[0])
+ viewname = bits[1]
args = []
kwargs = {}
+ asvar = None
+
if len(bits) > 2:
- for arg in bits[2].split(','):
- if '=' in arg:
- k, v = arg.split('=', 1)
- k = k.strip()
- kwargs[k] = parser.compile_filter(v)
+ bits = iter(bits[2:])
+ for bit in bits:
+ if bit == 'as':
+ asvar = bits.next()
+ break
else:
- args.append(parser.compile_filter(arg))
- return URLNode(bits[1], args, kwargs)
+ for arg in bit.split(","):
+ if '=' in arg:
+ k, v = arg.split('=', 1)
+ k = k.strip()
+ kwargs[k] = parser.compile_filter(v)
+ elif arg:
+ args.append(parser.compile_filter(arg))
+ return URLNode(viewname, args, kwargs, asvar)
url = register.tag(url)
#@register.tag