Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to append pages of data using jQuery and Django pagination?

I am using Django's inbuilt pagination to paginate the data and displaying in the template. I now would like to implement jQuery to load and append pages to the template using ajax. How do I do it using jQuery?

I was using django-endless-pagination before, but since it adds the entries by JavaScript my lightbox to display images does not catch the image elements and only displays the entry which was loaded at first request.

views.py:

def snaps(request):
    snapgroup_list = SnapGroup.objects.all()
    paginator = Paginator(snapgroup_list, 1)

    try:
        page = int(request.GET.get('page', '1'))
    except:
        page = 1
    try:
        snapgroup = paginator.page(page)
    except(EmptyPage, InvalidPage):
        snapgroup = paginator.page(page)

    index = snapgroup.number - 1  # edited to something easier without index
    max_index = len(paginator.page_range)
    start_index = index - 3 if index >= 3 else 0
    end_index = index + 3 if index <= max_index - 3 else max_index
    page_range = paginator.page_range[start_index:end_index]

    return render(request, 'snaps.html', {
        'page_range': page_range,
        'snapgroup':snapgroup
        })

snaps.html:

{% extends "base.html" %}
{% block main_content %}

<div id="main_content">
    <div id="snap_wrapper" class="container">
        <hr>
        {% if snapgroup.object_list.count > 0 %} 
            {% include 'snapgroups.html' %}
        {% else %}
            <li><p>No SNAPS yet!</p></li>
            <span class="clear_both"></span>
        {% endif %}
    </div>

</div>
<div class="container">
    <div class="prev_next">
        {% if snapgroup.has_previous %}
          <a class="prev btn btn-info" href="?page={{snapgroup.previous_page_number}}">Prev</a>
        {% endif %}
        {% if snapgroup.has_next %}
          <a class="next btn btn-info" href="?page={{snapgroup.next_page_number}}">Next</a>
        {% endif %}
        <div class="pages">
          <ul>
          {% for pg in page_range %}
            {% if snapgroup.number == pg %}
              <li><a href="?page={{pg}}" class="btn btn-default">{{pg}}</a></li>
            {% else %}
              <li><a href="?page={{pg}}" class="btn">{{pg}}</a></li>
            {% endif %}
          {% endfor %}
          </ul>
        </div>
        <span class="clear_both"></span>
    </div>  
</div>

{% endblock %}

snapgroups.html:

{% for sg in snapgroup.object_list %}
    <h4 id="combination" class="snap_date">{{sg.date|date:'l'}}, {{sg.date}}</h4>
    <ul>
    {% for snap in sg.snap_set.all %}
        <li><a href="{{MEDIA_URL}}{{snap.image}}" data-imagelightbox="f"><img src="{{MEDIA_URL}}{{snap.image}}" alt="{{snap.caption}}" /></a></li>
    {% endfor %}
        <span class="clear_both"></span>
    </ul>
{% endfor %}
like image 630
Robin Avatar asked Jun 18 '15 14:06

Robin


People also ask

How does Django deal with pagination?

Note that you can give Paginator a list/tuple, a Django QuerySet , or any other object with a count() or __len__() method. When determining the number of objects contained in the passed object, Paginator will first try calling count() , then fallback to using len() if the passed object has no count() method.

What is Paginator in Django?

Django provides a few classes that help you manage paginated data – that is, data that's split across several pages, with “Previous/Next” links. These classes live in django/core/paginator.py. For examples, see the Pagination topic guide.

What is Python pagination?

What is pagination? This module helps dividing large lists of items into pages. The user is shown one page at a time and can navigate to other pages. Imagine you are offering a company phonebook and let the user search the entries.


1 Answers

I'd show you with an example app. Since you're just learning, this will be helpful if you actually make one such app with the code below.

I've tried to keep the code as minimum as I could.

models.py

class Article(...):
    title = models.CharField(...)
    photo = models.ImageField(...)

views.py

import json

def article_ajax(request):
    TOTAL = 10
    OFFSET = request.GET.get('offset', 0)
    END = offset + TOTAL
    # TOTAL means how many articles to load
    # in a single request

    # to understand OFFSET and END, consider this:
    # mylist = [1,2,3,4,5,6,7,8,9]
    # mylist[2:5] outputs => [3,4,5]
    # Above 2 is OFFSET and 5 is END

    articles = Article.objects.all()[OFFSET:END]

    json_list = []
    for article in articles:
        json_list.append({
            'title': article.title, 'photo_url': article.photo.url
        })

    data = json.dumps(json_list)

    return HttpResponse(data, content_type='application/json')

urls.py

...
url(r'^ajax/articles/$', 'myapp.views.article_ajax'),
...

articles.html

The script also contains infinite scrolling code, too :)

<!-- All articles will be loaded in following div -->
<div id="ArticlesDiv"></div>

<script>
var articleOffset = 0;

var articleLoader = function() {
    $.ajax({
        url: '/ajax/articles/?offset=' + articleOffset,
        success: function(data) {
            if (data.length > 0) {
                for (var i = 0, total = data.length; i < total; i++) {
                    var compile_data;
                    compile_data = '<h1>' + data[i].title + '</h1>\
                        <img src="' + data[i]photo_url + '">';

                    $('#ArticlesDiv').append(compile_data);
                }

                /* update the offset */
                articleOffset += 10
            } else {
                $('#ArticlesDiv').append('No articles found');
            }
        }
    });
}

/* Infinite scrolling for fetching articles */
var $window = $(window);
function prodScrollPosition() {
    var distance = $window.scrollTop() + $window.height();
    if ($('body').height() <= distance && $('#ArticlesDiv')) {
        articleLoader();
    }
}

$window.scroll(prodScrollPosition).scroll();

/* Manually initiate the first ajax request */
articleLoader();
</script>
like image 170
xyres Avatar answered Oct 23 '22 07:10

xyres