Django用户求助:jQuery加载API数据后DataTable无法正常渲染
Hey there! Let's break down why your DataTables isn't working when loading data via jQuery AJAX, and fix it step by step.
The Core Issue
When you render data directly with Django templates, DataTables initializes on a fully populated table. But with AJAX, you're dynamically adding content after DataTables might have already initialized—so it doesn't recognize the new rows, and its features (sorting, pagination, styling) break.
Fix 1: Use DataTables' Native API for Dynamic Rows (Recommended)
Instead of manually building HTML strings, use DataTables' built-in methods to add rows. This ensures DataTables tracks all changes and maintains full functionality.
First, initialize an empty DataTable when the page loads:
$(document).ready(function() { // Initialize empty DataTable with your preferred options var table = $('#approvedData').DataTable({ // Add options like pagination, sorting here if needed paging: true, searching: true }); });
Then update your fetchData function to use DataTables' API:
function fetchData() { $.ajax({ type: 'GET', url: endpoint, success: function (data) { console.log(data); var table = $('#approvedData').DataTable(); // Clear existing rows first to avoid duplicates table.clear(); data.forEach(object => { let storyStatus = 'Story not finish'; let colorClassName = "badge-danger"; if (object.story_status === "sf") { colorClassName = "badge-success"; storyStatus = "Story finish" } if (object.story_status === "fr") { colorClassName = "badge-success"; storyStatus = "Approved" } // Add row directly via DataTables API table.row.add([ object.id, `<a href="#">${object.title}</a>`, object.author, moment(object.created_on).fromNow(), `<span class="badge ${colorClassName}" id="story-status">${storyStatus}</span>`, `<div class="table-btns"> <a href="${updateURL}update/${object.id}" class="table-btn table-btn--edit"> <i class="icon ion-ios-create"></i> </a> <a href="#" class="table-btn table-btn--delete" data-pk="${object.id}"> <i class="icon ion-ios-trash"></i> </a> </div>` ]); }); // Draw the updated table table.draw(); // Use event delegation for delete buttons (dynamic elements) $('#approvedData').off('click', '.table-btn--delete').on('click', '.table-btn--delete', function () { var pk = $(this).data('pk'); var $row = $(this).closest('tr'); swal({ title: "Are you sure?", text: "You will not be able to recover this story!", icon: "warning", buttons: true, dangerMode: true, }) .then((willDelete) => { if (willDelete) { $.ajax({ url: '{% url "del" %}', type: 'POST', headers: { "X-CSRFToken": '{{csrf_token}}' }, data: { pk: pk }, success: function () { swal("Story has been deleted!", { icon: "success" }); // Remove the row from DataTables and redraw table.row($row).remove().draw(); } }); } else { swal("Story is safe"); } }); }); } }); }; // Initial data load fetchData(); // Note: 2 seconds is way too frequent for refreshes—use 30+ seconds to avoid server strain setInterval(fetchData, 30000);
Fix 2: If You Prefer Manual HTML Rendering
If you want to keep building HTML strings, you need to destroy and reinitialize DataTables after updating the table content:
function fetchData() { $.ajax({ type: 'GET', url: endpoint, success: function (data) { console.log(data); var html = ''; data.forEach(object => { let storyStatus = 'Story not finish'; let colorClassName = "badge-danger"; if (object.story_status === "sf") { colorClassName = "badge-success"; storyStatus = "Story finish" } if (object.story_status === "fr") { colorClassName = "badge-success"; storyStatus = "Approved" } html += `<tr> <td>${object.id}</td> <td><a href="#">${object.title}</a></td> <td>${object.author}</td> <td>${moment(object.created_on).fromNow()}</td> <td><span class="badge ${colorClassName}" id="story-status">${storyStatus}</span></td> <td> <div class="table-btns"> <a href="${updateURL}update/${object.id}" class="table-btn table-btn--edit"> <i class="icon ion-ios-create"></i> </a> <a href="#" class="table-btn table-btn--delete" data-pk="${object.id}"> <i class="icon ion-ios-trash"></i> </a> </div> </td> </tr>`; }); // Destroy existing DataTable instance $('#approvedData').DataTable().destroy(); // Update table content $("#approvedList").html(html); // Reinitialize DataTable $('#approvedData').DataTable(); // Event delegation for delete buttons $('#approvedData').off('click', '.table-btn--delete').on('click', '.table-btn--delete', function () { var pk = $(this).data('pk'); var $row = $(this).closest('tr'); swal({ title: "Are you sure?", text: "You will not be able to recover this story!", icon: "warning", buttons: true, dangerMode: true, }) .then((willDelete) => { if (willDelete) { $.ajax({ url: '{% url "del" %}', type: 'POST', headers: { "X-CSRFToken": '{{csrf_token}}' }, data: { pk: pk }, success: function () { swal("Story has been deleted!", { icon: "success" }); $('#approvedData').DataTable().row($row).remove().draw(); } }); } else { swal("Story is safe"); } }); }); } }); };
Key Notes
- Event Delegation: Always use
on()with a parent element for dynamically added buttons (like delete) — directclick()bindings won't work on new rows. - Avoid Frequent Refreshes: A 2-second interval will hammer your server. Use a longer window (30+ seconds) or implement a smarter refresh trigger.
- Check Resources: Ensure you've correctly included DataTables CSS and JS files in your template—missing resources are a common cause of style failures.
内容的提问来源于stack exchange,提问作者afi

