Skip to content

Instantly share code, notes, and snippets.

@oisobstudio
Last active April 1, 2023 18:53
Show Gist options
  • Save oisobstudio/b99d568974a3393865d53d85cad04106 to your computer and use it in GitHub Desktop.
Save oisobstudio/b99d568974a3393865d53d85cad04106 to your computer and use it in GitHub Desktop.
Django Pagination Server-Side Menggunakan DataTable

myapp/views.py

import json

from django.views.generic import View
from django.http import HttpResponse
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.db.models import Q
from django.core.serializers.json import DjangoJSONEncoder

# ================
# Inner app module
# ================
from .models import Invoice
from .models import TransactionDetail 
from .models import InvoiceCategory
from .models import InvoiceStatus


class AjaxInvoiceWebList(View):

	def post(self, request):
		# Ambil semua data invoice yang valid
		invoices = self._datatables(request)
		return HttpResponse(json.dumps(invoices, cls=DjangoJSONEncoder), content_type='application/json')
		
	def _datatables(self, request):
		datatables = request.POST
		# Ambil draw
		draw = int(datatables.get('draw'))
		# Ambil start
		start = int(datatables.get('start'))
		# Ambil length (limit)
		length = int(datatables.get('length'))
		# Ambil data search
		search = datatables.get('search[value]')
		# Set record total
		records_total = Invoice.objects.all().exclude(Q(transactiondetail=None)|Q(shipping=None)|Q(billing=None)).count()
		# Set records filtered
		records_filtered = records_total
		# Ambil semua invoice yang valid
		invoices = Invoice.objects.all().exclude(Q(transactiondetail=None)|Q(shipping=None)|Q(billing=None))

		if search:
			invoices = Invoice.objects.filter(
					Q(invoice_number__icontains=search)|
					Q(user__username__icontains=search)|
					Q(category__info__icontains=search)|
					Q(status__info__icontains=search)
				).exclude(Q(transactiondetail=None)|Q(shipping=None)|Q(billing=None))
			records_total = invoices.count()
			records_filtered = records_total

		# Atur paginator
		paginator = Paginator(invoices, length)

		try:
			object_list = paginator.page(draw).object_list
		except PageNotAnInteger:
			object_list = paginator.page(draw).object_list
		except EmptyPage:
			object_list = paginator.page(paginator.num_pages).object_list


		data = [
			{
				'user': inv.user.username,
				'invoice_number': inv.invoice_number,
				'date_transaction': inv.invoice_date,
				'total_price': inv.total,
				'category': inv.category.info,
				'status': inv.status.info
			} for inv in object_list
		]

		return {
			'draw': draw,
			'recordsTotal': records_total,
			'recordsFiltered': records_filtered,
			'data': data,
		}
		
def invoiceweb_list(request):
    data_context = {}
    return render(request, 
				  'myapp/invoice/invoiceweb_list.html', 
				  data_context)

myapp/urls.py

from django.conf.urls import url
from . import views


urlpatterns = [
	url(r'^invoice/web\.html$', 
		views.invoiceweb_list, 
		name='invoiceweb_list'),
	url(r'^ajax/invoice/web\.html$', 
		views.AjaxInvoiceWebList.as_view(), 
		name='ajax_invoice_web_list'),
]

project/urls.py

from django.conf.urls import include, url
from django.contrib import admin

urlpatterns = [
	# ....
    url(r'^transaction/', include('apltransaction.urls', namespace="apltransaction")),
]

myapp/templates/myapp/invoice/invoiceweb_list.html

{% extends "base.html" %}
{% load staticfiles %}
{% load widget_tweaks %}

{% block title %}Invoice In Web{% endblock %}

{% block heading %}Invoice In Web{% endblock %}

{% block css %}
<link rel="stylesheet" type="text/css" href="{% static 'bower_components/datatables/css/dataTables.bootstrap.min.css' %}">
{% endblock %}

