Files
allianceauth/docs/development/custom/framework/datatables.md
2026-01-20 08:22:25 +00:00

215 lines
7.3 KiB
Markdown

# 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
```django
{% load evelinks %}
{% character_portrait_url row 32 %}
```
### template/appname/stubs/name.html
```django
{{ row.character_name }} <span class="text-small">({{ row.character_ownership.user.username }})</span>
```
### template/appname/stubs/corp.html
```django
{{ row.corporation_name }}
```
### template/appname/list.html
```django
{% extends "allianceauth/base-bs5.html" %}
{% load i18n %}
{% load aa_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 %}
{% include "bundles/datatables-2-css-bs5.html" %}
{% comment %} If you don't use the ColumnControl Extension, remove the next line {% endcomment %}
{% include "bundles/datatables-2-columncontrol-css-bs5.html" %}
{% endblock %}
{% block extra_javascript %}
{% get_datatables_language_static LANGUAGE_CODE as DT_LANG_PATH %}
{% include "bundles/datatables-2-js-bs5.html" %}
{% comment %} If you don't use the ColumnControl Extension, remove the next line {% endcomment %}
{% include "bundles/datatables-2-columncontrol-js-bs5.html" %}
<script>
$(document).ready(() => {
// Assuming you have a table with the ID 'table'
// A jQuery HTML Element `$('#table')` can also be passed instead of a selector string
const dt = new DataTable('#table', {
language: {
url: '{{ DT_LANG_PATH }}',
// Important: The value for `language.processing` must be passed
// as a JS template string, not as a normal string. This is to
// allow for Django template rendering inside the processing
// indicator.
processing: `{% include "framework/datatables/process-indicator.html" %}`
},
layout: { // See: https://datatables.net/reference/option/layout
topStart: 'pageLength',
topEnd: 'search',
bottomStart: 'info',
bottomEnd: 'paging'
},
ordering: { // See: https://datatables.net/reference/option/ordering
handler: true, // Enable ordering by clicking on column headers
indicators: false, // Disable ordering indicators on column headers (important when ColumnControl is used)
},
processing: true, // Show processing indicator when loading data
serverSide: true, // Enable server-side processing
ajax: '{% url "appname:data_table_view" %}',
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, // Override default page length if desired
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
```python
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
```python
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='data_table_view')
]
```
and you are done.