django-smartbase-admin 0.2.54__py3-none-any.whl → 1.0.42__py3-none-any.whl

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 (184) hide show
  1. django_smartbase_admin/actions/admin_action_list.py +79 -38
  2. django_smartbase_admin/actions/advanced_filters.py +24 -1
  3. django_smartbase_admin/admin/admin_base.py +402 -97
  4. django_smartbase_admin/admin/site.py +93 -35
  5. django_smartbase_admin/admin/widgets.py +636 -26
  6. django_smartbase_admin/apps.py +2 -0
  7. django_smartbase_admin/engine/actions.py +34 -16
  8. django_smartbase_admin/engine/admin_base_view.py +252 -115
  9. django_smartbase_admin/engine/configuration.py +186 -4
  10. django_smartbase_admin/engine/const.py +6 -0
  11. django_smartbase_admin/engine/dashboard.py +49 -24
  12. django_smartbase_admin/engine/fake_inline.py +15 -11
  13. django_smartbase_admin/engine/field.py +42 -12
  14. django_smartbase_admin/engine/field_formatter.py +38 -14
  15. django_smartbase_admin/engine/filter_widgets.py +348 -24
  16. django_smartbase_admin/engine/menu_item.py +8 -5
  17. django_smartbase_admin/engine/modal_view.py +12 -7
  18. django_smartbase_admin/engine/request.py +2 -0
  19. django_smartbase_admin/integration/__init__.py +0 -0
  20. django_smartbase_admin/integration/django_cms.py +43 -0
  21. django_smartbase_admin/locale/sk/LC_MESSAGES/django.mo +0 -0
  22. django_smartbase_admin/locale/sk/LC_MESSAGES/django.po +268 -37
  23. django_smartbase_admin/migrations/0005_sbadminuserconfiguration.py +26 -0
  24. django_smartbase_admin/migrations/0006_alter_sbadminuserconfiguration_color_scheme.py +18 -0
  25. django_smartbase_admin/models.py +22 -0
  26. django_smartbase_admin/monkeypatch/admin_readonly_field_monkeypatch.py +96 -0
  27. django_smartbase_admin/monkeypatch/fake_inline_monkeypatch.py +1 -1
  28. django_smartbase_admin/querysets.py +3 -0
  29. django_smartbase_admin/services/configuration.py +30 -0
  30. django_smartbase_admin/services/thread_local.py +6 -19
  31. django_smartbase_admin/services/views.py +80 -13
  32. django_smartbase_admin/services/xlsx_export.py +6 -0
  33. django_smartbase_admin/static/sb_admin/build/tailwind.config.js +1 -0
  34. django_smartbase_admin/static/sb_admin/build/tailwind_config_partials/colors.js +4 -0
  35. django_smartbase_admin/static/sb_admin/build/tailwind_config_partials/spacing.js +1 -0
  36. django_smartbase_admin/static/sb_admin/build/webpack.common.js +11 -8
  37. django_smartbase_admin/static/sb_admin/css/ckeditor/ckeditor_content_dark.css +208 -0
  38. django_smartbase_admin/static/sb_admin/css/coloris/coloris.min.css +1 -0
  39. django_smartbase_admin/static/sb_admin/dist/calendar.js +1 -0
  40. django_smartbase_admin/static/sb_admin/dist/calendar_style.css +1 -0
  41. django_smartbase_admin/static/sb_admin/dist/calendar_style.js +0 -0
  42. django_smartbase_admin/static/sb_admin/dist/chart.js +1 -1
  43. django_smartbase_admin/static/sb_admin/dist/main.js +1 -1
  44. django_smartbase_admin/static/sb_admin/dist/main_style.css +1 -1
  45. django_smartbase_admin/static/sb_admin/dist/table.js +1 -1
  46. django_smartbase_admin/static/sb_admin/dist/tree_widget.js +1 -0
  47. django_smartbase_admin/static/sb_admin/dist/tree_widget_style.css +1 -0
  48. django_smartbase_admin/static/sb_admin/dist/tree_widget_style.js +0 -0
  49. django_smartbase_admin/static/sb_admin/fancytree/jquery.fancytree-all-deps.min.js +1 -0
  50. django_smartbase_admin/static/sb_admin/images/file_types/file-csv.svg +11 -0
  51. django_smartbase_admin/static/sb_admin/images/file_types/file-doc.svg +11 -0
  52. django_smartbase_admin/static/sb_admin/images/file_types/file-docx.svg +11 -0
  53. django_smartbase_admin/static/sb_admin/images/file_types/file-other.svg +13 -0
  54. django_smartbase_admin/static/sb_admin/images/file_types/file-pdf.svg +11 -0
  55. django_smartbase_admin/static/sb_admin/images/file_types/file-ppt.svg +11 -0
  56. django_smartbase_admin/static/sb_admin/images/file_types/file-xls.svg +11 -0
  57. django_smartbase_admin/static/sb_admin/images/file_types/file-xlsx.svg +11 -0
  58. django_smartbase_admin/static/sb_admin/images/file_types/file-zip.svg +18 -0
  59. django_smartbase_admin/static/sb_admin/images/flags/de-at.png +0 -0
  60. django_smartbase_admin/static/sb_admin/images/flags/de-ch.png +0 -0
  61. django_smartbase_admin/static/sb_admin/images/logo_light.svg +21 -0
  62. django_smartbase_admin/static/sb_admin/js/coloris/coloris.min.js +6 -0
  63. django_smartbase_admin/static/sb_admin/js/fullcalendar.min.js +14804 -0
  64. django_smartbase_admin/static/sb_admin/js/sbadmin_prepopulated_fields_init.js +25 -0
  65. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Bolt-one.svg +3 -0
  66. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Calendar.svg +3 -0
  67. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Caution.svg +3 -0
  68. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Electric-drill.svg +3 -0
  69. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Fire-extinguisher.svg +3 -0
  70. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Gas.svg +3 -0
  71. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Lightning-fill.svg +3 -0
  72. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Moon.svg +3 -0
  73. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Phone-telephone.svg +3 -0
  74. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Printer.svg +3 -0
  75. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Pull.svg +3 -0
  76. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Sun-one.svg +3 -0
  77. django_smartbase_admin/static/sb_admin/sprites/sb_admin/Time.svg +3 -0
  78. django_smartbase_admin/static/sb_admin/src/css/_base.css +5 -1
  79. django_smartbase_admin/static/sb_admin/src/css/_colors.css +257 -82
  80. django_smartbase_admin/static/sb_admin/src/css/_components.css +61 -13
  81. django_smartbase_admin/static/sb_admin/src/css/_datepicker.css +8 -1
  82. django_smartbase_admin/static/sb_admin/src/css/_filer.css +60 -0
  83. django_smartbase_admin/static/sb_admin/src/css/_inlines.css +51 -10
  84. django_smartbase_admin/static/sb_admin/src/css/_tabulator.css +8 -2
  85. django_smartbase_admin/static/sb_admin/src/css/calendar.css +162 -0
  86. django_smartbase_admin/static/sb_admin/src/css/components/_button.css +41 -1
  87. django_smartbase_admin/static/sb_admin/src/css/components/_dropdown.css +31 -7
  88. django_smartbase_admin/static/sb_admin/src/css/components/_input.css +62 -20
  89. django_smartbase_admin/static/sb_admin/src/css/components/_modal.css +1 -1
  90. django_smartbase_admin/static/sb_admin/src/css/components/_query-builder.css +21 -2
  91. django_smartbase_admin/static/sb_admin/src/css/components/_toggle.css +12 -1
  92. django_smartbase_admin/static/sb_admin/src/css/components/_tooltip.css +8 -22
  93. django_smartbase_admin/static/sb_admin/src/css/style.css +17 -0
  94. django_smartbase_admin/static/sb_admin/src/css/tree_widget.css +411 -0
  95. django_smartbase_admin/static/sb_admin/src/js/autocomplete.js +69 -11
  96. django_smartbase_admin/static/sb_admin/src/js/calendar.js +56 -0
  97. django_smartbase_admin/static/sb_admin/src/js/chart.js +8 -22
  98. django_smartbase_admin/static/sb_admin/src/js/choices.js +18 -8
  99. django_smartbase_admin/static/sb_admin/src/js/datepicker.js +97 -336
  100. django_smartbase_admin/static/sb_admin/src/js/datepicker_plugins.js +357 -0
  101. django_smartbase_admin/static/sb_admin/src/js/main.js +306 -31
  102. django_smartbase_admin/static/sb_admin/src/js/multiselect.js +50 -41
  103. django_smartbase_admin/static/sb_admin/src/js/radio.js +31 -0
  104. django_smartbase_admin/static/sb_admin/src/js/range.js +3 -2
  105. django_smartbase_admin/static/sb_admin/src/js/table.js +34 -5
  106. django_smartbase_admin/static/sb_admin/src/js/table_modules/advanced_filter_module.js +43 -20
  107. django_smartbase_admin/static/sb_admin/src/js/table_modules/data_edit_module.js +8 -10
  108. django_smartbase_admin/static/sb_admin/src/js/table_modules/detail_view_module.js +50 -1
  109. django_smartbase_admin/static/sb_admin/src/js/table_modules/filter_module.js +10 -3
  110. django_smartbase_admin/static/sb_admin/src/js/table_modules/header_tabs_module.js +11 -11
  111. django_smartbase_admin/static/sb_admin/src/js/table_modules/selection_module.js +28 -8
  112. django_smartbase_admin/static/sb_admin/src/js/table_modules/table_params_module.js +6 -0
  113. django_smartbase_admin/static/sb_admin/src/js/table_modules/views_module.js +6 -0
  114. django_smartbase_admin/static/sb_admin/src/js/tree_widget.js +406 -0
  115. django_smartbase_admin/static/sb_admin/src/js/utils.js +56 -21
  116. django_smartbase_admin/templates/sb_admin/actions/change_form.html +176 -116
  117. django_smartbase_admin/templates/sb_admin/actions/dashboard.html +2 -2
  118. django_smartbase_admin/templates/sb_admin/actions/list.html +79 -39
  119. django_smartbase_admin/templates/sb_admin/actions/partials/action_link.html +14 -0
  120. django_smartbase_admin/templates/sb_admin/actions/partials/tabulator_header_v2.html +2 -2
  121. django_smartbase_admin/templates/sb_admin/actions/tree_list.html +63 -0
  122. django_smartbase_admin/templates/sb_admin/authentification/login_base.html +5 -1
  123. django_smartbase_admin/templates/sb_admin/components/columns.html +1 -1
  124. django_smartbase_admin/templates/sb_admin/components/filters.html +1 -0
  125. django_smartbase_admin/templates/sb_admin/components/filters_v2.html +99 -85
  126. django_smartbase_admin/templates/sb_admin/dashboard/calendar_widget.html +69 -0
  127. django_smartbase_admin/templates/sb_admin/dashboard/chart_widget.html +21 -2
  128. django_smartbase_admin/templates/sb_admin/dashboard/list_widget.html +6 -0
  129. django_smartbase_admin/templates/sb_admin/dashboard/widget_base.html +1 -1
  130. django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/date_field.html +18 -8
  131. django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/multiple_choice_field.html +1 -1
  132. django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/tree_select_filter.html +2 -0
  133. django_smartbase_admin/templates/sb_admin/filter_widgets/boolean_field.html +1 -14
  134. django_smartbase_admin/templates/sb_admin/filter_widgets/date_field.html +18 -4
  135. django_smartbase_admin/templates/sb_admin/filter_widgets/multiple_choice_field.html +14 -0
  136. django_smartbase_admin/templates/sb_admin/filter_widgets/partials/clear.html +12 -6
  137. django_smartbase_admin/templates/sb_admin/filter_widgets/radio_choice_field.html +5 -3
  138. django_smartbase_admin/templates/sb_admin/filter_widgets/tree_select_filter.html +16 -0
  139. django_smartbase_admin/templates/sb_admin/includes/change_form_title.html +3 -1
  140. django_smartbase_admin/templates/sb_admin/includes/inline_fieldset.html +48 -39
  141. django_smartbase_admin/templates/sb_admin/includes/notifications.html +2 -1
  142. django_smartbase_admin/templates/sb_admin/includes/readonly_boolean_field.html +9 -0
  143. django_smartbase_admin/templates/sb_admin/includes/readonly_field.html +12 -0
  144. django_smartbase_admin/templates/sb_admin/includes/table_inline_delete_button.html +4 -5
  145. django_smartbase_admin/templates/sb_admin/inlines/stacked_inline.html +68 -40
  146. django_smartbase_admin/templates/sb_admin/inlines/table_inline.html +76 -34
  147. django_smartbase_admin/templates/sb_admin/integrations/filer/folder_list.html +18 -0
  148. django_smartbase_admin/templates/sb_admin/navigation.html +166 -158
  149. django_smartbase_admin/templates/sb_admin/partials/modal/modal_content.html +2 -6
  150. django_smartbase_admin/templates/sb_admin/sb_admin_base.html +49 -4
  151. django_smartbase_admin/templates/sb_admin/sb_admin_base_no_sidebar.html +27 -11
  152. django_smartbase_admin/templates/sb_admin/sb_admin_js_trans.html +3 -0
  153. django_smartbase_admin/templates/sb_admin/sprites/sb_admin.svg +1 -1
  154. django_smartbase_admin/templates/sb_admin/tailwind_whitelist.html +6 -3
  155. django_smartbase_admin/templates/sb_admin/widgets/array.html +0 -1
  156. django_smartbase_admin/templates/sb_admin/widgets/attributes.html +68 -0
  157. django_smartbase_admin/templates/sb_admin/widgets/autocomplete.html +13 -2
  158. django_smartbase_admin/templates/sb_admin/widgets/{checkbox_select.html → checkbox_dropdown.html} +2 -2
  159. django_smartbase_admin/templates/sb_admin/widgets/clearable_file_input.html +2 -2
  160. django_smartbase_admin/templates/sb_admin/widgets/color_field.html +30 -0
  161. django_smartbase_admin/templates/sb_admin/widgets/date.html +8 -1
  162. django_smartbase_admin/templates/sb_admin/widgets/filer_file.html +84 -0
  163. django_smartbase_admin/templates/sb_admin/widgets/includes/related_item_buttons.html +38 -0
  164. django_smartbase_admin/templates/sb_admin/widgets/multiwidget.html +1 -1
  165. django_smartbase_admin/templates/sb_admin/widgets/radio.html +3 -2
  166. django_smartbase_admin/templates/sb_admin/widgets/radio_dropdown.html +30 -0
  167. django_smartbase_admin/templates/sb_admin/widgets/read_only_password_hash.html +3 -0
  168. django_smartbase_admin/templates/sb_admin/widgets/time.html +8 -1
  169. django_smartbase_admin/templates/sb_admin/widgets/toggle.html +1 -1
  170. django_smartbase_admin/templates/sb_admin/widgets/tree_base.html +59 -0
  171. django_smartbase_admin/templates/sb_admin/widgets/tree_select.html +24 -0
  172. django_smartbase_admin/templates/sb_admin/widgets/tree_select_inline.html +12 -0
  173. django_smartbase_admin/templatetags/sb_admin_tags.py +115 -4
  174. django_smartbase_admin/utils.py +22 -3
  175. django_smartbase_admin/views/dashboard_view.py +6 -0
  176. django_smartbase_admin/views/global_filter_view.py +8 -2
  177. django_smartbase_admin/views/translations_view.py +12 -5
  178. django_smartbase_admin/views/user_config_view.py +52 -0
  179. django_smartbase_admin-1.0.42.dist-info/METADATA +166 -0
  180. {django_smartbase_admin-0.2.54.dist-info → django_smartbase_admin-1.0.42.dist-info}/RECORD +182 -118
  181. {django_smartbase_admin-0.2.54.dist-info → django_smartbase_admin-1.0.42.dist-info}/WHEEL +1 -1
  182. django_smartbase_admin/templates/sb_admin/integrations/sorting/change_list.html +0 -401
  183. django_smartbase_admin-0.2.54.dist-info/METADATA +0 -25
  184. {django_smartbase_admin-0.2.54.dist-info → django_smartbase_admin-1.0.42.dist-info}/LICENSE.md +0 -0
