Files
allianceauth/docs/development/custom/framework/datatables.md

5.9 KiB

DataTables Server Side Rendering

The allianceauth.framework.datatables.DataTablesView module provides a simple class based view to implement simple server side filtering ordering and searching of DataTables.

This is intended to make the life of our community apps developer a little easier, so they don't have to reinvent the wheel.

Usage

To use this view is as easy as defining your stub templates, and fields and adding the view to the urls.py

Given the EveCharacter Model as our model of choice we would define our stubs like so

Add our Templates

template/appname/stubs/icon.html

{% load evelinks %}
{% character_portrait_url row 32 %}

template/appname/stubs/name.html

{{ row.character_name }} <span class="text-small">({{ row.character_ownership.user.username }})</span>

template/appname/stubs/corp.html

{{ row.corporation_name }}

template/appname/list.html

{% extends "allianceauth/base-bs5.html" %}
{% load i18n %}
{% block page_title %}
    {% translate "App Name" %}
{% endblock page_title %}
{% block content %}
    <table class="table table-striped w-100" id="table">
        <!-- Normal Header Rows -->
        <thead>
            <tr>
                <th></th>
                <th>{% translate "Name" %}</th>
                <th>{% translate "Corporation" %}</th>
                <th>{% translate "Alliance" %}</th>
            </tr>
        </thead>
    </table>
{% endblock content %}
{% block extra_css %}
    <link rel="stylesheet" href="https://cdn.datatables.net/2.3.6/css/dataTables.bootstrap5.css" />
    <link href="https://cdn.datatables.net/columncontrol/1.2.0/css/columnControl.bootstrap5.min.css" rel="stylesheet">
{% endblock %}
{% block extra_javascript %}
    <script src="https://cdn.datatables.net/2.3.6/js/dataTables.js"></script>
    <script src="https://cdn.datatables.net/2.3.6/js/dataTables.bootstrap5.js"></script>
    <script src="https://cdn.datatables.net/columncontrol/1.2.0/js/dataTables.columnControl.min.js"></script>
    <script>
        $(document).ready(function() {
            $('#table').DataTable({
                serverSide: true,
                ajax: '{% url "appname:table" %}',
                columnDefs: [
                    {
                        targets: [0],
                        columnControl: [],
                        sortable: false,
                        searchable: false

                    },
                    {
                        targets: [1,2,3],
                        columnControl: [
                            {
                                target: 0,
                                content: []
                            },
                            {
                                target: 1,
                                content: ['search']
                            }
                        ],
                    }
                ],
                order: [
                    [1, "asc"]
                ],
                pageLength: 10,
                responsive : true
            });
        });
    </script>
{% endblock extra_javascript %}

Add our Views

Then we can setup out view in our appname/views.py file.

Columns definition

The columns must be defined as a 2 part tuple

  • Part 1 is the database field that will be used for filtering and ordering. If this is a foreign key you need to point to a field that is compatible with __icontains like charField or textField. It can be None/False/"" if no ordering for filtering is required for this row.
    • Examples for the EveCharacter Model:
      • character_name
      • character_ownership__user__username
      • character_ownership__user__profile__main_character__character_name
  • Part 2 is a string that is used to the render the column for each row. This can be a html stub or a string containing django style template language.
    • Examples for the EveCharacter Model
      • {{ row.character_name }}
      • {{ row.character_ownership.user.username }}
      • {{ row.character_ownership.user.profile.main_character.character_name }}
      • appname/stubs/character_img.html

appname/views.py

from django.shortcuts import render
# Alliance Auth
from allianceauth.framework.datatables import DataTablesView
from allianceauth.eveonline.models import EveCharacter

## Datatables server side view
class EveCharacterTable(DataTablesView):
    model = EveCharacter

    # Define the columns as a tuple.
    # String for field name for filtering and ordering
    # String for the render template
    # Templates can be a html file or template language directly in the list below
    columns = [
        # ("field_for_queries_or_sort", template: str)
        ("", "appname/stubs/icon.html"),
        ("character_name", "appname/stubs/name.html"),
        ("corporation_name", "appname/stubs/corp.html"),
        ("alliance_name", "{{ row.alliance_name }} {{ row.alliance_id }}"),
    ]

    # if you need to do some prefetch or pre-filtering you can overide this function
    def get_model_qs(self, request: HttpRequest):
        qs = self.model.objects
        if not request.user.is_superuser:
            # eg only show unlinked characters to non-superusers
            # just an example
            # filtering here will prevent people searching things that may not be visible to them
            qs = qs.filter(character_ownership__isnull=True)
        # maybe some character ownership select related for performance?
        return qs.select_related("character_ownership", "character_ownership__user")

## Main Page View
def show_table(request):
    return render("appname/list.html")

Add our Urls

appname/urls.py

from django.urls import path

from . import views

app_name = 'appname'

urlpatterns = [
    path("list/", views.EveCharacterTable.as_view(), name='eve_character_table'),
    path("tables/data_table", views.show_table, name='table')
]

and you are done.