Paginator TemplateTag

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
from django import template
from django.db.models.query import QuerySet
from django.core.paginator import Paginator, QuerySetPaginator

register = template.Library()

class PaginateNode(template.Node):
    def __init__(self, objlist_name, nr_pages, var_name="page", param_name="page"):
        self.objlist_name = objlist_name
        self.nr_pages = nr_pages
        self.var_name = var_name
        self.param_name = param_name
    
    def render(self, context):
        try:
    	    list_or_queryset = context[self.objlist_name]
        except KeyError:
            return ''
        
    	if isinstance(list_or_queryset, QuerySet):
    	    paginator = QuerySetPaginator(list_or_queryset, self.nr_pages)
    	else:
    	    paginator = Paginator(list_or_queryset, self.nr_pages)
	
    	try:
    	    page = int(context['request'].REQUEST.get(self.param_name, 1))
    	except:
    	    page = 1

    	context[self.var_name] = paginator.page(page)
        context[self.var_name+"_set"] = paginator
        # backward compatibility injections into the context
    	context[self.var_name+"_count"] = paginator.count
    	context[self.var_name+"_num_pages"] = paginator.num_pages
    	context[self.var_name+"_page_range"] = paginator.page_range
    	return ''

def paginate(parser, token):
    try:
        tag_name, arg = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError, "%r tag requires arguments" % token.contents.split()[0]
    args = arg.split(None)
    var_name = "page"
    param_name = "page"
    try:
        objlist_name = args[0]
        nr_pages = args[1]
    except:
        raise template.TemplateSyntaxError, "%r tag invalid arguments" % token.contents.split()[0]
    if len(args)==2:
        pass
    elif len(args)==4 and args[2]=="as":
        var_name = args[3]
    elif len(args)==6 and args[4]=="using":
        var_name = args[3]
        param_name = args[5]
    else:
        raise template.TemplateSyntaxError, "%r tag invalid arguments" % token.contents.split()[0]
    try:
        nr_pages = int(nr_pages)
    except:
        raise template.TemplateSyntaxError, "%r tag invalid arguments" % token.contents.split()[0]
    return PaginateNode(objlist_name, nr_pages, var_name, param_name)
paginate = register.tag(paginate)

More like this

  1. Add querystring parameters to path (template tag) by spenoir 1 year, 2 months ago
  2. Pagination Alphabetically compatible with paginator_class by vascop 1 year, 12 months ago
  3. Generic CSV Export by zbyte64 5 years, 10 months ago
  4. Tags & filters for rendering search results by exogen 6 years ago
  5. load m2m fields objects by dirol 3 years, 10 months ago

Comments

wam (on April 16, 2008):

It probably merits mentioning that this tag depends on 'django.core.context_processors.request' being added to settings.TEMPLATE_CONTEXT_PROCESSORS, as this is a non-default configuration.

#

trbs (on April 19, 2008):

Thanks wam, text has been updated.

I've also added a new variable in the context called "page_set" or otherwise var_name+"_set" which contains the paginator object.

However since the paginator object does not implement __len__ and alikes so you cannot use {{ page_set|count }} instead you need the call the method {{ page_set.count }} or for example with the humanize contrib {{ page_set.count|apnumber }} .

The old names are still there for backwards compatibility. (But might be removed in the future as it clutters the context)

#

jaaay (on April 28, 2008):

I can't seem to get past a KeyError at the line:

list_or_queryset = context[self.objlist_name]

Which I would guess means I'm not passing the request object properly, but I do have django.core.context_processors.request added to settings.py. Is there something else that needs to be considered?

For what it's worth, Here's what I'm doing in the template: {% paginate category.product_set.active 10 %}

#

trbs (on June 1, 2008):

The snippet should be updated to lookup the variable with the template tags resolve_variable api.

Currently it requires you to put the list_or_queryset directly into the template context.

Since the other paginator tag seems to be far far more popular then mine, i will not spend much more time on this. If anyone wants to make a patch (and remind me of it, cause djangosnippets doesn't send mails) I'll happily apply it and update the snippet.

#

schraal (on July 10, 2008):

there's a bug in the template example code. the 'for' is closed by an 'endif'.

thanks for the snippet, I found it very usefull indeed for my usecase. hope you feel encouraged to keep maintaining the snippet.

#

trbs (on August 24, 2008):

thnx schraal, updated the example code. i'll hope to update the tag for 1.0 once it is released.

#

(Forgotten your password?)