@@ -1,12 +1,14 @@
1
+ from __future__ import annotations
1
2
  import json
2
3
  import math
4
+ from typing import Any, TYPE_CHECKING
3
5
 
4
- from django.core.paginator import Paginator
5
6
  from django.db.models import Q
6
7
  from django.utils import timezone
8
+ from django.utils.html import escape
9
+ from django.utils.safestring import SafeString
7
10
  from django.utils.text import smart_split, unescape_string_literal
8
11
 
9
- from django_smartbase_admin.engine.actions import SBAdminAction
10
12
  from django_smartbase_admin.engine.const import (
11
13
  XLSX_PAGE_CHUNK_SIZE,
12
14
  SELECTED_ROWS_KWARG_NAME,
@@ -32,8 +34,8 @@ from django_smartbase_admin.engine.const import (
32
34
  CONFIG_NAME,
33
35
  TABLE_PARAMS_FULL_TEXT_SEARCH,
34
36
  TABLE_PARAMS_SELECTED_FILTER_TYPE,
35
- FilterVersions,
36
37
  ADVANCED_FILTER_DATA_NAME,
38
+ IGNORE_LIST_SELECTION,
37
39
  )
38
40
  from django_smartbase_admin.services.views import SBAdminViewService
39
41
  from django_smartbase_admin.utils import import_with_injection
@@ -42,6 +44,19 @@ QueryBuilderService = import_with_injection(
42
44
  "django_smartbase_admin.actions.advanced_filters", "QueryBuilderService"
43
45
  )
44
46
 
47
+ if TYPE_CHECKING:
48
+ from django_smartbase_admin.engine.field import SBAdminField
49
+
50
+
51
+ class SBAdminAction(object):
52
+ view = None
53
+ threadsafe_request = None
54
+
55
+ def __init__(self, view, request) -> None:
56
+ super().__init__()
57
+ self.view = view
58
+ self.threadsafe_request = request
59
+
45
60
 
46
61
  class SBAdminListAction(SBAdminAction):
47
62
  def __init__(
@@ -83,7 +98,7 @@ class SBAdminListAction(SBAdminAction):
83
98
  )
84
99
  self.deselected_rows = self.selection_data.get(DESELECTED_ROWS_KWARG_NAME, [])
85
100
  self.page_size = page_size or self.table_params.get(
86
- TABLE_PARAMS_SIZE_NAME, self.view.get_list_per_page()
101
+ TABLE_PARAMS_SIZE_NAME, self.view.get_list_per_page(request)
87
102
  )
88
103
  self.init_column_fields()
89
104
  self.tabulator_definition = tabulator_definition
@@ -132,11 +147,6 @@ class SBAdminListAction(SBAdminAction):
132
147
  if field.field in values
133
148
  ]
