Twitter-style Pagination

Assuming the developer wants Twitter-style pagination of entries of a blog post, in views.py we have class-based:

from el_pagination.views import AjaxListView

class EntryListView(AjaxListView):
    context_object_name = "entry_list"
    template_name = "myapp/entry_list.html"

    def get_queryset(self):
        return Entry.objects.all()

or fuction-based:

def entry_index(request, template='myapp/entry_list.html'):
    context = {
        'entry_list': Entry.objects.all(),
    }
    return render(request, template, context)

In myapp/entry_list.html:

<h2>Entries:</h2>
{% for entry in entry_list %}
    {# your code to show the entry #}
{% endfor %}

Split the template

The response to an Ajax request should not return the entire template, but only the portion of the page to be updated or added. So it is convenient to extract from the template the part containing the entries, and use it to render the context if the request is Ajax. The main template will include the extracted part, so it is convenient to put the page template name in the context.

views.py class-based becomes:

from el_pagination.views import AjaxListView

class EntryListView(AjaxListView)
    context_object_name = "entry_list"
    template_name = "myapp/entry_list.html"
    page_template='myapp/entry_list_page.html'

    def get_queryset(self):
        return Entry.objects.all()

or fuction-based:

def entry_list(request,
    template='myapp/entry_list.html',
    page_template='myapp/entry_list_page.html'):
    context = {
        'entry_list': Entry.objects.all(),
        'page_template': page_template,
    }
    if request.is_ajax():
        template = page_template
    return render(request, template, context)

See below how to obtain the same result just decorating the view.

myapp/entry_list.html becomes:

<h2>Entries:</h2>
{% include page_template %}

myapp/entry_list_page.html becomes:

{% for entry in entry_list %}
    {# your code to show the entry #}
{% endfor %}

A shortcut for ajaxed views

A good practice in writing views is to allow other developers to inject the template name and extra data, so that they are added to the context. This allows the view to be easily reused. Let’s resume the original view with extra context injection:

views.py:

def entry_index(request,
        template='myapp/entry_list.html', extra_context=None):
    context = {
        'entry_list': Entry.objects.all(),
    }
    if extra_context is not None:
        context.update(extra_context)
    return render(request, template, context)

Splitting templates and putting the Ajax template name in the context is easily achievable by using an included decorator.

views.py becomes:

from el_pagination.decorators import page_template

@page_template('myapp/entry_list_page.html')  # just add this decorator
def entry_list(request,
        template='myapp/entry_list.html', extra_context=None):
    context = {
        'entry_list': Entry.objects.all(),
    }
    if extra_context is not None:
        context.update(extra_context)
    return render(request, template, context)

Paginating objects

All that’s left is changing the page template and loading the endless templatetags, the jQuery library and the jQuery plugin el-pagination.js included in the distribution under /static/el-pagination/js/.

myapp/entry_list.html becomes:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>$.endlessPaginate();</script>
{% endblock %}

myapp/entry_list_page.html becomes:

{% load el_pagination_tags %}

{% paginate entry_list %}
{% for entry in entry_list %}
    {# your code to show the entry #}
{% endfor %}
{% show_more %}

The paginate template tag takes care of customizing the given queryset and the current template context. In the context of a Twitter-style pagination the paginate tag is often replaced by the lazy_paginate one, which offers, more or less, the same functionalities and allows for reducing database access: see Lazy pagination.

The show_more one displays the link to navigate to the next page.

You might want to glance at the JavaScript reference for a detailed explanation of how to integrate JavaScript and Ajax features in Django Endless Pagination.

Pagination on scroll

If you want new items to load when the user scroll down the browser page, you can use the pagination on scroll feature: just set the paginateOnScroll option of $.endlessPaginate() to true, e.g.:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>$.endlessPaginate({paginateOnScroll: true});</script>
{% endblock %}

That’s all. See the Templatetags reference to improve the use of included templatetags.

It is possible to set the bottom margin used for pagination on scroll (default is 1 pixel). For example, if you want the pagination on scroll to be activated when 20 pixels remain to the end of the page:

<h2>Entries:</h2>
{% include page_template %}

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $.endlessPaginate({
            paginateOnScroll: true,
            paginateOnScrollMargin: 20
        });
    </script>
{% endblock %}

Again, see the JavaScript reference.

On scroll pagination using chunks

Sometimes, when using on scroll pagination, you may want to still display the show more link after each N pages. In Django Endless Pagination this is called chunk size. For instance, a chunk size of 5 means that a show more link is displayed after page 5 is loaded, then after page 10, then after page 15 and so on. Activating chunks is straightforward, just use the paginateOnScrollChunkSize option:

{% block js %}
    {{ block.super }}
    <script src="http://code.jquery.com/jquery-latest.js"></script>
    <script src="{{ STATIC_URL }}el-pagination/js/el-pagination.js"></script>
    <script>
        $.endlessPaginate({
            paginateOnScroll: true,
            paginateOnScrollChunkSize: 5
        });
    </script>
{% endblock %}

Before version 2.0

Django Endless Pagination v2.0 introduces a redesigned Ajax support for pagination. As seen above, Ajax can now be enabled using a brand new jQuery plugin that can be found in static/el-pagination/js/el-pagination.js.

For backward compatibility, the application still includes the two JavaScript files el-pagination-endless.js and el-pagination_on_scroll.js that were used before, so that it is still possible to use code like this:

<script src="http://code.jquery.com/jquery-latest.js"></script>
{# Deprecated. #}
<script src="{{ STATIC_URL }}el-pagination/js/el-pagination-endless.js"></script>

To enable pagination on scroll, the code was the following:

<script src="http://code.jquery.com/jquery-latest.js"></script>
{# Deprecated. #}
<script src="{{ STATIC_URL }}el-pagination/js/el-pagination-endless.js"></script>
<script src="{{ STATIC_URL }}el-pagination/js/el-pagination_on_scroll.js"></script>

However, please consider migrating as soon as possible: the old JavaScript files are deprecated, are no longer maintained, and don’t provide the new JavaScript features. Also note that the old Javascript files will not work if jQuery >= 1.9 is used.

Please refer to the JavaScript reference for a detailed overview of the new features and for instructions on how to migrate from the old JavaScript files to the new one.