django-advanced-datatables 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. django_advanced_datatables-1.0.0/LICENSE +21 -0
  2. django_advanced_datatables-1.0.0/MANIFEST.in +3 -0
  3. django_advanced_datatables-1.0.0/PKG-INFO +406 -0
  4. django_advanced_datatables-1.0.0/README.md +385 -0
  5. django_advanced_datatables-1.0.0/django_advanced_datatables.egg-info/PKG-INFO +406 -0
  6. django_advanced_datatables-1.0.0/django_advanced_datatables.egg-info/SOURCES.txt +111 -0
  7. django_advanced_datatables-1.0.0/django_advanced_datatables.egg-info/dependency_links.txt +1 -0
  8. django_advanced_datatables-1.0.0/django_advanced_datatables.egg-info/requires.txt +6 -0
  9. django_advanced_datatables-1.0.0/django_advanced_datatables.egg-info/top_level.txt +1 -0
  10. django_advanced_datatables-1.0.0/django_datatables/__init__.py +1 -0
  11. django_advanced_datatables-1.0.0/django_datatables/admin.py +7 -0
  12. django_advanced_datatables-1.0.0/django_datatables/apps.py +13 -0
  13. django_advanced_datatables-1.0.0/django_datatables/cache.py +69 -0
  14. django_advanced_datatables-1.0.0/django_datatables/colour_rows.py +1 -0
  15. django_advanced_datatables-1.0.0/django_datatables/column_visibility/__init__.py +0 -0
  16. django_advanced_datatables-1.0.0/django_datatables/column_visibility/mixins.py +86 -0
  17. django_advanced_datatables-1.0.0/django_datatables/column_visibility/modals.py +117 -0
  18. django_advanced_datatables-1.0.0/django_datatables/columns/__init__.py +11 -0
  19. django_advanced_datatables-1.0.0/django_datatables/columns/column_base.py +444 -0
  20. django_advanced_datatables-1.0.0/django_datatables/columns/columns.py +465 -0
  21. django_advanced_datatables-1.0.0/django_datatables/columns/currency.py +137 -0
  22. django_advanced_datatables-1.0.0/django_datatables/columns/date_time.py +50 -0
  23. django_advanced_datatables-1.0.0/django_datatables/columns/many_to_many.py +101 -0
  24. django_advanced_datatables-1.0.0/django_datatables/columns/modal_columns.py +108 -0
  25. django_advanced_datatables-1.0.0/django_datatables/constants.py +9 -0
  26. django_advanced_datatables-1.0.0/django_datatables/datatables/__init__.py +6 -0
  27. django_advanced_datatables-1.0.0/django_datatables/datatables/column_initialiser.py +104 -0
  28. django_advanced_datatables-1.0.0/django_datatables/datatables/datatable_error.py +2 -0
  29. django_advanced_datatables-1.0.0/django_datatables/datatables/datatable_table.py +508 -0
  30. django_advanced_datatables-1.0.0/django_datatables/datatables/server_side.py +556 -0
  31. django_advanced_datatables-1.0.0/django_datatables/datatables/simple_table.py +47 -0
  32. django_advanced_datatables-1.0.0/django_datatables/datatables/views.py +157 -0
  33. django_advanced_datatables-1.0.0/django_datatables/detect_device.py +5 -0
  34. django_advanced_datatables-1.0.0/django_datatables/downloads/__init__.py +0 -0
  35. django_advanced_datatables-1.0.0/django_datatables/downloads/clipboard.py +54 -0
  36. django_advanced_datatables-1.0.0/django_datatables/downloads/excel_download.py +113 -0
  37. django_advanced_datatables-1.0.0/django_datatables/filters.py +93 -0
  38. django_advanced_datatables-1.0.0/django_datatables/helpers.py +128 -0
  39. django_advanced_datatables-1.0.0/django_datatables/includes.py +60 -0
  40. django_advanced_datatables-1.0.0/django_datatables/migrations/0001_initial.py +28 -0
  41. django_advanced_datatables-1.0.0/django_datatables/migrations/0002_savedstate_column_order_savedstate_column_visibility_and_more.py +28 -0
  42. django_advanced_datatables-1.0.0/django_datatables/migrations/0003_alter_savedstate_state.py +18 -0
  43. django_advanced_datatables-1.0.0/django_datatables/migrations/0004_alter_savedstate_public_alter_savedstate_state_and_more.py +29 -0
  44. django_advanced_datatables-1.0.0/django_datatables/migrations/__init__.py +0 -0
  45. django_advanced_datatables-1.0.0/django_datatables/modal_filter/__init__.py +0 -0
  46. django_advanced_datatables-1.0.0/django_datatables/modal_filter/filter_fields.py +60 -0
  47. django_advanced_datatables-1.0.0/django_datatables/modal_filter/mixins.py +115 -0
  48. django_advanced_datatables-1.0.0/django_datatables/modal_filter/modals.py +42 -0
  49. django_advanced_datatables-1.0.0/django_datatables/modals.py +39 -0
  50. django_advanced_datatables-1.0.0/django_datatables/model_def.py +71 -0
  51. django_advanced_datatables-1.0.0/django_datatables/models.py +19 -0
  52. django_advanced_datatables-1.0.0/django_datatables/plugins/__init__.py +0 -0
  53. django_advanced_datatables-1.0.0/django_datatables/plugins/colour_rows.py +22 -0
  54. django_advanced_datatables-1.0.0/django_datatables/plugins/column_totals.py +58 -0
  55. django_advanced_datatables-1.0.0/django_datatables/plugins/reorder.py +10 -0
  56. django_advanced_datatables-1.0.0/django_datatables/plugins/save_filters.py +28 -0
  57. django_advanced_datatables-1.0.0/django_datatables/reorder_datatable.py +67 -0
  58. django_advanced_datatables-1.0.0/django_datatables/server_side_filters.py +401 -0
  59. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/css/datatables.css +247 -0
  60. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/datatables/css/datatables.min.css +24 -0
  61. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/datatables/js/datatables.min.js +375 -0
  62. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/js/filtered-datatable.js +1270 -0
  63. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/js/filtered_datatables_legacy.js +1057 -0
  64. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/js/runtime.js +754 -0
  65. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/js/spreadsheet.js +98 -0
  66. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/jspreadsheet/index.d.ts +3065 -0
  67. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/jspreadsheet/index.js +23 -0
  68. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/jspreadsheet/jspreadsheet.css +761 -0
  69. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/jspreadsheet/jspreadsheet.datatables.css +95 -0
  70. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/jsuites/jsuites.css +2930 -0
  71. django_advanced_datatables-1.0.0/django_datatables/static/django_datatables/jsuites/jsuites.js +12414 -0
  72. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/clear_table.html +18 -0
  73. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/base_filter_block.html +28 -0
  74. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/date_filter.html +78 -0
  75. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/filter_control.html +92 -0
  76. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/pivot_filter.html +19 -0
  77. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/pivot_totals.html +55 -0
  78. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/python_pivot_filter.html +79 -0
  79. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/row_tree.html +73 -0
  80. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/select2_filter.html +85 -0
  81. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/selected_filter.html +75 -0
  82. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/server_date_filter.html +81 -0
  83. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/server_pivot_filter.html +19 -0
  84. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/server_pivot_totals.html +44 -0
  85. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/server_select2_filter.html +118 -0
  86. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/server_tag_filter.html +159 -0
  87. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/table_search.html +22 -0
  88. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_blocks/tag_filter.html +175 -0
  89. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_rows/checkbox_filter.html +8 -0
  90. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_rows/checkbox_python.html +8 -0
  91. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_rows/checkbox_tag.html +9 -0
  92. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/filter_rows/checkbox_total.html +11 -0
  93. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/horizontal_table.html +32 -0
  94. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/icon_menu.html +14 -0
  95. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/no_of_results.html +15 -0
  96. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/no_of_rows.html +21 -0
  97. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/plugins/colour_rows.html +13 -0
  98. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/plugins/column_totals.html +91 -0
  99. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/plugins/reorder.html +20 -0
  100. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/plugins/save_state.html +97 -0
  101. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/search_boxes.html +63 -0
  102. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/spreadsheet.html +9 -0
  103. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/table.html +40 -0
  104. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/view_file_modal.html +46 -0
  105. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/widgets/datatable-reorder.html +24 -0
  106. django_advanced_datatables-1.0.0/django_datatables/templates/datatables/widgets/datatable.html +78 -0
  107. django_advanced_datatables-1.0.0/django_datatables/templatetags/__init__.py +0 -0
  108. django_advanced_datatables-1.0.0/django_datatables/templatetags/datatable_tags.py +48 -0
  109. django_advanced_datatables-1.0.0/django_datatables/urls.py +8 -0
  110. django_advanced_datatables-1.0.0/django_datatables/utils.py +11 -0
  111. django_advanced_datatables-1.0.0/django_datatables/widgets.py +58 -0
  112. django_advanced_datatables-1.0.0/pyproject.toml +32 -0
  113. django_advanced_datatables-1.0.0/setup.cfg +4 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Ian Jones
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,3 @@
1
+ recursive-include django_datatables *
2
+ recursive-exclude django_datatables *.pyc
3
+ prune tests
@@ -0,0 +1,406 @@
1
+ Metadata-Version: 2.4
2
+ Name: django-advanced-datatables
3
+ Version: 1.0.0
4
+ Summary: Django views with javascript filters using Datatables
5
+ Author: Ian Jones
6
+ Maintainer: Thomas Turner
7
+ License-Expression: MIT
8
+ Project-URL: Homepage, https://github.com/django-advance-utils/django-advanced-datatables
9
+ Project-URL: Upstream, https://github.com/jonesim/django-datatables
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.6
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: ajax-advanced-helpers>=1.0.1
16
+ Requires-Dist: django-advanced-menus>=1.0.0
17
+ Requires-Dist: django-advanced-modals>=1.0.0
18
+ Provides-Extra: excel
19
+ Requires-Dist: openpyxl; extra == "excel"
20
+ Dynamic: license-file
21
+
22
+ [![PyPI version](https://img.shields.io/pypi/v/django-advanced-datatables)](https://pypi.org/project/django-advanced-datatables/)
23
+
24
+ # django-advanced-datatables
25
+
26
+ The [django-advance-utils](https://github.com/django-advance-utils) line of Ian Jones's
27
+ [django-filtered-datatables](https://github.com/jonesim/django-datatables), forked so that releases can be
28
+ cut as the downstream libraries and django-advanced-report-builder need them. The Python package
29
+ is still `django_datatables`, so existing imports and `INSTALLED_APPS` entries do not change; only the
30
+ pip name does. It depends on [ajax-advanced-helpers](https://github.com/django-advance-utils/ajax-advanced-helpers),
31
+ [django-advanced-menus](https://github.com/django-advance-utils/django-advanced-menus) and
32
+ [django-advanced-modals](https://github.com/django-advance-utils/django-advanced-modals).
33
+
34
+ A Django library for building interactive data tables powered by [DataTables.js](https://datatables.net/), with server-side processing, dynamic JavaScript filters, inline editing, and a rich plugin system.
35
+
36
+ Define your tables in Python using Django models and ORM queries -- columns, filters, sorting, annotations, and rendering are all configured from your views, with minimal JavaScript required.
37
+
38
+ ## Features
39
+
40
+ - **20+ column types** -- dates, currency, booleans, links, many-to-many, choice fields, lambdas, and more
41
+ - **AJAX and non-AJAX modes** -- load data dynamically or render inline
42
+ - **JavaScript filters** -- pivot, tag, select2, date range, and text search filters
43
+ - **Modal filter dialogs** -- form-based filtering with crispy-forms support
44
+ - **Inline editing** -- edit cells directly in the table with select2 dropdowns or text inputs
45
+ - **Row selection** -- checkbox-based row selection with bulk actions
46
+ - **Plugins** -- column totals, conditional row colouring, drag-and-drop reordering, save/restore filter state
47
+ - **Data export** -- Excel (.xlsx) download and clipboard copy
48
+ - **Client-side rendering** -- render functions for badges, links, conditional formatting, and lookups
49
+ - **Django ORM integration** -- annotations, aggregations, foreign key traversal, callable model methods
50
+ - **Model-defined columns** -- configure columns directly on your Django models via an inner `Datatable` class
51
+ - **Multiple tables per view** -- display several tables on a single page
52
+ - **Spreadsheet mode** -- JSpreadsheet integration for spreadsheet-like editing
53
+ - **Form widgets** -- `DataTableWidget` and `DataTableReorderWidget` for use in Django forms
54
+ - **Mobile responsive** -- automatic device detection with per-device column visibility
55
+ - **Redis caching** -- optional cache layer with signal-based invalidation
56
+
57
+ ## Installation
58
+
59
+ ```bash
60
+ pip install django-advanced-datatables
61
+ ```
62
+
63
+ Add to your `INSTALLED_APPS`:
64
+
65
+ ```python
66
+ INSTALLED_APPS = [
67
+ # ...
68
+ 'django_datatables',
69
+ 'ajax_helpers',
70
+ # ...
71
+ ]
72
+ ```
73
+
74
+ Include the required JavaScript and CSS in your base template. The library depends on DataTables.js, jQuery, and Bootstrap.
75
+
76
+ ## Quick Start
77
+
78
+ ### 1. Define a view
79
+
80
+ ```python
81
+ from django_datatables.datatables import DatatableView
82
+
83
+ class CompanyList(DatatableView):
84
+ model = Company
85
+
86
+ @staticmethod
87
+ def setup_table(table):
88
+ table.add_columns(
89
+ 'id',
90
+ 'name',
91
+ 'dissolved',
92
+ )
93
+ ```
94
+
95
+ ### 2. Wire up the URL
96
+
97
+ ```python
98
+ urlpatterns = [
99
+ path('companies/', CompanyList.as_view(), name='company-list'),
100
+ ]
101
+ ```
102
+
103
+ ### 3. Use the template
104
+
105
+ The default template renders a complete DataTables table. You can override it via `template_name` on your view.
106
+
107
+ ## Usage
108
+
109
+ ### Adding Columns
110
+
111
+ Columns can be added in several ways:
112
+
113
+ ```python
114
+ def setup_table(table):
115
+ table.add_columns(
116
+ 'name', # model field name
117
+ ('id', {'title': 'ID', 'width': '30px'}), # tuple with options
118
+ DateColumn('date_entered', column_name='Date'), # column class instance
119
+ 'company__name', # foreign key traversal
120
+ 'Tags', # model-defined column
121
+ )
122
+ ```
123
+
124
+ **String prefix syntax** for quick column options:
125
+ - `.field` -- hidden column (still available for filtering/rendering)
126
+ - `_field` -- calculated column (not from the database)
127
+ - `$field` -- secure column (hidden from client source)
128
+
129
+ ### Column Types
130
+
131
+ | Column | Purpose |
132
+ |--------|---------|
133
+ | `DatatableColumn` | Standard column with customisable `row_result` and `col_setup` |
134
+ | `DateColumn` | Formats dates (dd/mm/yyyy) |
135
+ | `DateTimeColumn` | Formats datetimes |
136
+ | `ChoiceColumn` | Maps integer choices to display labels |
137
+ | `CurrencyColumn` | Currency formatting |
138
+ | `BooleanColumn` | Boolean display |
139
+ | `ColumnLink` | Clickable link using Django URL names |
140
+ | `ManyToManyColumn` | Displays many-to-many relationships |
141
+ | `CallableColumn` | Calls a model method |
142
+ | `LambdaColumn` | Processes values with a lambda function |
143
+ | `SelectColumn` | Row selection checkboxes |
144
+ | `TextFieldColumn` | Long text with truncation |
145
+
146
+ ### Model-Defined Columns
147
+
148
+ Configure columns directly on your models:
149
+
150
+ ```python
151
+ class Company(models.Model):
152
+ name = models.CharField(max_length=80)
153
+
154
+ class Datatable(DatatableModel):
155
+ # Annotation-based column
156
+ people = {'annotations': {'people': Count('person__id')}}
157
+
158
+ # Link column
159
+ collink_1 = ColumnLink(title='View', field=['id', 'name'], url_name='company-detail')
160
+
161
+ # Column list (renders multiple fields as a group)
162
+ company_list = ['id', 'name']
163
+
164
+ # Custom column class
165
+ class ModelIdColumn(DatatableColumn):
166
+ def col_setup(self):
167
+ self.field = 'id'
168
+ self.title = 'Custom ID'
169
+ ```
170
+
171
+ These columns can then be referenced by name in `add_columns()`:
172
+
173
+ ```python
174
+ table.add_columns('id', 'name', 'people', 'collink_1', 'ModelIdColumn')
175
+ ```
176
+
177
+ ### Filters
178
+
179
+ ```python
180
+ def setup_table(table):
181
+ table.add_columns('id', 'name', 'company__name', 'Tags')
182
+
183
+ # JavaScript filters
184
+ table.add_js_filters('tag', 'Tags') # tag filter
185
+ table.add_js_filters('select2', 'company__name') # select2 dropdown
186
+ table.add_js_filters('totals', 'id') # totals/count filter
187
+ table.add_js_filters('date', 'date_entered') # date range
188
+ table.add_js_filters('expand', 'level', id_column='id') # tree expand
189
+
190
+ # ORM-level filters
191
+ table.filter = {'company__id': 1}
192
+ table.exclude = {'dissolved': True}
193
+ ```
194
+
195
+ #### Modal Filter (form-based)
196
+
197
+ ```python
198
+ from django_datatables.modal_filter.mixins import DatatableFilterMixin, DatatableFilterField
199
+
200
+ class CompanyList(DatatableFilterMixin, DatatableView):
201
+ model = Company
202
+ filter_fields = [
203
+ DatatableFilterField('Company Name', CharField(required=False), datatable_field='name__contains'),
204
+ DatatableFilterField('Tags', FilterModelMultipleChoiceField(queryset=Tags.objects.all()), datatable_field='tags__in'),
205
+ ]
206
+ ```
207
+
208
+ ### Sorting
209
+
210
+ ```python
211
+ table.sort('name') # ascending
212
+ table.sort('-name') # descending
213
+ table.sort('name', '-id') # multi-column
214
+ ```
215
+
216
+ ### Column Search
217
+
218
+ Per-column search boxes appear below the header by default. Customise them:
219
+
220
+ ```python
221
+ table.add_columns(
222
+ ColumnBase(column_name='status', field='dissolved',
223
+ col_search_select=[['true', 'Dissolved'], ['false', 'Active']]),
224
+ ColumnBase(column_name='order', field='order', no_col_search=True),
225
+ )
226
+ table.table_options['no_col_search'] = True # disable all column search
227
+ ```
228
+
229
+ ### Client-Side Rendering
230
+
231
+ Render functions transform cell data in the browser without extra server round-trips:
232
+
233
+ ```python
234
+ from django_datatables.helpers import render_replace, row_button
235
+
236
+ table.add_columns(
237
+ # Badge rendering
238
+ ColumnBase(column_name='people', field='people', render=[
239
+ render_replace(column='people', html='<span class="badge badge-primary">%1%</span>'),
240
+ ]),
241
+
242
+ # Row action button
243
+ ColumnBase(column_name='action', render=[row_button('delete', 'Delete')]),
244
+
245
+ # Lookup-based rendering
246
+ ('id', {'title': 'Status', 'render': [
247
+ {'function': 'ReplaceLookup', 'html': '%1%', 'var': '%1%'}
248
+ ], 'lookup': [[1, 'Active'], [2, 'Inactive']]}),
249
+ )
250
+ ```
251
+
252
+ Available render functions: `Replace`, `ReplaceLookup`, `Html`, `MergeArray`, `ValueInColumn`.
253
+
254
+ ### Plugins
255
+
256
+ ```python
257
+ from django_datatables.plugins.colour_rows import ColourRows
258
+ from django_datatables.plugins.column_totals import ColumnTotals
259
+ from django_datatables.plugins.reorder import Reorder
260
+
261
+ # Conditional row colouring
262
+ table.add_plugin(ColourRows, [
263
+ {'column': 'status', 'values': {'overdue': 'table-danger', 'pending': 'table-warning'}}
264
+ ])
265
+
266
+ # Column totals in footer
267
+ table.add_plugin(ColumnTotals, {
268
+ 'amount': {'sum': True},
269
+ 'id': {'text': 'Total', 'css_class': 'text-danger'},
270
+ 'percentage': {'sum': 'percentage', 'numerator': 'vans', 'denominator': 'total', 'decimal_places': 1},
271
+ })
272
+
273
+ # Drag-and-drop row reordering
274
+ table.add_plugin(Reorder)
275
+ ```
276
+
277
+ ### Inline Editing
278
+
279
+ ```python
280
+ def setup_table(table):
281
+ table.edit_fields = ['first_name', 'title']
282
+ table.edit_options = {'company__name': {'select2': True}}
283
+ ```
284
+
285
+ ### Row Actions (AJAX Commands)
286
+
287
+ Handle row-level actions from buttons:
288
+
289
+ ```python
290
+ class MyView(DatatableView):
291
+ ajax_commands = ['row']
292
+
293
+ def row_delete(self, **kwargs):
294
+ return self.command_response('delete_row', row_no=kwargs['row_no'], table_id=kwargs['table_id'])
295
+
296
+ def row_toggle_tag(self, **kwargs):
297
+ row_data = json.loads(kwargs['row_data'])
298
+ # ... process action ...
299
+ table = self.tables[kwargs['table_id']]
300
+ return table.refresh_row(self.request, kwargs['row_no'])
301
+ ```
302
+
303
+ ### Data Export
304
+
305
+ ```python
306
+ from django_datatables.downloads.excel_download import ExcelDownload
307
+ from django_datatables.downloads.clipboard import ClipboardCopy
308
+
309
+ class MyView(ExcelDownload, ClipboardCopy, DatatableView):
310
+ model = MyModel
311
+
312
+ def setup_menu(self):
313
+ self.add_menu('menu', 'buttons').add_items(
314
+ self.download_menu_item(),
315
+ self.clipboard_menu_item(),
316
+ )
317
+ super().setup_menu()
318
+ ```
319
+
320
+ ### Multiple Tables Per View
321
+
322
+ ```python
323
+ class TwoTableView(DatatableView):
324
+ template_name = 'two_tables.html'
325
+
326
+ def add_tables(self):
327
+ self.add_table('t1', model=Company)
328
+ self.add_table('t2', model=Person)
329
+
330
+ @staticmethod
331
+ def setup_t1(table):
332
+ table.add_columns('id', 'name')
333
+
334
+ @staticmethod
335
+ def setup_t2(table):
336
+ table.add_columns('id', 'first_name')
337
+ ```
338
+
339
+ ### Non-Model Data
340
+
341
+ Load data from any source (JSON files, APIs, etc.):
342
+
343
+ ```python
344
+ class JsonTableView(DatatableView):
345
+
346
+ @staticmethod
347
+ def setup_table(table):
348
+ table.add_columns(
349
+ ColumnBase(column_name='field1'),
350
+ ColumnBase(column_name='field2'),
351
+ )
352
+
353
+ @staticmethod
354
+ def get_table_query(table, **kwargs):
355
+ with open('data.json') as f:
356
+ return json.load(f)
357
+ ```
358
+
359
+ ### Custom Column Classes
360
+
361
+ ```python
362
+ from django_datatables.columns import DatatableColumn
363
+
364
+ class FullName(DatatableColumn):
365
+ def col_setup(self):
366
+ self.field = ['first_name', 'surname']
367
+
368
+ def row_result(self, data_dict, _page_results):
369
+ return f'{data_dict["first_name"]} {data_dict["surname"]}'
370
+ ```
371
+
372
+ ### Table Options
373
+
374
+ Common options passed via `table.table_options`:
375
+
376
+ ```python
377
+ table.table_options['pageLength'] = 50
378
+ table.table_options['no_col_search'] = True
379
+ table.table_options['scrollX'] = True
380
+ table.table_options['ajax_url'] = '/custom/ajax/url/'
381
+ table.table_options['row_href'] = [render_replace(column='id', html='/detail/%1%/')]
382
+ ```
383
+
384
+ ## Demo Application
385
+
386
+ A Docker-based demo is included with sample data and 15+ examples covering filters, plugins, editing, rendering, and more.
387
+
388
+ ```bash
389
+ docker-compose up
390
+ ```
391
+
392
+ Then visit [http://localhost:8006](http://localhost:8006).
393
+
394
+ ## Dependencies
395
+
396
+ - Python >= 3.6
397
+ - Django
398
+ - [ajax-advanced-helpers](https://github.com/django-advance-utils/ajax-advanced-helpers) >= 1.0.1
399
+
400
+ Optional:
401
+ - `openpyxl` -- for Excel export
402
+ - `redis` -- for table caching
403
+
404
+ ## License
405
+
406
+ MIT