Index: django/template/defaulttags.py
===================================================================
--- django/template/defaulttags.py	(revision 4229)
+++ django/template/defaulttags.py	(working copy)
@@ -3,6 +3,7 @@
 from django.template import Node, NodeList, Template, Context, resolve_variable
 from django.template import TemplateSyntaxError, VariableDoesNotExist, BLOCK_TAG_START, BLOCK_TAG_END, VARIABLE_TAG_START, VARIABLE_TAG_END, SINGLE_BRACE_START, SINGLE_BRACE_END, COMMENT_TAG_START, COMMENT_TAG_END
 from django.template import get_library, Library, InvalidTemplateLibrary
+from django.template.loader import get_template
 from django.conf import settings
 import sys
 
@@ -222,6 +223,58 @@
         and_ = 0,
         or_ = 1
 
+class PageListNode(Node):
+    def __init__(self, surround=0, firstlast=False, urlprefix='?page=', template='pagelists/default.html'):
+        self.surround = surround
+        self.firstlast = firstlast
+        self.urlsuffix = "/"
+        if urlprefix.startswith('?'):
+            self.urlprefix = urlprefix
+            self.urlsuffix = ""
+        elif urlprefix.startswith('/'):
+            self.urlprefix = urlprefix
+        else:
+            self.urlprefix = '../'+urlprefix
+        self.template_name = template
+
+    def render(self, context):
+        if self.surround:
+            surround_start = context['page'] - self.surround
+            surround_end = context['page'] + self.surround
+            if self.firstlast and surround_start <= 1:
+                surround_start = 2
+            elif surround_start < 1:
+                surround_start = 1
+            if self.firstlast and surround_end >= context['pages']:
+                surround_end = context['pages'] - 1
+            elif surround_end > context['pages']:
+                surround_end = context['pages']
+            page_list = range(surround_start, surround_end+1)
+        else:
+            if self.firstlast:
+                page_list = range(2, context['pages'])
+            else:
+                page_list = range(1, context['pages'] + 1)
+        page_index = []
+        for page in page_list:
+            page_index.append({'number': page, 'link': self.urlprefix+str(page)+self.urlsuffix})
+        tmpl_context = Context()
+        tmpl_context.update(context)
+        tmpl_context['page_index'] = page_index
+        tmpl_context['firstlast'] = self.firstlast
+        if self.firstlast:
+            tmpl_context['first_link'] = self.urlprefix+"1"+self.urlsuffix
+            tmpl_context['last_link'] = self.urlprefix+str(context['pages'])+self.urlsuffix
+
+        try:
+            t = get_template(self.template_name)
+            return t.render(tmpl_context)
+        except:
+            if settings.TEMPLATE_DEBUG:
+                raise
+            else:
+                return ''
+        
 class RegroupNode(Node):
     def __init__(self, target, expression, var_name):
         self.target, self.expression = target, expression
@@ -675,6 +728,103 @@
 ifchanged = register.tag(ifchanged)
 
 #@register.tag
