Search code examples
javascriptjquerydjangoajaxdatatable

How to update a Datatable via Ajax call


I have a table that displays the content from a model whenever someone accesses the URL /project_page.

On that page, the user can add files and I would like the table to be updated in real-time without having to constantly refresh.

For that purpose, I have tried to implement an Ajax function that updates the table content every few seconds. Since it is something that was suggested a few years ago here

I think the function is implemented and I receive the data properly in the Ajax success function but I don't know how to 'inject it' to the table.

enter image description here

I would also like to know if there is a more optimal or pythonic way to achieve this result.

urls.py

path('project_page_ajax/', views.project_page_ajax, name='project_page_ajax'),

views.py

@login_required
def project_page(request):
    
    context = {}
    context['nbar'] = 'projects'
    if request.method == 'POST':
        print(request.FILES)
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            file_hist = form.save(commit=False)
            file_hist.user = request.user
            # file is saved
            file_hist.save()
            file_hist_results = FileHistory.objects.all().filter(user=request.user)
            context['file_hist_results'] = file_hist_results
            print(type(context['file_hist_results']))
            return render(request, 'project_page.html', context)
        print (form.errors)
    else:
        form = UploadFileForm()
    file_hist_results = FileHistory.objects.all().filter(user=request.user)
    context['file_hist_results'] = file_hist_results
    context['form'] = form
    return render(request, 'project_page.html', context)

@login_required
def project_page_ajax(request):
    response = dict()
    if request.method == 'GET':
        file_hist_results = FileHistory.objects.all().filter(user=request.user).values()
        #response.update({'file_hist_results': file_hist_results})
        return JsonResponse({"file_hist_results": list(file_hist_results)})
    return HttpResponse('')

project_page.html (JS PART)

var intervalID = setInterval(updateTable, 10000);

function updateTable()
{
    $.ajax({
        method: "GET",
        url: "/project_page_ajax/",
        success: function(data, textStatus, request) {
            console.log(data); 
        }
    });
}

project_page.html(HTML PART)

<table id="ittFileUploadTable" class="display nowrap" width="100%">
    <thead>
        <tr class="ittLineItemsTh">
        <th style="text-align:center;">File Name</th>
        <th style="text-align:center;">Submitted</th>
        <th style="text-align:center;">Updated</th>
        <th style="text-align:center;">User</th>
        <th style="text-align:center;">Action</th>
        </tr>
    </thead>
    <tbody>
        {% for histfiles in file_hist_results %}
        <tr>
        <td>{{ histfiles.filename }}</td>
        <td>{{ histfiles.uploaded }}</td>
        <td>{{ histfiles.updated }}</td>
        <td>{{ histfiles.user }}</td>
        <td>
        <button id="delete-itt-file" type="button" class="btn btn-secondary">
        <svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="currentColor" class="bi bi-trash-fill" viewBox="0 0 16 16">
        <path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"></path>
        </svg>
        </button>
        </td>
        </tr>
        {% endfor %}
    </tbody>
</table>                            

Solution

  • I found a solution!

    As @mark_b sugested, I used the datatables Ajax instead of jQuery AJAX

    Now it works, here is my code:

    $('#ittFileUploadTable').DataTable( {
        responsive: true,
        autowidth: false,
        destroy: true,
        deferRender: true,
        ajax: {
            url: '/project_page_ajax/',
            type: 'GET',
            data: {},
            dataSrc: ""
        },
        columns: [
            {"data": "fields.filename"},
            {"data": "fields.uploaded"},
            {"data": "fields.updated"},
            {"data": "fields.user"},
            {"data": "pk"},
        ],
        columnDefs: [
            { className: 'text-center', targets: [1] },
            {
                targets: [0],
                class: 'text-center',
                orderable: false,
                render: function (data, type, row) {
                    var buttons = '<a href="/media/'+data+'" target="_blank">'+data+'</a>';
                    return buttons;
                }
            },
            {
                targets: [-1],
                class: 'text-center',
                orderable: false,
                render: function (data, type, row) {
                    var buttons = '<form method="post" action="delete_file/'+data+'/"><button type="submit" class="btn btn-danger"><svg xmlns="http://www.w3.org/2000/svg" width="25" height="25" fill="white" class="bi bi-trash-fill" viewBox="0 0 16 16"><path d="M2.5 1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1H3v9a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V4h.5a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H10a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1H2.5zm3 4a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 .5-.5zM8 5a.5.5 0 0 1 .5.5v7a.5.5 0 0 1-1 0v-7A.5.5 0 0 1 8 5zm3 .5v7a.5.5 0 0 1-1 0v-7a.5.5 0 0 1 1 0z"/></svg></button></form>';
                    return buttons;
                }
            },
        ],
        order: [
            [0, 'asc']
        ],
        "pagingType": "numbers",
        dom: 'rt'
    });