class RangeNode(template.Node): def __init__(self, start, stop, step, context_name): if not self._isint(start): self.start = template.Variable(start) else: self.start = start if not self._isint(stop): self.stop = template.Variable(stop) else: self.stop = stop if not self._isint(step): self.step = template.Variable(step) else: self.step = step self.context_name = context_name def _isint(self, value): return isinstance(value, int) def _resolveint(self, value, context): if self._isint(value): return value return int(value.resolve(context)) def render(self, context): start = self._resolveint(self.start, context) stop = self._resolveint(self.stop, context) step = self._resolveint(self.step, context) context[self.context_name] = range(start, stop, step) return "" @register.tag def num_range(parser, token): """ Create a list containing an arithmetic progression that can be iterated through in templates. If the start argument is omitted, it defaults to 0. If step is positive, the last element is the largest start + i * step less than stop; if step is negative, the last element is the smallest start + i * step greater than stop. step must not be zero (or else ValueError is raised). see http://docs.python.org/library/functions.html#range for more details. Syntax: {% num_range [start] stop [step] as some_range %} {% for i in some_range %} ... do something {% endfor %} """ bits = token.contents.split() len_bits = len(bits) if len_bits not in range(4, 7): raise template.TemplateSyntaxError(_('%s tag requires between three and fifth arguments') % bits[0]) if bits[-2] != 'as': raise template.TemplateSyntaxError(_("last but one argument to %s tag must be 'as'") % bits[0]) #DEFAULTS start, step = 0, 1 as_index = bits.index('as') if as_index == 2: stop = bits[1] else: start, stop = bits[1], bits[2] if as_index == 4: step = bits[3] context_name = bits[-1] return RangeNode(start, stop, step, context_name)