134
149
 
135
- def is_jquery_required(self, request):
136
- return (
137
- self.view.get_filters_version(request) == FilterVersions.FILTERS_VERSION_2
138
- )
139
-
140
150
  def get_template_data(self):
141
151
  context_data = self.view.get_context_data(self.threadsafe_request)
142
152
  constants = {
@@ -175,7 +185,9 @@ class SBAdminListAction(SBAdminAction):
175
185
  tabulator_definition["tableIdColumnName"] = id_column_name
176
186
  tabulator_definition["constants"] = constants
177
187
 
178
- list_actions = self.list_actions or self.view._get_sbadmin_list_actions()
188
+ list_actions = self.list_actions or self.view._get_sbadmin_list_actions(
189
+ self.threadsafe_request
190
+ )
179
191
 
180
192
  context_data.update(
181
193
  {
@@ -183,7 +195,6 @@ class SBAdminListAction(SBAdminAction):
183
195
  "tabulator_definition": tabulator_definition,
184
196
  "id_column_name": id_column_name,
185
197
  "filters": self.get_filters(),
186
- "is_jquery_required": self.is_jquery_required(self.threadsafe_request),
187
198
  "advanced_filters_data": QueryBuilderService.get_advanced_filters_context_data(
188
199
  self
189
200
  ),
@@ -194,16 +205,18 @@ class SBAdminListAction(SBAdminAction):
194
205
  self.threadsafe_request
195
206
  ),
196
207
  "search_fields": self.view.get_search_fields(self.threadsafe_request),
197
- "search_field_placeholder": self.view.get_search_field_placeholder(),
198
- "list_actions": self.view.process_actions_permissions(
208
+ "search_field_placeholder": self.view.get_search_field_placeholder(
209
+ self.threadsafe_request
210
+ ),
211
+ "list_actions": self.view.process_actions(
199
212
  self.threadsafe_request, list_actions
200
213
  ),
201
214
  "list_selection_actions": self.view.get_sbadmin_list_selection_actions_grouped(
202
215
  self.threadsafe_request
203
216
  ),
204
- "config_url": self.view.get_config_url(),
217
+ "config_url": self.view.get_config_url(self.threadsafe_request),
205
218
  "new_url": (
206
- self.view.get_new_url()
219
+ self.view.get_new_url(self.threadsafe_request)
207
220
  if self.view.has_add_permission(self.threadsafe_request)
208
221
  else None
209
222
  ),
@@ -217,9 +230,23 @@ class SBAdminListAction(SBAdminAction):
217
230
  for sort in self.table_params.get("sort", []):
218
231
  order_by.append(f"{'-' if sort['dir'] == 'desc' else ''}{sort['field']}")
219
232
  if len(order_by) == 0:
220
- order_by = self.view.get_list_ordering() or [self.get_pk_field().name]
233
+ order_by = self.view.get_list_ordering(self.threadsafe_request) or [
234
+ self.get_pk_field().name
235
+ ]
221
236
  return order_by
222
237
 
238
+ def get_order_by_fields_from_request(self):
239
+ order_by = self.get_order_by_from_request()
240
+ order_by_fields = []
241
+ order_by_fields_names = set()
242
+ for field in order_by:
243
+ field_name = field[1:] if field.startswith("-") else field
244
+ order_by_fields_names.add(field_name)
245
+ for field in self.column_fields:
246
+ if field.name in order_by_fields_names:
247
+ order_by_fields.append(field)
248
+ return order_by_fields
249
+
223
250
  def get_filter_from_request(self):
224
251
  base_filters = SBAdminViewService.get_filter_from_request(
225
252
  self.threadsafe_request, self.column_fields, self.filter_data
@@ -246,6 +273,7 @@ class SBAdminListAction(SBAdminAction):
246
273
  filter_fields.extend(
247
274
  QueryBuilderService.get_filters_fields_for_list_action(self)
248
275
  )
276
+ filter_fields.extend(self.get_order_by_fields_from_request())
249
277
  if self.is_search_query():
250
278
  search_fields = self.get_search_fields(self.threadsafe_request)
251
279
  filter_fields.extend(search_fields)
@@ -264,7 +292,7 @@ class SBAdminListAction(SBAdminAction):
264
292
  **self.get_annotates(visible_fields)
265
293
  )
266
294
 
267
- def get_visible_column_fields(self):
295
+ def get_visible_column_fields(self) -> list[SBAdminField]:
268
296
  columns_data_dict = self.columns_data.get(COLUMNS_DATA_COLUMNS_NAME, {})
269
297
  return [
270
298
  field
@@ -281,8 +309,15 @@ class SBAdminListAction(SBAdminAction):
281
309
  values = [self.get_pk_field().name]
282
310
  visible_column_fields = self.get_visible_column_fields()
283
311
  values.extend([field.field for field in visible_column_fields])
312
+ # Include supporting_annotates keys for visible columns
313
+ for field in visible_column_fields:
314
+ if field.supporting_annotates:
315
+ values.extend(field.supporting_annotates.keys())
284
316
  if self.view.sbadmin_list_display_data:
285
317
  values.extend(self.view.sbadmin_list_display_data)
318
+ values.extend(
319
+ [field.field for field in self.get_order_by_fields_from_request()]
320
+ )
286
321
  return values
287
322
 
288
323
  def get_search_results(self, request, queryset, search_term):
@@ -379,32 +414,33 @@ class SBAdminListAction(SBAdminAction):
379
414
  "last_row": total_count,
380
415
  }
381
416
 
382
- def process_final_data(self, final_data):
417
+ def process_final_data(self, final_data: list[dict[str, Any]]) -> None:
383
418
  visible_columns = self.get_visible_column_fields()
384
- fields_with_methods_to_call = [
385
- field
386
- for field in visible_columns
387
- if field.view_method or field.python_formatter
388
- ]
419
+ field_key_field_map: dict[str, SBAdminField] = {
420
+ field.field: field for field in visible_columns
421
+ }
389
422
  for row in final_data:
423
+ obj_id = row.get(self.get_pk_field().name, None)
390
424
  additional_data = {}
391
425
  if self.view.sbadmin_list_display_data:
392
426
  additional_data = {
393
427
  data: row.get(data, None)
394
428
  for data in self.view.sbadmin_list_display_data
395
429
  }
396
- for field in fields_with_methods_to_call:
397
- object_id = row.get(self.get_pk_field().name, None)
398
- value = row.get(field.field, None)
399
- processed_value = value
400
- if field.view_method:
401
- processed_value = field.view_method(
402
- object_id, value, **additional_data
430
+ # Include supporting_annotates values in additional_data
431
+ for field in visible_columns:
432
+ if field.supporting_annotates:
433
+ for key in field.supporting_annotates.keys():
434
+ additional_data[key] = row.get(key, None)
435
+ for field_key, value in row.items():
436
+ if field_key in field_key_field_map:
437
+ field = field_key_field_map[field_key]
438
+ value = self.view.process_field_data(
439
+ self.threadsafe_request, field, obj_id, value, additional_data
403
440
  )
404
- formatted_value = processed_value
405
- if field.python_formatter:
406
- formatted_value = field.python_formatter(object_id, processed_value)
407
- row[field.field] = formatted_value
441
+ if isinstance(value, str) and not isinstance(value, SafeString):
442
+ value = escape(value)
443
+ row[field_key] = value
408
444
 
409
445
  def get_json_data(self):
410
446
  return self.get_data()
@@ -419,6 +455,9 @@ class SBAdminListAction(SBAdminAction):
419
455
  return final_data
420
456
 
421
457
  def get_selection_queryset(self):
458
+ if not self.selection_data:
459
+ # don't run with no selection data as it will result in querying all records
460
+ return Q(id__in=[])
422
461
  additional_filter = None
423
462
  if self.selected_rows and self.selected_rows != SELECT_ALL_KEYWORD:
424
463
  additional_filter = Q(id__in=self.selected_rows)
@@ -427,13 +466,15 @@ class SBAdminListAction(SBAdminAction):
427
466
  additional_filter = ~Q(id__in=self.deselected_rows)
428
467
  return additional_filter
429
468
 
430
- def get_xlsx_data(self):
469
+ def get_xlsx_data(self, request):
431
470
  page_size = XLSX_PAGE_CHUNK_SIZE
432
471
  file_name = (
433
472
  f'{self.view.get_menu_label()}__{timezone.now().strftime("%Y-%m-%d")}.xlsx'
434
473
  )
435
474
  columns = self.get_excel_columns()
436
- additional_filter = self.get_selection_queryset()
475
+ additional_filter = Q()
476
+ if request.request_data.modifier != IGNORE_LIST_SELECTION:
477
+ additional_filter = self.get_selection_queryset()
437
478
  data_list = []
438
479
  report_data = self.get_data(
439
480
  page_size=page_size,
@@ -450,8 +491,8 @@ class SBAdminListAction(SBAdminAction):
450
491
  )["data"]
451
492
  )
452
493
  options = (
453
- self.view.get_sbadmin_xlsx_options().to_json()
454
- if self.view.get_sbadmin_xlsx_options()
494
+ self.view.get_sbadmin_xlsx_options(request).to_json()
495
+ if self.view.get_sbadmin_xlsx_options(request)
455
496
  else {}
456
497
  )
457
498
  return [file_name, data_list, columns, options]
@@ -5,7 +5,7 @@ from dataclasses import field as dataclass_field
5
5
  from typing import List, Optional, TYPE_CHECKING
6
6
 
7
7
  from django.db import models
8
- from django.db.models import Q
8
+ from django.db.models import Q, Count
9
9
  from django.template.loader import render_to_string
10
10
  from django.utils.translation import gettext_lazy as _
11
11
 
@@ -45,6 +45,8 @@ class AllOperators(models.TextChoices):
45
45
  IS_NOT_NULL = "is_not_null", _("Is not null")
46
46
  BEFORE = "before", _("Before")
47
47
  AFTER = "after", _("After")
48
+ IN_THE_LAST = "in_the_last", _("In the last")
49
+ IN_THE_NEXT = "in_the_next", _("In the next")
48
50
 
49
51
 
50
52
  NULL_ATTRIBUTES = [
@@ -59,6 +61,8 @@ DATE_ATTRIBUTES = [
59
61
  AllOperators.AFTER,
60
62
  AllOperators.IS_NULL,
61
63
  AllOperators.IS_NOT_NULL,
64
+ AllOperators.IN_THE_LAST,
65
+ AllOperators.IN_THE_NEXT,
62
66
  ]
63
67
 
64
68
  NUMBER_ATTRIBUTES = [
@@ -157,6 +161,8 @@ class QueryBuilderService:
157
161
  AllOperators.IS_NOT_NULL.value: "__isnull",
158
162
  AllOperators.BEFORE.value: "__lt",
159
163
  AllOperators.AFTER.value: "__gte",
164
+ AllOperators.IN_THE_LAST.value: "__range",
165
+ AllOperators.IN_THE_NEXT.value: "__range",
160
166
  }
161
167
 
162
168
  ZERO_INPUTS_OPERATORS = {
@@ -252,11 +258,28 @@ class QueryBuilderService:
252
258
  if operator in [AllOperators.IS_NULL, AllOperators.IS_NOT_NULL]
253
259
  else ""
254
260
  )
261
+ if field.annotate and isinstance(field.annotate, Count):
262
+ filter_value = 0
255
263
  q = Q(
256
264
  **{
257
265
  f"{field.filter_field}{cls.OPERATOR_MAP[operator]}": filter_value,
258
266
  }
259
267
  )
268
+ from django_smartbase_admin.engine.filter_widgets import (
269
+ StringFilterWidget,
270
+ )
271
+
272
+ if isinstance(
273
+ field.filter_widget, StringFilterWidget
274
+ ) and operator in [
275
+ AllOperators.IS_EMPTY,
276
+ AllOperators.IS_NOT_EMPTY,
277
+ ]:
278
+ q = q | Q(
279
+ **{
280
+ f"{field.filter_field}{cls.OPERATOR_MAP[AllOperators.IS_NULL]}": True
281
+ }
282
+ )
260
283
  else:
261
284
  value = field.filter_widget.parse_value_from_input(
262
285
  request, rule["value"]