Question

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.

Était-ce utile?

La solution

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.

Autres conseils

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)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top