How to re-render django template code on AJAX call

2020-06-04 16:23发布

问题:

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.

回答1:

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
    );
});


回答2:

If you want to rely on django templates you should reload the page and send over the pagination information in the requests. This is what is usually done (e.g. in django-admin). It requires reloading the page, but this is what django templates are made for.

Otherwise i would delegate the whole rendering over to the client and provide only a JSON view inside of django. This way django will provide a template that includes some markup together with your favorite js library, that takes care of making the AJAX calls and renders the data directly on it's own.

UPDATE:

If you really need to do this, the approach you mentioned is possible. Nothing stops you from rendering a part of your template, outsourced in separate file and send the already rendered HTML over to your client.

Therefor you can utilize the include template tag to move the table template into a separate file. For the AJAX calls you should use a second view, that just renders the table part of your template.

All this feels a hacky to me, but it should work.