4

I'm using django-pagination to paginate my pages. It works great, but I would like to set up

<link rel="prev" href="http://www.example.com/foo/?page=1" />
<link rel="next" href="http://www.example.com/foo/?page=3" />

to the <head>, like it is recommended by google .

However I found no way ho to do this (without extra queries at least). First I tried to edit the pagination/templates/pagination.html with something like this

{% block extra_head %}
<link rel=... ... />
{% endblock %}

Which of course did not work (pagination.html is included by the {% paginate %} tag, it does not extend my layout.html). Next, I tried to modify my template for /foo/ view to something like this (adding the {% block extra_head %}):

{# foo.html #}
{% extends "layout.html" %}

{% block content %}

{% load pagination_tags %}
{% autopaginate object_list %}
{% paginate %}
{% for obj in object_list %}
  {{ obj }}
{% endfor %}
{% paginate %}

{% endblock %}

{% block extra_head %}
<link rel="prev" href="?page={{ page_obj.previous_page_number }}"/>
{% endblock %}

But this won't work either, as the page_obj variable is only available in scope of {% block content %}. A could call

{% autopaginate object_list %}

in the extra_head block, but that will mean an extra hit to the db (and possibly other side effects that I'm not aware of). Is there an elegant way to solve this, ideally as DRY as possible?

Edit: I'm using django 1.2.

Ondrej Skalicka
  • 3,046
  • 9
  • 32
  • 53

2 Answers2

2

You can do {% autopaginate %} in higher-level block, then paginated objects will be available in sub-blocks. If you don't have higher level block it is possible to do this in base template:

{% block root %}
...
{% endblock %}

And in extended template:

{% extends "base.html" %}
{% load pagination_tags %}

{% block root %}
    {% autopaginate objects 10 %}
    {{ block.super }}
{% endblock %}

<!-- the rest of your code -->

Now, to get a different rendering of paginator in head, you can make use of the with tag:

{% with we_are_in_head=1 %}
    {% paginate %}
{% endwith %}

And override templates/pagination/pagination.html with something like this:

{% if we_are_in_head %}
    # Your links to next and prev only
{% else %}
    # original code
{% endif %}

A moral

This is not elegant and the reason is that pagination should be implemented in the view. Templates are for rendering only, template-tags too. Pagination makes extra sql queries, it also parses arguments from request, template is totally wrong place for this code, so workarounds has to be invented. These workarounds might break on next release of django, they are also subtle and can be accidentally broken by other developer.

Ski
  • 14,197
  • 3
  • 54
  • 64
  • I've tried this, but when I move the {% autopaginate my_list %} out of all blocks, eg. it is directly after {% extends %} and {% load pagination_tags %}, the pagination fails (all items are rendered, no pagination is made). – Ondrej Skalicka Nov 15 '11 at 16:40
  • Maybe django-pagination has been updated since last time I've used it so this method no longer work... – Ski Nov 15 '11 at 21:37
  • Is it possible that this is due to the django version I use? (1.2) I'm not that skilled in Django to be able to easily read the source code and say where the problem lies. – Ondrej Skalicka Nov 16 '11 at 06:54
  • 1
    Sorry, actually `autopaginate` had never worked the way I've described. You only can use it in higher-level block, but it won't work in non-block. I've updated my answer. But please also conciser my moral at the end of answer and do the right thing if you have time for that. – Ski Nov 16 '11 at 12:47
  • 1
    I agree with your moral note that this starts to look a bit more a `view`'s job. However django-pagination does not allow any other approach. What would you recommend instead of it? In my views I use some filters to narrow down the result set, then I want to display it in template, paginated. I'd like to work with as litte code as possible as it will be used in several views. – Ondrej Skalicka Nov 16 '11 at 14:01
  • I think that https://docs.djangoproject.com/en/dev/topics/pagination is easy enough to use. I would recommend to simply create helper-function to automate paginator initialization. In templates use `include` to display page numbers. Keep it simple. – Ski Nov 16 '11 at 14:22
  • Okay, tried it and this looks like the good solution. Thanks :) – Ondrej Skalicka Nov 17 '11 at 16:03
0

We can call autopaginate in a view and then use {% paginate %} as usual. Here is a recipe if somebody still face the described problem:

from pagination.templatetags.pagination_tags import AutoPaginateNode

def autopaginate(request, context, queryset_var, paginate_by):
    """ It allows us to use paginated objects in different template blocks """
    autopagination = AutoPaginateNode(queryset_var, paginate_by)
    # Inject a request - it's required by `autopagination` function
    context['request'] = request
    autopagination.render(context)
potar
  • 468
  • 6
  • 6