{% block content %}
<table id="example" class="display table" cellspacing="0" width="100%">
    <thead>
        <tr>
            <th>#</th>
            <th>User</th>
            <th>Invoice Number</th>
            <th>Date Transaction</th>
            <th>Total Price</th>
            <th>Category</th>
            <th>Status</th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <th><input type="checkbox" name="checkbox"></th>
            <th>User</th>
            <th>Invoice Number</th>
            <th>Date Transaction</th>
            <th>Total Price</th>
            <th>Category</th>
            <th>Status</th>
        </tr>
    </tfoot>
</table>
{% endblock %}

{% block js %}
<script src="{% static 'bower_components/datatables/js/dataTables.bootstrap.min.js' %}"></script>
<script>
    $(document).ready(function() {
        $('#example').DataTable( {
            "processing": true,
            "serverSide": true,
            "ajax": {
                "url": "url 'apltransaction:ajax_invoice_web_list'",
                "type": "POST"
            },
            "columns": [
                { "data": "user" },
                { "data": "user" },
                { "data": "invoice_number" },
                { "data": "date_transaction" },
                { "data": "total_price" },
                { "data": "category" },
                { "data": "status" }
            ]
        } );
    } );
</script>
{% endblock %}
@h4rm41n
Copy link

h4rm41n commented Sep 11, 2018

this is awesome trick for datatables server side on django
sorry please correct the js client code if type POST request

"ajax": {
        "url": "{% url 'app_url:ajax_web_list' %}",
        "type": "post",
        "data": {
            "csrfmiddlewaretoken": "{{ csrf_token }}"
        }
    }
"ajax": {
        "url": "{% url 'app_url:ajax_web_list' %}",
        "type": "get",
    }

@chalist
Copy link

chalist commented Nov 21, 2018

Where you use start variable?

@dsifat
Copy link

dsifat commented Nov 29, 2018

Is this working perfectly?

@chalist
Copy link

chalist commented Dec 1, 2018

Does not work for me!

@rodrigosobrero
Copy link

Pagination it's wrong, you need to change to this:

page_number = start / length + 1

try:
    object_list = paginator.page(page_number).object_list
except PageNotAnInteger:
    object_list = paginator.page(1).object_list
except EmptyPage:
    object_list = paginator.page(1).object_list

@Ildemselcuk
Copy link

Thank you for coding of datatables with Django.
I run to above code . But line of "draw = int(datatables.get('draw')) " take following errors.
"TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'"

@guhkun13
Copy link

guhkun13 commented Apr 6, 2020

hi, thanks for the code, it works after applied the solution in comment sections (also thanks to contributor) , it really help me!

btw, the sorting does not work , so i add these lines :

  • Ambil data untuk ordering

`

order_idx = int(datatables.get('order[0][column]'))
order_dir = datatables.get('order[0][dir]')
order_col = 'columns[' + str(order_idx) + '][data]'
order_col_name = datatables.get(order_col)

if (order_dir == "desc"):
  order_col_name =  str('-' + order_col_name)

... (code filtering data)

  • after data filterred , apply order
    datas = datas.order_by(order_col_name)

it's just there is still this bug, the data in first row is not sorted. still try to figure out the solutions

@guhkun13
Copy link

guhkun13 commented Apr 11, 2020

update, i found this column filtering in datatables but it's for client side rendering ( https://datatables.net/extensions/fixedheader/examples/options/columnFiltering.html )
so i added it to able using server side, cont from code above

        idx=0
        for itemcol in datatables:
            colname = 'columns['+str(idx)+'][data]'
            colsearchval = 'columns['+str(idx)+'][search][value]'

            colname = datatables.get(colname)
            colsearchval = datatables.get(colsearchval)
            if (colsearchval):
                search_type = 'icontains'
                filter = colname + '__' + search_type
                datas=datas.filter(**{ filter: colsearchval })

                records_total = datas.count()
                records_filtered = records_total

            idx+=1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment