rg3915 / django-datatables-experiment

Experiment with Django and DataTables.
14 stars 7 forks source link

DataTables Server Side render #1

Closed rg3915 closed 4 years ago

rg3915 commented 4 years ago

https://datatables.net/examples/data_sources/server_side.html

rg3915 commented 4 years ago

Vendo o exemplo Server-side processing e seguindo a doc Server-side processing, temos que:

img

A partir do endpoint /person/json/ devemos passar como parâmetros da url

?start=0&length=10

E a API deve retornar

response = {
    'data': data,
    'page': page,
    'per_page': per_page,
    'recordsTotal': total,
    'recordsFiltered': total,
}

Se você não informar recordsTotal e recordsFiltered ele não vai mostrar os itens total, consequentemente não vai mostrar a paginação completa.

Então:

  1. API endpoint

1.1 Eu criei um endpoint que me retorna os dados em JSON.

Os dados são paginados de 10 em 10.

path('person/json/', v.person_json, name='person_json'),

1.2 Montei um dicionário no models pra me retornar os dados

class Person(models.Model):
    name = models.CharField('nome', max_length=100)
    email = models.EmailField(null=True, blank=True)
    phone = models.CharField('telefone', max_length=11, null=True, blank=True)
    GENDER = (
        ('0', ''),
        ('man', 'homem'),
        ('woman', 'mulher'),
    )
    gender = models.CharField(
        'sexo',
        max_length=5,
        choices=GENDER,
        default='0'
    )

    def to_dict_json(self):
        return {
            'pk': self.pk,
            'name': self.name,
            'email': self.email,
            'phone': self.phone,
            'gender': self.get_gender_display(),
        }

1.3 Em views eu monto uma list compreehension que me retorna os dados em JSON.

persons = Person.objects.all()
data = [person.to_dict_json() for person in persons]
response = {
    'data': data,
}
return JsonResponse(response)
  1. Criei um novo template: persons_serverside.html
{% extends "base.html" %}
{% load static %}

{% block content %}

<div class="jumbotron">
  <div class="container">
    <h2>Exemplo do uso de <a href="https://datatables.net/" target="_blank">DataTables</a></h2>
    <p>Exemplo do uso de DataTables em <a href="https://datatables.net/examples/data_sources/server_side.html" target="_blank">Server-side render processing</a> com Django.</p>
  </div>
</div>

<div class="container">
  <div class="row">
    <div class="cols">
      <h2>DataTables Server-side render </h2>
      <table id="myTable" class="table">
        <thead>
          <tr>
            <th>Nome</th>
            <th>E-mail</th>
            <th>Telefone</th>
            <th>Gênero</th>
          </tr>
        </thead>
      </table>
    </div>
  </div>

  <hr>

</div> <!-- /container -->

{% endblock content %}

{% block js %}

<script>
  $(document).ready( function () {
    $('#myTable').DataTable({
      "processing": true,
      "serverSide": true,
      "ajax": "/person/json/",
      "columns": [
        {"data": "name"},
        {"data": "email"},
        {"data": "phone"},
        {"data": "gender"}
      ]
    });
  });

</script>

{% endblock js %}

Repare nas opções:

"processing": true,
"serverSide": true,
"ajax": "/person/json/",

2.1 views.py

def persons_serverside(request):
    template_name = 'persons_serverside.html'
    return render(request, template_name)
  1. Agora vamos nos concentrar nos dados que vem da API:
def person_json(request):
    persons = Person.objects.all()
    total = persons.count()

    _start = request.GET.get('start')
    _length = request.GET.get('length')
    if _start and _length:
        start = int(_start)
        length = int(_length)
        page = math.ceil(start / length) + 1
        per_page = length

        persons = persons[start:start + length]

    data = [person.to_dict_json() for person in persons]
    response = {
        'data': data,
        'page': page,  # [opcional]
        'per_page': per_page,  # [opcional]
        'recordsTotal': total,
        'recordsFiltered': total,
    }
    return JsonResponse(response)

O DataTable me fornece start e length via GET.

E eu uso o mesmo para fazer um fatiamento nos registros:

persons = persons[start:start + length]

E por fim

...
'recordsTotal': total,
'recordsFiltered': total,
...

PS: na verdade eu precisava de page e per_page por causa da API original, não é por causa do DataTable em si. Tanto que eu fiz o slice usando apenas start e length.

No final o DataTable só precisa disso:

response = {
    'data': data,
    'recordsTotal': total,
    'recordsFiltered': total,
}
vikaspwr commented 1 year ago

Thank you @rg3915 this worked for me :)