Django Aware

« | Home | »

Digg Style Pagination In Django Revisited

By Paul Kenjora | March 19, 2009

Months ago I wrote a Auto Adjusting Pagination As A Template Tag Plus Include post about a template tag that can paginate any result set on the fly producing a Digg style page widget. What is a Digg style page widget? Its pagination that breaks the list of pages into three dynamic groups. Left, middle, and right set of pages. For example…

Digg Style Pagination In Django

This image was Google Image borrowed from Ryan Kanno

The advantage of this pagination implementation is that it only requires one template tag and one line of template code to work. No messy URLs to configure and no need to recode any of your existing parameters except adding a ?page=X for the current page.

The source download contains everything you need to implement this in about 5 minutes. Once you unpack the download, you will see:

For those of you wondering how this works, on the left is probably close to the template you have today, it shows a simple list of objects you pulled from the database using a query. On the right is the same template with pagination added. This is how you modify the code you have to use this:

Original Template

{% for item in items %}
{{ item.title }}
{% endfor %}

Paginated Template

{% load pagination_tag %}
{% paginate "/items/" items current_page 50 10 paged_items %}
{% include "pagination.html" %}
{% for item in paged_items %}
{{ item.title }}
{% endfor %}

The source download. Full Code Here!

This code has been taken up by MeoCode, see an updated and more detailed version here. Thanks MeoCode, enjoy!

Topics: Template Tags | Comments

  • Thanks for sharing your work, here are fixes of the code:
    1) Code as-is will not run with Apache/WSGI, because wsgi does not allow writing to stdout. To fix this, remove 'print' statements in code.
    2) If you add:
    view = template.resolve_variable(self.view, context)
    to PaginationNode.render(), you will be able to pass 'current_url' as context-variable also, similary to page index
    3. As meppum posted, using alternative template/css is very good idea
  • You can see final result of pagination with alternative CSS here:
    http://www.gamejumble.com/category/action/
  • john
    gamejumble

    Wow, I love the result.

    I'd love to use this but can't figure out how to get it working. Could you post a complete example, eg view, url, template + any thing else necessary.

    Thanks
  • Ook, it's here:
    http://www.meowcode.com/django/digg-style-pagin...
    I tried to make it step-by-step, let me know how does it works for you in comments there.
  • Glad to hear you like it, I'll publish it in next few days and link back here..
  • corsairmoran
    Please post a sample urls.py and views.py
  • rollenc
    Greate script

    Thanks
  • frustrateduser
    For anyone wanting to do pagination and sorting I suggest using:

    http://code.google.com/p/django-pagination/
    and
    http://code.google.com/p/django-sorting/

    DO NOT WASTE YOUR TIME trying to understand this templatetag.
    It might actually work well, but with practically no documentation and no complete examples you're bound to loose a lot of your valuable time.
  • Wow a bit harsh on the delivery but I'm not opposed to pointing users at something better.

    I looked over the other code and it looks good. Go for it... sorry my startup has taken time away from my ability to maintain this code, a year is a good run though.

    PS: The frustrated user above doesn't sound like he/she even tried the code before passing judgment. I hope I'm wrong.
  • The thing I like most with that kind of design is when you can just type in the page number and it takes you there. If you need to click 20 times to get from page 1 to page 70 it's just too much trouble and often not worth it.
  • I prefer this pagination over the alternatives.

    I posted a modified version of the pagination.html that can be used with any of the css files from here: http://mis-algoritmos.com/2007/03/16/some-style...

    You can find the modified version of pagination.html here: http://meppum.com/media/blog_media/pagination.html
  • Usually if you post the specific problem in the comments you'll get one of the awesome readers to drop by with an answer.
  • Brilliant! Works a treat.

    I'm trying to get the pagination widget to display in one template block and the page data to display in another template block.

    Is there a way to share the "variable" of paged data across two blocks easily or do I need to create some sort of global in the paginaton tag and pass that across to the context of the other block?

    Great work.
  • UnhappyJoe
    I gotta say, you fail at documentation.

    After an hour or two of slamming my head into my desk, I finally realised that the idea of this is to have the paginator do all the paging for you [including the ORM calls]. Then I realised your /strict/url/s are not actually suitable for my paged search page and I'm going to have to modify it anyway.

    Would have been so much easier for you to explain how it works, than it was for me to spend time discovering it's not what I'm looking for.
  • Sorry to hear that, guess I can't please everyone all of the time. You may want to double check the code, it supports dynamic URLs.

    {% paginate "[dynamic URL here]" items current_page 50 10 paged_items %}

    If you're asking for variable defined URLs then I suggest adding a resolve context variable call around the URL variable. Next release i guess.... hopefully your head will feel better by then.

    <img src="http://i35.tinypic.com/2u78t3d.jpg" border="0">


    PS: Note I didn't ask, "Why would you need dynamic pagination URLs..."
  • UnhappyJoe
    I apologise for my previous comment... but you DO need some documentation he he. For somebody who has only recently picked up Django, your code made very little sense to me to begin with :)

    I am trying to use your pagination code on a search page.. so I need this sort of thing -

    site/search/?s=bla&show=all&threshold=2days&page=3

    Is this possible using "a resolve context variable call" (don't know what that is) ?
  • Try changing your URL to the following:

    {% paginate "site/search/bla/all/2days/" items current_page 50 10 paged_items %}

    The current page you will still have to carry around in the context. Pete's comment below is addressing this I think.

    Not sure how much experience you've had passing parameters via URL but its a very powerful tool in Django.
  • UnhappyJoe
    While I accept that you are not obligated to do any of this for free, and that your code is very good, I can't help but feel like you're passing the buck when you tell me I should change my URLs. One of the main selling points of django is its extensibility, and I think it would be fitting for you to make changes to your script so that it can be used in a wider range of situations, rather than just the situations which suit you.

    I have eliminated querystrings from my application where possible, but when it comes to searching I would actually prefer a query string.

    You suggested changing my URL to:

    {% paginate "site/search/bla/all/2days/" items current_page 50 10 paged_items %}

    But how exactly is that going to work? How is "site/search/bla/all/2days/" going to insert the parameters specified by the user doing the search? ie..

    site/pictures of cats and dogs/bla/videos-only/2weeks

    ............

    There absolutely must be a simple way to modify your script to support any kind of url, and I guess I am forced to find it myself and modify your script. I shall post the results here when I get around to it.

    All that aside, thanks for your effort. I'm in a better position with your code than I would be without it, so for that I am grateful.
  • If you want to use this script you need to remember to put a scrolldown list with all the pages too. I'm sick and tired of going for example from page 200 to 400 and having to reload the site like 50 times because it only moves 4 pages at the time.
  • bob
    Could you please provide some documentation how to use this? - Where does pagination_tag.py go? - What do I put in views.py?

    Maybe something like the standard pagination method documentation but how to use this digg style pagination: http://docs.djangoproject.com/en/dev/topics/pag...
  • Bob,

    You don't put anything in views. The source download has everything you need, including an example.

    This implementation is significantly different than the standard one in that it does not deal with views.py. Just take the query you currently have coming back from views.py and stick it in the tag call in your template.

    The only parameter you should be passing through views.py is the current page (integer).
  • guest
    Could you post an example of how you pass current_page to views.py?

    Thank you.
  • john
    I'd also like to see an example, surprising there isn't one in the first place.

    "No messy URLs to configure" how do you pass the page no without configuring the url?
  • Yehat
    Paul,

    If you want to help people, as I'm sure you do... more detailed documentation is required... especially for newbie Django peeps.
  • Yehat,

    I've updated the post with more details. Hope it helps. What were you having trouble with? Usually if you post the specific problem in the comments you'll get one of the awesome readers to drop by with an answer.

    - Paul
  • Yehat
    Paul,

    Thanks for the update...

    I found that by putting href="?page={{ page }}" in the pagination.html file instead of
    href="/{{ pagination.view }}/{{ page }}/" you omit the need to include the url path as an argument... this is especially helpful if you are looking at, say, a list of Y's that are related to the Nth X object. This way the dynamic path (e.g. path/XN) can be omitted. It would otherwise have to be passed into the template by the view.

    What were the reasons you chose to the convention urlpath/p/ over the convention ?page=p ?

    I'm a Django newbie ;p
  • One of the main reasons to use urlpath/p/ over ?page=p is caching. The built in django cache only caches by the part of the url that comes before the parameters. So it would consider www.foo.com/?page=1 the same as www.foo.com/?page=2.
  • Another great script!
    Thanks for sharing.
blog comments powered by Disqus