How to re-render django template code on AJAX call

MohitC picture MohitC · Sep 27, 2016 · Viewed 7.6k times · Source

I have a view which sends paginated object (on a queryset) to a template, which I further render in template as a table. What I am trying to do is on clicking a page number on pagination bar on template, it should make an ajax call to get paginated output for that page number and update the content of table with it dynamically.

View:

def accounts(request):
    #Including only necessary part
    accounts_list = Accounts.objects.all()
    paginator = Paginator(accounts_list, 25)
    page = request.GET.get('page')
    try:
        accounts = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        accounts = paginator.page(1)
    except EmptyPage:
        # If page is out of range, deliver last page of results.
        accounts = paginator.page(paginator.num_pages)

    context['accounts'] = accounts
    return render(request, template, context)

Template loads this as:

{% if accounts %}
<table id="acc">
    <tr>
        <th>Field 1</th>
        ...
        <th>Field N</th>
    </tr>
    {% for item in accounts %}
    <tr> 
        <td>{{ item.field1 }}</td>
        ...<!-- Some complex logic with template tags too in here -->
        <td>{{ item.fieldN }}</td>
    </tr>
    {% endfor %}
</table>
{% endif %}

Now for pagination bar, I am using Bootpag's library, and I can render stuff as:

$('.pagination_top').bootpag({
   /*bootpag logic here */
}).on("page", function(event, num){
    //$.ajax loading here where I can update the table div with new output 
    //or make the table div "template code" reload without reloading page
}

Sorry I haven't shown much of what I tried on ajax part since I am completely blank on how to make template re-render new accounts returned without reloading page.

The only dirty solution I can think of is generate my whole html in the view and then update the table div's html with new html ajax returned?

What would be the easy way to say reload the table div using template rendering logic written without reloading page? Can this be achieved by making table part a separated template and including/extending templates?

Please note that I can not use a method of getting all data on template and then using pagination logic of some jquery/js libaray, because complete data is relatively very large.

Answer

MohitC picture MohitC · Sep 28, 2016

I addressed the problem as following:

Separated the table part as template table.html as:

app/table.html:

{% if accounts %}
<table id="acc">
    <tr>
        <th>Field 1</th>
        ...
        <th>Field N</th>
    </tr>
    {% for item in accounts %}
    <tr> 
        <td>{{ item.field1 }}</td>
        ...<!-- Some complex logic with template tags too in here -->
        <td>{{ item.fieldN }}</td>
    </tr>
    {% endfor %}
</table>
{% endif %}

Called this in primary template main.html as included template:

app/main.html:

<div class="table-responsive">
    {% include 'app/table.html' %}
</div>

Now in my view I added a line which renders to only table.html if request is ajax request.

if request.is_ajax():
        return render(request, 'app/table.html', context)
#else
return render(request, 'app/main.html', context)

Reloading table on pagination as:

$('.pagination_top').bootpag({
   /*bootpag logic here */
}).on("page", function(event, num){
    $(".table-responsive").html('').load(
        "{% url 'app:accounts' %}?page=" + num
    );
});