Django中Datatables服务端自定义分页数据返回异常问题排查
Hey there, let's dig into why your Datatables isn't pulling 50 records per page like you configured—this is a common gotcha with server-side processing!
问题根源
The core issue here is that you're manually handling pagination with Django's Paginator and a URL page parameter, but Datatables uses its own set of query parameters for server-side pagination: start (the index of the first record to fetch) and length (the number of records per page). Your custom pagination logic isn't hooked into these parameters, and the BaseDatatableView you're using already has built-in pagination that defaults to 10 records—so it's overriding your 50-item setting.
Plus, Datatables never sends a page parameter in its AJAX requests, so your URL's (?P<page>\d+) capture is irrelevant here, and your manual pagination code isn't actually doing what you think it is.
修正方案
Let's fix this by leaning into BaseDatatableView's built-in capabilities instead of reinventing the wheel:
1. 更新视图类
Remove your custom pagination logic—BaseDatatableView handles pagination, sorting, and filtering automatically if you configure it correctly. Just set the page_length attribute to your desired default per-page count, and return your base queryset from get_initial_queryset:
from django.db.models import Q from django.contrib.auth.mixins import LoginRequiredMixin from datatables.views import BaseDatatableView from .models import ProductSerialNumbers class ProductSerialNumbersListJSon(LoginRequiredMixin, BaseDatatableView): model = ProductSerialNumbers columns = ['snumber', 'order', 'product', 'registration_date'] order_columns = ['snumber', 'order', 'product', 'registration_date'] # Set default records per page here page_length = 50 def get_initial_queryset(self): # Return your base filter queryset—let BaseDatatableView handle pagination return ProductSerialNumbers.objects.filter( Q(snumber__isnull=True) | Q(order_id__isnull=True) | Q(order_id__finished=0) ).order_by("id")
2. 修正URL配置
Drop the page parameter from your URL—Datatables won't use it, and BaseDatatableView expects a standard endpoint without pagination segments:
from django.urls import path from . import views urlpatterns = [ # ... other URLs path('warehouse_tabledata/', views.ProductSerialNumbersListJSon.as_view(), name='warehouse_list_json'), ]
3. 前端Datatables配置(重要!)
Make sure your front-end Datatables initialization enables server-side processing and aligns with your backend settings. Here's a sample config:
$(document).ready(function() { $('#your-product-table').DataTable({ serverSide: true, ajax: "{% url 'warehouse_list_json' %}", // Use your URL name pageLength: 50, // Match your backend's default page_length // Optional: Let users choose per-page counts lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]], columns: [ { data: 'snumber' }, { data: 'order' }, { data: 'product' }, { data: 'registration_date' } ] }); });
为什么这能解决问题?
BaseDatatableViewautomatically reads thelengthparameter sent by Datatables (which will be 50 if you setpageLengthin the front-end, or your backend'spage_lengthdefault).- It handles the offset calculation using the
startparameter, so you don't have to manually manage page numbers and offsets. - Your queryset is filtered once, and the view takes care of slicing it to the correct page size for each request.
验证返回的JSON
After making these changes, your JSON response should have:
recordsTotal: Total number of unfiltered records in your querysetrecordsFiltered: Total number of records after any search/filtering (same asrecordsTotalif no filters are applied)data: Exactly 50 records (or the user-selected count) per request
内容的提问来源于stack exchange,提问作者gtopal

