Index: django/template/defaulttags.py
===================================================================
--- django/template/defaulttags.py	(revision 6413)
+++ django/template/defaulttags.py	(working copy)
@@ -69,6 +69,59 @@
                 return smart_unicode(value)
         return u''
 
+class NumForNode(Node):
+    def __init__(self, loopvar, start, end, step, exclusive, nodelist_loop):
+        self.loopvar = loopvar
+        self.start = Variable(start)
+        self.end = Variable(end)
+        self.step = Variable(step)
+        self.exclusive = exclusive
+        self.nodelist_loop = nodelist_loop
+
+    def __repr__(self):
+        if self.exclusive:
+            exclusive = ' exclusive'
+        else:
+            exclusive = ''
+
+        if step != 1:
+            step_str = ' by %s' % step
+        else:
+            step_str = ''
+
+        return '<For Node: for %s %s to %s%s%s>' % \
+                (self.loopvar, self.start, self.end,
+                 step_str, exclusive)
+
+    def __iter__(self):
+        for node in self.nodelist_loop:
+            yield node
+
+    def make_seq(self, context):
+        start = int(self.start.resolve(context))
+        end = int(self.end.resolve(context))
+        step = int(self.step.resolve(context))
+    
+        if step < 0:
+            end -= int(not self.exclusive)
+        else:
+            end += int(not self.exclusive)
+
+        return xrange(start, end, step)
+
+
+    def render(self, context):
+        nodelist = NodeList()
+        context.push()
+        seq = self.make_seq(context)
+        for i in seq:
+            context[self.loopvar] = i
+            for node in self.nodelist_loop:
+                nodelist.append(node.render(context))
+        context.pop()
+        return nodelist.render(context)
+
+
 class ForNode(Node):
     def __init__(self, loopvars, sequence, reversed, nodelist_loop):
         self.loopvars, self.sequence = loopvars, sequence
@@ -565,9 +618,13 @@
 
     """
     bits = token.contents.split()
+
     if len(bits) < 4:
         raise TemplateSyntaxError, "'for' statements should have at least four words: %s" % token.contents
 
+    if bits[-3] != 'in' and bits[-2] != 'in':
+        return do_numfor(parser, token)
+
     reversed = bits[-1] == 'reversed'
     in_index = reversed and -3 or -2
     if bits[in_index] != 'in':
@@ -584,6 +641,35 @@
     return ForNode(loopvars, sequence, reversed, nodelist_loop)
 do_for = register.tag("for", do_for)
 
+def do_numfor(parser, token):
+    bits = token.split_contents()
+
+    if len(bits) < 5:
+        raise TemplateSyntaxError("num 'for' tag should have at least 5 arguments: %s" % token.contents)
+    if bits[3] != 'to':
+        raise TemplateSyntaxError("num 'for' tag should use the format 'for i 1 to 5': %s" % token.contents)
+    try:
+        start, end = bits[2], bits[4]
+    except ValueError:
+        raise TemplateSyntaxError("num 'for' tag should use the format 'for i 1 to 5': %s" % token.contents)
+        
+    step = '1'
+    try:
+        if bits[5] == 'by':
+            try:
+                step = bits[6]
+            except IndexError:
+                raise TemplateSyntaxError("step value required after 'by' keyword: %s" % token.contents)
+    except IndexError:
+        pass
+    exclusive = bits[-1] == 'exclusive'
+
+    loopvar = bits[1]
+
+    nodelist_loop = parser.parse(('endfor',))
+    parser.delete_first_token()
+    return NumForNode(loopvar, start, end, step, exclusive, nodelist_loop)
+
 def do_ifequal(parser, token, negate):
     bits = list(token.split_contents())
     if len(bits) != 3:
Index: tests/regressiontests/templates/tests.py
===================================================================
--- tests/regressiontests/templates/tests.py	(revision 6413)
+++ tests/regressiontests/templates/tests.py	(working copy)
@@ -365,6 +365,23 @@
             'for-tag-unpack12': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2))}, ("one:1,carrot/two:2,/", "one:1,carrot/two:2,INVALID/")),
             'for-tag-unpack13': ("{% for x,y,z in items %}{{ x }}:{{ y }},{{ z }}/{% endfor %}", {"items": (('one', 1, 'carrot'), ('two', 2, 'cheese'))}, ("one:1,carrot/two:2,cheese/", "one:1,carrot/two:2,cheese/")),
 
+
+            ### NUMERICAL FOR TAG #####################################################
+            'numfor-tag01': ("{% for i 1 to 5 %}{{ i }}{% endfor %}", {}, "12345"),
+            'numfor-tag02': ("{% for i 1 to 5 exclusive %}{{ i }}{% endfor %}", {}, u"1234"),
+            'numfor-tag03': ("{% for i 1 to 5 by 2 %}{{ i }}{% endfor %}", {}, "135"),
+            'numfor-tag04': ("{% for i 1 to 5 by 2 exclusive %}{{ i }}{% endfor %}", {}, "13"),
+
+            'numfor-tag05': ("{% for i 5 to 1 by -1 %}{{ i }}{% endfor %}", {}, "54321"),
+            'numfor-tag06': ("{% for i 5 to 1 by -1 exclusive %}{{ i }}{% endfor %}", {}, "5432"),
+            'numfor-tag07': ("{% for i 5 to 1 by -2 %}{{ i }}{% endfor %}", {}, "531"),
+            'numfor-tag08': ("{% for i 5 to 1 by -2 exclusive %}{{ i }}{% endfor %}", {}, "53"),
+
+            'numfor-tag09': ("{% for i 1 to 5 by -1 %}{{ i }}{% endfor %}", {}, ""),
+            'numfor-tag10': ("{% for i 5 to 1 by 1 %}{{ i }}{% endfor %}", {}, ""),
+
+            'numfor-tag11': ("{% for i x to y by z %}{{ i }}{% endfor %}", {'x': 1, 'y': 5, 'z': 1}, "12345"),
+
             ### IF TAG ################################################################
             'if-tag01': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": True}, "yes"),
             'if-tag02': ("{% if foo %}yes{% else %}no{% endif %}", {"foo": False}, "no"),