+def pagelist(parser, token):
+    """
+    Lists an index of pages.
+
+    This tag uses a template to display an index of pages. It requires ``page``
+    and ``pages`` to be in the context where it is used. These variable will
+    already be in the context if you are using the ``object_list`` generic
+    view. It can be used like this::
+
+        {% pagelist %}
+
+    If it is it will output a list of all the pages with links. If you only
+    want a certain number of pages surrounding the current page on the list
+    then you can use ``surround`` followed by a number. For example::
+
+        {% pagelist surround 3 %}
+
+    If you want the first and last pages to be displayed as well then you can
+    use ``firstlast``. For example::
+
+        {% pagelist surround 3 firstlast true %}
+
+    By default, pagelists assume that pages are specified by the GET variable
+    page. So any links it creates look like "?page=1". You can override this
+    and specify either absolute urls like "/stuff/list/page" or relative urls
+    like "page". These are specified using ``urlprefix``. For example::
+
+        {% pagelist urlprefix /stuff/list/page %}
+
+    Another example::
+
+        {% pagelist urlprefix page %}
+
+    These would use create links that look like "/stuff/list/page1/" and "../page1/"
+    respectively.
+
+    By default, pagelists are rendered via the template
+    ``pagelists/default.html``, but you can override that for a particular
+    pagelist using ``template``. For example::
+
+        {% pagelist template pagelists/mypagelist.html %}
+
+    Creating the ``pagelists/default.html`` template is your responsibility; in
+    your template directory, just create a ``pagelists`` directory containing a
+    file ``default.html``.
+
+    Pagelist templates are passed two context variables in addition to all
+    all context variables in the template the pagelist tag was used in.
+
+        * ``firstlast``: Whether to display the first and last pages.
+
+        * ``page_index``: A list of pages. Each page has two attributes: ``number``,
+        the page number and ``link``: the link to the page based on
+        ``urlprefix``.
+
+    If ``firstlast`` is true two more context variables are passed in.
+
+        * ``first_link``: A link to the first page based on ``urlprefix``.
+
+        * ``last_link``: A link to the last page based on ``urlprefix``.
+
+    Here's a sample ``pagelists/default.html`` template::
+
+        <ul class="pagelist">
+            {% if firstlast %}<li><a href="{{ first_link }}" title="First">&lt;&lt; First</a></li>{% endif %}
+            {% for other_page in page_index %}
+                <ol
+                    {% ifequal other_page.number previous %}class="previous"{% endifequal %}
+                    {% ifequal other_page.number page %}class="current"{% endifequal %}
+                    {% ifequal other_page.number next %}class="next"{% endifequal %}
+                >
+                    <a href="{{ other_page.link }}" title="Page {{ other_page.number }}">
+                        {{ other_page.number }}
+                    </a>
+                </ol>
+            {% endfor %}
+            {% if firstlast %}<li><a href="{{ last_link }}" title="Last">Last &gt;&gt;</a></li>{% endif %}
+        </ul>
+    """
+    bits = token.contents.split()
+    kwargs = {}
+    is_key = True
+    for bit in bits[1:]:
+        if is_key:
+            key = bit
+        else:
+            if key == 'surround':
+                bit = int(bit)
+            elif key == 'firstlast':
+                bit = bit.lower() == 'true'
+            kwargs[key] = bit
+        is_key = not is_key
+    return PageListNode(**kwargs)
+
+pagelist = register.tag(pagelist)
+
+#@register.tag
 def ssi(parser, token):
     """
     Output the contents of a given file into the page.
Index: docs/templates.txt
===================================================================
--- docs/templates.txt	(revision 4229)
+++ docs/templates.txt	(working copy)
@@ -699,6 +699,86 @@
 
 (Displays "It is the 4th of September" %}
 
+pagelist
+~~~~~~~~
+
+Lists an index of pages.
+
+This tag uses a template to display an index of pages. It requires ``page``
+and ``pages`` to be in the context where it is used. These variable will
+already be in the context if you are using the ``object_list`` generic
+view. It can be used like this::
+
+    {% pagelist %}
+
+If it is it will output a list of all the pages with links. If you only
+want a certain number of pages surrounding the current page on the list
+then you can use ``surround`` followed by a number. For example::
+
+    {% pagelist surround 3 %}
+
+If you want the first and last pages to be displayed as well then you can
+use ``firstlast``. For example::
+
+    {% pagelist surround 3 firstlast true %}
+
+By default, pagelists assume that pages are specified by the GET variable
+page. So any links it creates look like "?page=1". You can override this
+and specify either absolute urls like "/stuff/list/page" or relative urls
+like "page". These are specified using ``urlprefix``. For example::
+
+    {% pagelist urlprefix /stuff/list/page %}
+
+Another example::
+
+    {% pagelist urlprefix page %}
+
+These would use create links that look like "/stuff/list/page1/" and "../page1/"
+respectively.
+
+By default, pagelists are rendered via the template
+``pagelists/default.html``, but you can override that for a particular
+pagelist using ``template``. For example::
+
+    {% pagelist template pagelists/mypagelist.html %}
+
+Creating the ``pagelists/default.html`` template is your responsibility; in
+your template directory, just create a ``pagelists`` directory containing a
+file ``default.html``.
+
+Pagelist templates are passed two context variables in addition to all
+all context variables in the template the pagelist tag was used in.
+
+    * ``firstlast``: Whether to display the first and last pages.
+
+    * ``page_index``: A list of pages. Each page has two attributes: ``number``,
+      the page number and ``link``: the link to the page based on
+      ``urlprefix``.
+
+If ``firstlast`` is true two more context variables are passed in.
+
+    * ``first_link``: A link to the first page based on ``urlprefix``.
+
+    * ``last_link``: A link to the last page based on ``urlprefix``.
+
+Here's a sample ``pagelists/default.html`` template::
+
+    <ul class="pagelist">
+        {% if firstlast %}<li><a href="{{ first_link }}" title="First">&lt;&lt; First</a></li>{% endif %}
+        {% for other_page in page_index %}
+            <ol
+                {% ifequal other_page.number previous %}class="previous"{% endifequal %}
+                {% ifequal other_page.number page %}class="current"{% endifequal %}
+                {% ifequal other_page.number next %}class="next"{% endifequal %}
+            >
+                <a href="{{ other_page.link }}" title="Page {{ other_page.number }}">
+                    {{ other_page.number }}
+                </a>
+            </ol>
+        {% endfor %}
+        {% if firstlast %}<li><a href="{{ last_link }}" title="Last">Last &gt;&gt;</a></li>{% endif %}
+    </ul>
+
 regroup
 ~~~~~~~
 
