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.
- django_smartbase_admin/actions/admin_action_list.py +79 -38
- django_smartbase_admin/actions/advanced_filters.py +24 -1
- django_smartbase_admin/admin/admin_base.py +402 -97
- django_smartbase_admin/admin/site.py +93 -35
- django_smartbase_admin/admin/widgets.py +636 -26
- django_smartbase_admin/apps.py +2 -0
- django_smartbase_admin/engine/actions.py +34 -16
- django_smartbase_admin/engine/admin_base_view.py +252 -115
- django_smartbase_admin/engine/configuration.py +186 -4
- django_smartbase_admin/engine/const.py +6 -0
- django_smartbase_admin/engine/dashboard.py +49 -24
- django_smartbase_admin/engine/fake_inline.py +15 -11
- django_smartbase_admin/engine/field.py +42 -12
- django_smartbase_admin/engine/field_formatter.py +38 -14
- django_smartbase_admin/engine/filter_widgets.py +348 -24
- django_smartbase_admin/engine/menu_item.py +8 -5
- django_smartbase_admin/engine/modal_view.py +12 -7
- django_smartbase_admin/engine/request.py +2 -0
- django_smartbase_admin/integration/__init__.py +0 -0
- django_smartbase_admin/integration/django_cms.py +43 -0
- django_smartbase_admin/locale/sk/LC_MESSAGES/django.mo +0 -0
- django_smartbase_admin/locale/sk/LC_MESSAGES/django.po +268 -37
- django_smartbase_admin/migrations/0005_sbadminuserconfiguration.py +26 -0
- django_smartbase_admin/migrations/0006_alter_sbadminuserconfiguration_color_scheme.py +18 -0
- django_smartbase_admin/models.py +22 -0
- django_smartbase_admin/monkeypatch/admin_readonly_field_monkeypatch.py +96 -0
- django_smartbase_admin/monkeypatch/fake_inline_monkeypatch.py +1 -1
- django_smartbase_admin/querysets.py +3 -0
- django_smartbase_admin/services/configuration.py +30 -0
- django_smartbase_admin/services/thread_local.py +6 -19
- django_smartbase_admin/services/views.py +80 -13
- django_smartbase_admin/services/xlsx_export.py +6 -0
- django_smartbase_admin/static/sb_admin/build/tailwind.config.js +1 -0
- django_smartbase_admin/static/sb_admin/build/tailwind_config_partials/colors.js +4 -0
- django_smartbase_admin/static/sb_admin/build/tailwind_config_partials/spacing.js +1 -0
- django_smartbase_admin/static/sb_admin/build/webpack.common.js +11 -8
- django_smartbase_admin/static/sb_admin/css/ckeditor/ckeditor_content_dark.css +208 -0
- django_smartbase_admin/static/sb_admin/css/coloris/coloris.min.css +1 -0
- django_smartbase_admin/static/sb_admin/dist/calendar.js +1 -0
- django_smartbase_admin/static/sb_admin/dist/calendar_style.css +1 -0
- django_smartbase_admin/static/sb_admin/dist/calendar_style.js +0 -0
- django_smartbase_admin/static/sb_admin/dist/chart.js +1 -1
- django_smartbase_admin/static/sb_admin/dist/main.js +1 -1
- django_smartbase_admin/static/sb_admin/dist/main_style.css +1 -1
- django_smartbase_admin/static/sb_admin/dist/table.js +1 -1
- django_smartbase_admin/static/sb_admin/dist/tree_widget.js +1 -0
- django_smartbase_admin/static/sb_admin/dist/tree_widget_style.css +1 -0
- django_smartbase_admin/static/sb_admin/dist/tree_widget_style.js +0 -0
- django_smartbase_admin/static/sb_admin/fancytree/jquery.fancytree-all-deps.min.js +1 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-csv.svg +11 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-doc.svg +11 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-docx.svg +11 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-other.svg +13 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-pdf.svg +11 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-ppt.svg +11 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-xls.svg +11 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-xlsx.svg +11 -0
- django_smartbase_admin/static/sb_admin/images/file_types/file-zip.svg +18 -0
- django_smartbase_admin/static/sb_admin/images/flags/de-at.png +0 -0
- django_smartbase_admin/static/sb_admin/images/flags/de-ch.png +0 -0
- django_smartbase_admin/static/sb_admin/images/logo_light.svg +21 -0
- django_smartbase_admin/static/sb_admin/js/coloris/coloris.min.js +6 -0
- django_smartbase_admin/static/sb_admin/js/fullcalendar.min.js +14804 -0
- django_smartbase_admin/static/sb_admin/js/sbadmin_prepopulated_fields_init.js +25 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Bolt-one.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Calendar.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Caution.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Electric-drill.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Fire-extinguisher.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Gas.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Lightning-fill.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Moon.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Phone-telephone.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Printer.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Pull.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Sun-one.svg +3 -0
- django_smartbase_admin/static/sb_admin/sprites/sb_admin/Time.svg +3 -0
- django_smartbase_admin/static/sb_admin/src/css/_base.css +5 -1
- django_smartbase_admin/static/sb_admin/src/css/_colors.css +257 -82
- django_smartbase_admin/static/sb_admin/src/css/_components.css +61 -13
- django_smartbase_admin/static/sb_admin/src/css/_datepicker.css +8 -1
- django_smartbase_admin/static/sb_admin/src/css/_filer.css +60 -0
- django_smartbase_admin/static/sb_admin/src/css/_inlines.css +51 -10
- django_smartbase_admin/static/sb_admin/src/css/_tabulator.css +8 -2
- django_smartbase_admin/static/sb_admin/src/css/calendar.css +162 -0
- django_smartbase_admin/static/sb_admin/src/css/components/_button.css +41 -1
- django_smartbase_admin/static/sb_admin/src/css/components/_dropdown.css +31 -7
- django_smartbase_admin/static/sb_admin/src/css/components/_input.css +62 -20
- django_smartbase_admin/static/sb_admin/src/css/components/_modal.css +1 -1
- django_smartbase_admin/static/sb_admin/src/css/components/_query-builder.css +21 -2
- django_smartbase_admin/static/sb_admin/src/css/components/_toggle.css +12 -1
- django_smartbase_admin/static/sb_admin/src/css/components/_tooltip.css +8 -22
- django_smartbase_admin/static/sb_admin/src/css/style.css +17 -0
- django_smartbase_admin/static/sb_admin/src/css/tree_widget.css +411 -0
- django_smartbase_admin/static/sb_admin/src/js/autocomplete.js +69 -11
- django_smartbase_admin/static/sb_admin/src/js/calendar.js +56 -0
- django_smartbase_admin/static/sb_admin/src/js/chart.js +8 -22
- django_smartbase_admin/static/sb_admin/src/js/choices.js +18 -8
- django_smartbase_admin/static/sb_admin/src/js/datepicker.js +97 -336
- django_smartbase_admin/static/sb_admin/src/js/datepicker_plugins.js +357 -0
- django_smartbase_admin/static/sb_admin/src/js/main.js +306 -31
- django_smartbase_admin/static/sb_admin/src/js/multiselect.js +50 -41
- django_smartbase_admin/static/sb_admin/src/js/radio.js +31 -0
- django_smartbase_admin/static/sb_admin/src/js/range.js +3 -2
- django_smartbase_admin/static/sb_admin/src/js/table.js +34 -5
- django_smartbase_admin/static/sb_admin/src/js/table_modules/advanced_filter_module.js +43 -20
- django_smartbase_admin/static/sb_admin/src/js/table_modules/data_edit_module.js +8 -10
- django_smartbase_admin/static/sb_admin/src/js/table_modules/detail_view_module.js +50 -1
- django_smartbase_admin/static/sb_admin/src/js/table_modules/filter_module.js +10 -3
- django_smartbase_admin/static/sb_admin/src/js/table_modules/header_tabs_module.js +11 -11
- django_smartbase_admin/static/sb_admin/src/js/table_modules/selection_module.js +28 -8
- django_smartbase_admin/static/sb_admin/src/js/table_modules/table_params_module.js +6 -0
- django_smartbase_admin/static/sb_admin/src/js/table_modules/views_module.js +6 -0
- django_smartbase_admin/static/sb_admin/src/js/tree_widget.js +406 -0
- django_smartbase_admin/static/sb_admin/src/js/utils.js +56 -21
- django_smartbase_admin/templates/sb_admin/actions/change_form.html +176 -116
- django_smartbase_admin/templates/sb_admin/actions/dashboard.html +2 -2
- django_smartbase_admin/templates/sb_admin/actions/list.html +79 -39
- django_smartbase_admin/templates/sb_admin/actions/partials/action_link.html +14 -0
- django_smartbase_admin/templates/sb_admin/actions/partials/tabulator_header_v2.html +2 -2
- django_smartbase_admin/templates/sb_admin/actions/tree_list.html +63 -0
- django_smartbase_admin/templates/sb_admin/authentification/login_base.html +5 -1
- django_smartbase_admin/templates/sb_admin/components/columns.html +1 -1
- django_smartbase_admin/templates/sb_admin/components/filters.html +1 -0
- django_smartbase_admin/templates/sb_admin/components/filters_v2.html +99 -85
- django_smartbase_admin/templates/sb_admin/dashboard/calendar_widget.html +69 -0
- django_smartbase_admin/templates/sb_admin/dashboard/chart_widget.html +21 -2
- django_smartbase_admin/templates/sb_admin/dashboard/list_widget.html +6 -0
- django_smartbase_admin/templates/sb_admin/dashboard/widget_base.html +1 -1
- django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/date_field.html +18 -8
- django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/multiple_choice_field.html +1 -1
- django_smartbase_admin/templates/sb_admin/filter_widgets/advanced_filters/tree_select_filter.html +2 -0
- django_smartbase_admin/templates/sb_admin/filter_widgets/boolean_field.html +1 -14
- django_smartbase_admin/templates/sb_admin/filter_widgets/date_field.html +18 -4
- django_smartbase_admin/templates/sb_admin/filter_widgets/multiple_choice_field.html +14 -0
- django_smartbase_admin/templates/sb_admin/filter_widgets/partials/clear.html +12 -6
- django_smartbase_admin/templates/sb_admin/filter_widgets/radio_choice_field.html +5 -3
- django_smartbase_admin/templates/sb_admin/filter_widgets/tree_select_filter.html +16 -0
- django_smartbase_admin/templates/sb_admin/includes/change_form_title.html +3 -1
- django_smartbase_admin/templates/sb_admin/includes/inline_fieldset.html +48 -39
- django_smartbase_admin/templates/sb_admin/includes/notifications.html +2 -1
- django_smartbase_admin/templates/sb_admin/includes/readonly_boolean_field.html +9 -0
- django_smartbase_admin/templates/sb_admin/includes/readonly_field.html +12 -0
- django_smartbase_admin/templates/sb_admin/includes/table_inline_delete_button.html +4 -5
- django_smartbase_admin/templates/sb_admin/inlines/stacked_inline.html +68 -40
- django_smartbase_admin/templates/sb_admin/inlines/table_inline.html +76 -34
- django_smartbase_admin/templates/sb_admin/integrations/filer/folder_list.html +18 -0
- django_smartbase_admin/templates/sb_admin/navigation.html +166 -158
- django_smartbase_admin/templates/sb_admin/partials/modal/modal_content.html +2 -6
- django_smartbase_admin/templates/sb_admin/sb_admin_base.html +49 -4
- django_smartbase_admin/templates/sb_admin/sb_admin_base_no_sidebar.html +27 -11
- django_smartbase_admin/templates/sb_admin/sb_admin_js_trans.html +3 -0
- django_smartbase_admin/templates/sb_admin/sprites/sb_admin.svg +1 -1
- django_smartbase_admin/templates/sb_admin/tailwind_whitelist.html +6 -3
- django_smartbase_admin/templates/sb_admin/widgets/array.html +0 -1
- django_smartbase_admin/templates/sb_admin/widgets/attributes.html +68 -0
- django_smartbase_admin/templates/sb_admin/widgets/autocomplete.html +13 -2
- django_smartbase_admin/templates/sb_admin/widgets/{checkbox_select.html → checkbox_dropdown.html} +2 -2
- django_smartbase_admin/templates/sb_admin/widgets/clearable_file_input.html +2 -2
- django_smartbase_admin/templates/sb_admin/widgets/color_field.html +30 -0
- django_smartbase_admin/templates/sb_admin/widgets/date.html +8 -1
- django_smartbase_admin/templates/sb_admin/widgets/filer_file.html +84 -0
- django_smartbase_admin/templates/sb_admin/widgets/includes/related_item_buttons.html +38 -0
- django_smartbase_admin/templates/sb_admin/widgets/multiwidget.html +1 -1
- django_smartbase_admin/templates/sb_admin/widgets/radio.html +3 -2
- django_smartbase_admin/templates/sb_admin/widgets/radio_dropdown.html +30 -0
- django_smartbase_admin/templates/sb_admin/widgets/read_only_password_hash.html +3 -0
- django_smartbase_admin/templates/sb_admin/widgets/time.html +8 -1
- django_smartbase_admin/templates/sb_admin/widgets/toggle.html +1 -1
- django_smartbase_admin/templates/sb_admin/widgets/tree_base.html +59 -0
- django_smartbase_admin/templates/sb_admin/widgets/tree_select.html +24 -0
- django_smartbase_admin/templates/sb_admin/widgets/tree_select_inline.html +12 -0
- django_smartbase_admin/templatetags/sb_admin_tags.py +115 -4
- django_smartbase_admin/utils.py +22 -3
- django_smartbase_admin/views/dashboard_view.py +6 -0
- django_smartbase_admin/views/global_filter_view.py +8 -2
- django_smartbase_admin/views/translations_view.py +12 -5
- django_smartbase_admin/views/user_config_view.py +52 -0
- django_smartbase_admin-1.0.42.dist-info/METADATA +166 -0
- {django_smartbase_admin-0.2.54.dist-info → django_smartbase_admin-1.0.42.dist-info}/RECORD +182 -118
- {django_smartbase_admin-0.2.54.dist-info → django_smartbase_admin-1.0.42.dist-info}/WHEEL +1 -1
- django_smartbase_admin/templates/sb_admin/integrations/sorting/change_list.html +0 -401
- django_smartbase_admin-0.2.54.dist-info/METADATA +0 -25
- {django_smartbase_admin-0.2.54.dist-info → django_smartbase_admin-1.0.42.dist-info}/LICENSE.md +0 -0
|
@@ -1,12 +1,20 @@
|
|
|
1
|
-
from copy import deepcopy
|
|
2
|
-
|
|
3
1
|
from django.contrib.auth import get_permission_codename
|
|
2
|
+
from django.contrib.auth.views import LoginView
|
|
4
3
|
from django.db.models import Q
|
|
5
4
|
|
|
6
5
|
from django_smartbase_admin.admin.site import sb_admin_site
|
|
7
6
|
from django_smartbase_admin.engine.actions import SBAdminCustomAction
|
|
8
|
-
from django_smartbase_admin.engine.const import
|
|
9
|
-
|
|
7
|
+
from django_smartbase_admin.engine.const import (
|
|
8
|
+
GLOBAL_FILTER_DATA_KEY,
|
|
9
|
+
FilterVersions,
|
|
10
|
+
Action,
|
|
11
|
+
)
|
|
12
|
+
from django_smartbase_admin.models import (
|
|
13
|
+
ColorScheme,
|
|
14
|
+
SBAdminListViewConfiguration,
|
|
15
|
+
SBAdminUserConfiguration,
|
|
16
|
+
)
|
|
17
|
+
from django_smartbase_admin.utils import to_list, is_modal
|
|
10
18
|
|
|
11
19
|
|
|
12
20
|
class SBAdminConfigurationBase(object):
|
|
@@ -19,6 +27,145 @@ class SBAdminConfigurationBase(object):
|
|
|
19
27
|
def get_configuration_for_roles(self, user_roles):
|
|
20
28
|
raise NotImplementedError
|
|
21
29
|
|
|
30
|
+
# User configuration hooks - override these methods to customize user identification
|
|
31
|
+
# (e.g., use email instead of user_id for OAuth/external auth scenarios)
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def get_user_config(cls, request):
|
|
35
|
+
"""
|
|
36
|
+
Get or create user configuration (e.g., color scheme preferences).
|
|
37
|
+
|
|
38
|
+
Override this method to customize user identification. Default uses user_id.
|
|
39
|
+
|
|
40
|
+
Example for email-based users::
|
|
41
|
+
|
|
42
|
+
@classmethod
|
|
43
|
+
def get_user_config(cls, request):
|
|
44
|
+
from myapp.models import MyUserConfig
|
|
45
|
+
email = getattr(request.user, "email", None)
|
|
46
|
+
if not email:
|
|
47
|
+
return MyUserConfig(email="anonymous", color_scheme=ColorScheme.AUTO.value)
|
|
48
|
+
config, _ = MyUserConfig.objects.get_or_create(
|
|
49
|
+
email=email,
|
|
50
|
+
defaults={"color_scheme": request.request_data.configuration.default_color_scheme},
|
|
51
|
+
)
|
|
52
|
+
return config
|
|
53
|
+
"""
|
|
54
|
+
if not request.user or request.user.is_anonymous:
|
|
55
|
+
return None
|
|
56
|
+
user_config, _ = SBAdminUserConfiguration.objects.get_or_create(
|
|
57
|
+
defaults={
|
|
58
|
+
"color_scheme": request.request_data.configuration.default_color_scheme
|
|
59
|
+
},
|
|
60
|
+
user_id=request.user.id,
|
|
61
|
+
)
|
|
62
|
+
return user_config
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def get_saved_views(cls, request, view_id):
|
|
66
|
+
"""
|
|
67
|
+
Get saved views for the current user and view.
|
|
68
|
+
|
|
69
|
+
Override this method to customize user identification. Default uses user_id.
|
|
70
|
+
Returns a list of dicts with keys: id, name, url_params, view (view_id).
|
|
71
|
+
|
|
72
|
+
Example for email-based users::
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def get_saved_views(cls, request, view_id):
|
|
76
|
+
from myapp.models import MySavedView
|
|
77
|
+
email = getattr(request.user, "email", None)
|
|
78
|
+
if not email:
|
|
79
|
+
return []
|
|
80
|
+
return list(
|
|
81
|
+
MySavedView.objects.filter(email=email, view_id=view_id)
|
|
82
|
+
.values("id", "name", "config", "view_id")
|
|
83
|
+
)
|
|
84
|
+
"""
|
|
85
|
+
if not request.user or request.user.is_anonymous:
|
|
86
|
+
return []
|
|
87
|
+
return list(
|
|
88
|
+
SBAdminListViewConfiguration.objects.by_user_id(request.user.id)
|
|
89
|
+
.by_view_action_modifier(view=view_id)
|
|
90
|
+
.values()
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def create_or_update_saved_view(
|
|
95
|
+
cls, request, view_id, config_id, config_name, url_params
|
|
96
|
+
):
|
|
97
|
+
"""
|
|
98
|
+
Create or update a saved view for the current user.
|
|
99
|
+
|
|
100
|
+
Override this method to customize user identification. Default uses user_id.
|
|
101
|
+
Returns the created/updated saved view object.
|
|
102
|
+
|
|
103
|
+
Example for email-based users::
|
|
104
|
+
|
|
105
|
+
@classmethod
|
|
106
|
+
def create_or_update_saved_view(cls, request, view_id, config_id, config_name, url_params):
|
|
107
|
+
from myapp.models import MySavedView
|
|
108
|
+
email = getattr(request.user, "email", None)
|
|
109
|
+
if not email:
|
|
110
|
+
return None
|
|
111
|
+
config_params = {}
|
|
112
|
+
if config_id:
|
|
113
|
+
config_params["id"] = config_id
|
|
114
|
+
if config_name:
|
|
115
|
+
config_params["name"] = config_name
|
|
116
|
+
saved_view, _ = MySavedView.objects.update_or_create(
|
|
117
|
+
email=email,
|
|
118
|
+
**config_params,
|
|
119
|
+
defaults={"config": {"url_params": url_params}, "view_id": view_id},
|
|
120
|
+
)
|
|
121
|
+
return saved_view
|
|
122
|
+
"""
|
|
123
|
+
if not request.user or request.user.is_anonymous:
|
|
124
|
+
return None
|
|
125
|
+
config_params = {}
|
|
126
|
+
if config_id:
|
|
127
|
+
config_params["id"] = config_id
|
|
128
|
+
elif config_name:
|
|
129
|
+
config_params["name"] = config_name
|
|
130
|
+
if not config_params:
|
|
131
|
+
return None
|
|
132
|
+
saved_view, _ = SBAdminListViewConfiguration.objects.update_or_create(
|
|
133
|
+
user_id=request.user.id,
|
|
134
|
+
**config_params,
|
|
135
|
+
defaults={
|
|
136
|
+
"url_params": url_params,
|
|
137
|
+
"view": view_id,
|
|
138
|
+
"action": None,
|
|
139
|
+
"modifier": None,
|
|
140
|
+
},
|
|
141
|
+
)
|
|
142
|
+
return saved_view
|
|
143
|
+
|
|
144
|
+
@classmethod
|
|
145
|
+
def delete_saved_view(cls, request, view_id, config_id):
|
|
146
|
+
"""
|
|
147
|
+
Delete a saved view for the current user.
|
|
148
|
+
|
|
149
|
+
Override this method to customize user identification. Default uses user_id.
|
|
150
|
+
|
|
151
|
+
Example for email-based users::
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def delete_saved_view(cls, request, view_id, config_id):
|
|
155
|
+
from myapp.models import MySavedView
|
|
156
|
+
email = getattr(request.user, "email", None)
|
|
157
|
+
if not email or not config_id:
|
|
158
|
+
return
|
|
159
|
+
MySavedView.objects.filter(
|
|
160
|
+
email=email, id=config_id, view_id=view_id
|
|
161
|
+
).delete()
|
|
162
|
+
"""
|
|
163
|
+
if not request.user or request.user.is_anonymous or not config_id:
|
|
164
|
+
return
|
|
165
|
+
SBAdminListViewConfiguration.objects.by_user_id(request.user.id).by_id(
|
|
166
|
+
config_id
|
|
167
|
+
).by_view_action_modifier(view=view_id).delete()
|
|
168
|
+
|
|
22
169
|
|
|
23
170
|
class Singleton(type):
|
|
24
171
|
_instances = {}
|
|
@@ -37,6 +184,8 @@ class SBAdminRoleConfiguration(metaclass=Singleton):
|
|
|
37
184
|
menu_items = None
|
|
38
185
|
global_filter_form = None
|
|
39
186
|
filters_version = FilterVersions.FILTERS_VERSION_1
|
|
187
|
+
default_color_scheme = ColorScheme.AUTO
|
|
188
|
+
login_view_class = LoginView
|
|
40
189
|
|
|
41
190
|
def __init__(
|
|
42
191
|
self,
|
|
@@ -45,6 +194,8 @@ class SBAdminRoleConfiguration(metaclass=Singleton):
|
|
|
45
194
|
menu_items=None,
|
|
46
195
|
global_filter_form=None,
|
|
47
196
|
filters_version=None,
|
|
197
|
+
default_color_scheme=None,
|
|
198
|
+
login_view_class=None,
|
|
48
199
|
) -> None:
|
|
49
200
|
super().__init__()
|
|
50
201
|
self.default_view = default_view or self.default_view or []
|
|
@@ -54,6 +205,8 @@ class SBAdminRoleConfiguration(metaclass=Singleton):
|
|
|
54
205
|
self.init_configuration_static()
|
|
55
206
|
self.autocomplete_map = {}
|
|
56
207
|
self.filters_version = filters_version or self.filters_version
|
|
208
|
+
self.default_color_scheme = default_color_scheme or self.default_color_scheme
|
|
209
|
+
self.login_view_class = login_view_class or self.login_view_class
|
|
57
210
|
|
|
58
211
|
def init_registered_views(self):
|
|
59
212
|
registered_views = []
|
|
@@ -84,6 +237,18 @@ class SBAdminRoleConfiguration(metaclass=Singleton):
|
|
|
84
237
|
if hasattr(view, "get_id")
|
|
85
238
|
}
|
|
86
239
|
)
|
|
240
|
+
try:
|
|
241
|
+
from cms.plugin_pool import plugin_pool
|
|
242
|
+
|
|
243
|
+
for name, view in plugin_pool.plugins.items():
|
|
244
|
+
if hasattr(view, "get_id"):
|
|
245
|
+
view_instance = view(view.model, sb_admin_site)
|
|
246
|
+
self.view_map[view_instance.get_id()] = view_instance
|
|
247
|
+
view_instance.init_view_static(
|
|
248
|
+
self, view_instance.model, sb_admin_site
|
|
249
|
+
)
|
|
250
|
+
except ImportError:
|
|
251
|
+
pass
|
|
87
252
|
|
|
88
253
|
def init_model_admin_view_map(self):
|
|
89
254
|
for model, admin_view in sb_admin_site._registry.items():
|
|
@@ -132,6 +297,8 @@ class SBAdminRoleConfiguration(metaclass=Singleton):
|
|
|
132
297
|
|
|
133
298
|
def has_action_permission(self, request, request_data, view, model, obj, action):
|
|
134
299
|
if model:
|
|
300
|
+
if action.action_id == Action.BULK_DELETE.value:
|
|
301
|
+
return view.has_delete_permission(request, obj)
|
|
135
302
|
return self.has_permission(
|
|
136
303
|
request, request_data, view, model, obj, "view"
|
|
137
304
|
) or self.has_permission(request, request_data, view, model, obj, "change")
|
|
@@ -166,6 +333,9 @@ class SBAdminRoleConfiguration(metaclass=Singleton):
|
|
|
166
333
|
form_field, model=model, multiselect=multiselect
|
|
167
334
|
)
|
|
168
335
|
|
|
336
|
+
def get_filter_widget(self, field, default_widget):
|
|
337
|
+
return default_widget
|
|
338
|
+
|
|
169
339
|
def get_form_field_widget_class(
|
|
170
340
|
self, view, request, form_field, db_field, default_widget_class
|
|
171
341
|
):
|
|
@@ -204,3 +374,15 @@ class SBAdminRoleConfiguration(metaclass=Singleton):
|
|
|
204
374
|
if global_filter_mapped_filter_key:
|
|
205
375
|
filter_query &= Q(**{f"{global_filter_mapped_filter_key}": field_value})
|
|
206
376
|
return qs.filter(filter_query)
|
|
377
|
+
|
|
378
|
+
def process_global_filter_response(self, response, request):
|
|
379
|
+
return response
|
|
380
|
+
|
|
381
|
+
def autocomplete_show_related_buttons(
|
|
382
|
+
self,
|
|
383
|
+
related_model,
|
|
384
|
+
field_name,
|
|
385
|
+
current_view,
|
|
386
|
+
request,
|
|
387
|
+
) -> bool:
|
|
388
|
+
return not is_modal(request)
|
|
@@ -31,6 +31,7 @@ DEFAULT_PAGE_SIZE = 20
|
|
|
31
31
|
PAGE_SIZE_OPTIONS = [10, 20, 50, 100]
|
|
32
32
|
AUTOCOMPLETE_PAGE_SIZE = 20
|
|
33
33
|
XLSX_PAGE_CHUNK_SIZE = 50000
|
|
34
|
+
IGNORE_LIST_SELECTION = "__all__"
|
|
34
35
|
NEW_OBJECT_ID = 0
|
|
35
36
|
OBJECT_ID_PLACEHOLDER = -1
|
|
36
37
|
ALL_MODEL_FIELDS = "__all__"
|
|
@@ -52,6 +53,9 @@ TABLE_PARAMS_PAGE_NAME = "page"
|
|
|
52
53
|
TABLE_PARAMS_SORT_NAME = "sort"
|
|
53
54
|
TABLE_PARAMS_FULL_TEXT_SEARCH = "sb_admin_full_search"
|
|
54
55
|
TABLE_PARAMS_SELECTED_FILTER_TYPE = "sb_selected_filter_type"
|
|
56
|
+
TABLE_TAB_ADVANCED_FITLERS = "tab_advanced_filters"
|
|
57
|
+
TABLE_RELOAD_DATA_EVENT_NAME = "SBAdminReloadTableData"
|
|
58
|
+
TABLE_UPDATE_ROW_DATA_EVENT_NAME = "SBAdminUpdateRowData"
|
|
55
59
|
FILTER_DATA_NAME = "filterData"
|
|
56
60
|
ADVANCED_FILTER_DATA_NAME = "advancedFilterData"
|
|
57
61
|
BASE_PARAMS_NAME = "params"
|
|
@@ -69,3 +73,5 @@ DETAIL_STRUCTURE_RIGHT_CLASS = "detail-structure-right"
|
|
|
69
73
|
TRANSLATIONS_SELECTED_LANGUAGES = "translation_selected_languages"
|
|
70
74
|
OVERRIDE_CONTENT_OF_NOTIFICATION = "override_notification_content"
|
|
71
75
|
FIELDSET_HIDE_HEADER_CLASS = "hide-header"
|
|
76
|
+
ROW_CLASS_FIELD = "get_sbadmin_row_class"
|
|
77
|
+
SUPPORTED_FILE_TYPE_ICONS = ["doc", "docx", "csv", "xls", "xlsx", "pdf", "ppt", "zip"]
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
from copy import copy, deepcopy
|
|
1
|
+
from copy import copy
|
|
3
2
|
from datetime import timedelta
|
|
4
|
-
|
|
5
3
|
from django.core.cache import cache
|
|
6
4
|
from django.db import models
|
|
7
5
|
from django.db.models import QuerySet
|
|
@@ -17,7 +15,6 @@ from django_smartbase_admin.engine.admin_view import SBAdminView
|
|
|
17
15
|
from django_smartbase_admin.engine.const import OBJECT_ID_PLACEHOLDER
|
|
18
16
|
from django_smartbase_admin.engine.field import SBAdminField
|
|
19
17
|
from django_smartbase_admin.engine.filter_widgets import (
|
|
20
|
-
ChoiceFilterWidget,
|
|
21
18
|
DateFilterWidget,
|
|
22
19
|
RadioChoiceFilterWidget,
|
|
23
20
|
)
|
|
@@ -85,6 +82,7 @@ class SBAdminDashboardWidget(SBAdminView):
|
|
|
85
82
|
def get_widget_context_data(self, request):
|
|
86
83
|
return {
|
|
87
84
|
"widget_id": self.get_id(),
|
|
85
|
+
"widget_name": self.name,
|
|
88
86
|
"ajax_url": self.get_ajax_url,
|
|
89
87
|
"filters": self.get_filters(),
|
|
90
88
|
"settings": self.get_settings(),
|
|
@@ -95,6 +93,12 @@ class SBAdminDashboardWidget(SBAdminView):
|
|
|
95
93
|
def get_sub_widgets(self):
|
|
96
94
|
return self.sub_widgets
|
|
97
95
|
|
|
96
|
+
def get_sub_views(self, configuration):
|
|
97
|
+
for idx, sub_widget_view in enumerate(self.sub_widgets):
|
|
98
|
+
sub_widget_view.widget_id = f"{self.get_id()}_{idx}"
|
|
99
|
+
sub_widget_view.init_widget_static(configuration)
|
|
100
|
+
return self.sub_widgets
|
|
101
|
+
|
|
98
102
|
def get_template_name(self):
|
|
99
103
|
return self.template_name
|
|
100
104
|
|
|
@@ -196,6 +200,12 @@ class SBAdminChartAggregateSubWidget(object):
|
|
|
196
200
|
def render(self, request):
|
|
197
201
|
return render_to_string(self.template_name, self.get_context_data(request))
|
|
198
202
|
|
|
203
|
+
def init_widget_static(self, configuration):
|
|
204
|
+
pass
|
|
205
|
+
|
|
206
|
+
def init_view_dynamic(self, request, request_data=None, **kwargs):
|
|
207
|
+
pass
|
|
208
|
+
|
|
199
209
|
|
|
200
210
|
class SBAdminDashboardChartWidget(SBAdminDashboardWidget):
|
|
201
211
|
template_name = "sb_admin/dashboard/chart_widget.html"
|
|
@@ -330,12 +340,14 @@ class SBAdminDashboardChartWidget(SBAdminDashboardWidget):
|
|
|
330
340
|
sub_widget_data[sub_widget.get_id()] = sub_widget.get_data(
|
|
331
341
|
request, sub_widget_qs
|
|
332
342
|
)
|
|
343
|
+
active_sub_widget = self.get_active_sub_widget(request)
|
|
344
|
+
dataset_label = active_sub_widget.title if active_sub_widget else self.name
|
|
333
345
|
return_data = {
|
|
334
346
|
"main": {
|
|
335
347
|
"labels": labels,
|
|
336
348
|
"datasets": [
|
|
337
349
|
{
|
|
338
|
-
"label":
|
|
350
|
+
"label": dataset_label,
|
|
339
351
|
"data": dataset_data,
|
|
340
352
|
**self.get_dataset_options(request),
|
|
341
353
|
}
|
|
@@ -419,6 +431,7 @@ class SBAdminDashboardChartWidgetByDate(SBAdminDashboardChartWidget):
|
|
|
419
431
|
filter_widget=RadioChoiceFilterWidget(
|
|
420
432
|
choices=self.DateResolutionsOptions.choices,
|
|
421
433
|
default_value=self.default_date_resolution,
|
|
434
|
+
allow_clear=False,
|
|
422
435
|
),
|
|
423
436
|
),
|
|
424
437
|
SBAdminField(
|
|
@@ -427,6 +440,7 @@ class SBAdminDashboardChartWidgetByDate(SBAdminDashboardChartWidget):
|
|
|
427
440
|
filter_widget=RadioChoiceFilterWidget(
|
|
428
441
|
choices=self.CompareOptions.choices,
|
|
429
442
|
default_value=self.CompareOptions.values[0],
|
|
443
|
+
allow_clear=False,
|
|
430
444
|
),
|
|
431
445
|
),
|
|
432
446
|
]
|
|
@@ -542,25 +556,28 @@ class SBAdminDashboardChartWidgetByDate(SBAdminDashboardChartWidget):
|
|
|
542
556
|
self.date_annotate_field
|
|
543
557
|
)
|
|
544
558
|
)
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
559
|
+
if date_range[0] and date_range[1]:
|
|
560
|
+
date_range_compare = date_range
|
|
561
|
+
if compare == self.CompareOptions.COMPARE_PREVIOUS:
|
|
562
|
+
period_length = (
|
|
563
|
+
date_range_compare[1] - date_range_compare[0]
|
|
564
|
+
).days + 1
|
|
565
|
+
date_range_compare[0] = date_range_compare[0] - timedelta(
|
|
566
|
+
days=period_length
|
|
567
|
+
)
|
|
568
|
+
date_range_compare[1] = date_range_compare[1] - timedelta(
|
|
569
|
+
days=period_length
|
|
570
|
+
)
|
|
571
|
+
if compare == self.CompareOptions.COMPARE_PREVIOUS_YOY:
|
|
572
|
+
date_range_compare[0] = date_range_compare[0].replace(
|
|
573
|
+
year=date_range_compare[0].year - 1
|
|
574
|
+
)
|
|
575
|
+
date_range_compare[1] = date_range_compare[1].replace(
|
|
576
|
+
year=date_range_compare[1].year - 1
|
|
577
|
+
)
|
|
578
|
+
request_data_modified_date_filter.request_get[
|
|
579
|
+
self.date_annotate_field
|
|
580
|
+
] = DateFilterWidget.get_value_from_date_or_range(date_range_compare)
|
|
564
581
|
queryset_with_modified_date = self.get_data_queryset(request_copy)
|
|
565
582
|
|
|
566
583
|
sub_widget_data = {}
|
|
@@ -666,5 +683,13 @@ class SBAdminDashboardListWidget(SBAdminBaseListView, SBAdminDashboardWidget):
|
|
|
666
683
|
"viewsModule",
|
|
667
684
|
"tableParamsModule",
|
|
668
685
|
"detailViewModule",
|
|
686
|
+
"filterModule",
|
|
669
687
|
]
|
|
670
688
|
return tabulator_definition
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
class SbAdminCalendarWidget(SBAdminDashboardWidget):
|
|
692
|
+
template_name = "sb_admin/dashboard/calendar_widget.html"
|
|
693
|
+
|
|
694
|
+
def action_get_data(self, request, modifier):
|
|
695
|
+
return JsonResponse(data=self.get_cached_data(request), safe=False)
|
|
@@ -3,7 +3,9 @@ from django.db import models
|
|
|
3
3
|
from django.db.models import F
|
|
4
4
|
from django.forms import BaseInlineFormSet
|
|
5
5
|
|
|
6
|
+
from django_smartbase_admin.services.thread_local import SBAdminThreadLocalService
|
|
6
7
|
from django_smartbase_admin.services.views import SBAdminViewService
|
|
8
|
+
from django_smartbase_admin.utils import is_modal
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
class FakeQueryset(models.QuerySet):
|
|
@@ -33,6 +35,14 @@ class SBAdminFakeInlineFormset(BaseInlineFormSet):
|
|
|
33
35
|
original_model = None
|
|
34
36
|
inline_instance = None
|
|
35
37
|
|
|
38
|
+
@classmethod
|
|
39
|
+
def get_default_prefix(cls):
|
|
40
|
+
prefix = super().get_default_prefix()
|
|
41
|
+
modal_prefix = (
|
|
42
|
+
"modal_" if is_modal(SBAdminThreadLocalService.get_request()) else ""
|
|
43
|
+
)
|
|
44
|
+
return f"{modal_prefix}{prefix}"
|
|
45
|
+
|
|
36
46
|
def save_new(self, form, commit=True):
|
|
37
47
|
return self.inline_instance.save_new_fake_inline_instance(
|
|
38
48
|
form, self.inline_instance.parent_instance, commit
|
|
@@ -82,23 +92,17 @@ class SBAdminFakeInlineMixin:
|
|
|
82
92
|
formset.inline_instance = self
|
|
83
93
|
return formset
|
|
84
94
|
|
|
85
|
-
def has_add_permission(self, request, obj=None):
|
|
86
|
-
# don't allow adding new fake inline instances if parent instance is not saved yet
|
|
87
|
-
if not self.parent_instance.id:
|
|
88
|
-
return False
|
|
89
|
-
return super().has_add_permission(request, obj)
|
|
90
|
-
|
|
91
95
|
def filter_fake_inline_identifier_by_parent_instance(
|
|
92
96
|
self, inline_queryset, parent_instance
|
|
93
97
|
):
|
|
94
98
|
# filter queryset by parent istance, in queryset there is annotated 'identifier' by get_fake_inline_identifier_annotate
|
|
95
99
|
# example usage:
|
|
96
|
-
# qs = inline_queryset.filter(path_to_parent_instance__id: parent_instance.
|
|
100
|
+
# qs = inline_queryset.filter(path_to_parent_instance__id: parent_instance.pk)
|
|
97
101
|
# return qs
|
|
98
102
|
if not self.path_to_parent_instance_id:
|
|
99
103
|
raise NotImplementedError
|
|
100
104
|
qs = inline_queryset.filter(
|
|
101
|
-
**{self.path_to_parent_instance_id: parent_instance.
|
|
105
|
+
**{self.path_to_parent_instance_id: parent_instance.pk}
|
|
102
106
|
)
|
|
103
107
|
return qs
|
|
104
108
|
|
|
@@ -107,9 +111,9 @@ class SBAdminFakeInlineMixin:
|
|
|
107
111
|
if not self.path_to_parent_instance_id:
|
|
108
112
|
raise NotImplementedError
|
|
109
113
|
fake_inline_object = form.save(commit=False)
|
|
110
|
-
if parent_instance.
|
|
114
|
+
if parent_instance.pk:
|
|
111
115
|
setattr(
|
|
112
|
-
fake_inline_object, self.path_to_parent_instance_id, parent_instance.
|
|
116
|
+
fake_inline_object, self.path_to_parent_instance_id, parent_instance.pk
|
|
113
117
|
)
|
|
114
118
|
fake_inline_object.save()
|
|
115
119
|
return fake_inline_object
|
|
@@ -120,7 +124,7 @@ class SBAdminFakeInlineMixin:
|
|
|
120
124
|
# result of this method is used in fake_inline_queryset.annotate(SBAdminFakeInlineMixin.fk_name='result')
|
|
121
125
|
# example usage:
|
|
122
126
|
# return F('some_model__relationship_to_parent')
|
|
123
|
-
return F("
|
|
127
|
+
return F("pk")
|
|
124
128
|
|
|
125
129
|
def get_queryset(self, request):
|
|
126
130
|
model = self.original_model
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
from collections.abc import Callable
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
1
4
|
from django.core.exceptions import FieldDoesNotExist, FieldError, ImproperlyConfigured
|
|
2
|
-
from django.db.models import
|
|
5
|
+
from django.db.models import (
|
|
6
|
+
Count,
|
|
7
|
+
Value,
|
|
8
|
+
CharField,
|
|
9
|
+
F,
|
|
10
|
+
DateTimeField,
|
|
11
|
+
BooleanField,
|
|
12
|
+
FilteredRelation,
|
|
13
|
+
)
|
|
3
14
|
from django.db.models.functions import Concat
|
|
4
15
|
|
|
5
16
|
from django_smartbase_admin.engine.const import ANNOTATE_KEY, Formatter
|
|
@@ -23,6 +34,7 @@ class TabulatorFieldOptions(JSONSerializableMixin):
|
|
|
23
34
|
formatterParams = None
|
|
24
35
|
frozen = False
|
|
25
36
|
title = None
|
|
37
|
+
editorParams = None
|
|
26
38
|
|
|
27
39
|
def __init__(
|
|
28
40
|
self,
|
|
@@ -31,6 +43,7 @@ class TabulatorFieldOptions(JSONSerializableMixin):
|
|
|
31
43
|
formatterParams=None,
|
|
32
44
|
frozen=None,
|
|
33
45
|
title=None,
|
|
46
|
+
editorParams=None,
|
|
34
47
|
) -> None:
|
|
35
48
|
super().__init__()
|
|
36
49
|
self.headerFilter = headerFilter
|
|
@@ -38,20 +51,27 @@ class TabulatorFieldOptions(JSONSerializableMixin):
|
|
|
38
51
|
self.formatterParams = formatterParams
|
|
39
52
|
self.frozen = frozen
|
|
40
53
|
self.title = title
|
|
54
|
+
self.editorParams = editorParams
|
|
41
55
|
|
|
42
56
|
|
|
43
57
|
class XLSXFieldOptions(JSONSerializableMixin):
|
|
44
|
-
title = None
|
|
45
|
-
field = None
|
|
46
|
-
formatter = None
|
|
58
|
+
title: str | None = None
|
|
59
|
+
field: str | None = None
|
|
60
|
+
formatter: Formatter | None = None
|
|
61
|
+
python_formatter: Callable[[int, Any], Any] | None = None
|
|
47
62
|
|
|
48
63
|
def __init__(
|
|
49
|
-
self,
|
|
64
|
+
self,
|
|
65
|
+
title: str | None = None,
|
|
66
|
+
field: str | None = None,
|
|
67
|
+
formatter: Formatter | None = None,
|
|
68
|
+
python_formatter: Callable[[int, Any], Any] | None = None,
|
|
50
69
|
) -> None:
|
|
51
70
|
super().__init__()
|
|
52
71
|
self.title = title
|
|
53
72
|
self.field = field
|
|
54
73
|
self.formatter = formatter
|
|
74
|
+
self.python_formatter = python_formatter
|
|
55
75
|
|
|
56
76
|
|
|
57
77
|
class SBAdminField(JSONSerializableMixin):
|
|
@@ -80,6 +100,7 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
80
100
|
python_formatter = None
|
|
81
101
|
tabulator_options = None
|
|
82
102
|
xlsx_options = None
|
|
103
|
+
initialized = False
|
|
83
104
|
|
|
84
105
|
def __init__(
|
|
85
106
|
self,
|
|
@@ -96,7 +117,7 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
96
117
|
list_visible=None,
|
|
97
118
|
list_collapsed=None,
|
|
98
119
|
auto_created=None,
|
|
99
|
-
formatter: Formatter =
|
|
120
|
+
formatter: Formatter = Formatter.HTML.value,
|
|
100
121
|
tabulator_editor=None,
|
|
101
122
|
python_formatter=None,
|
|
102
123
|
tabulator_options: "TabulatorFieldOptions" = None,
|
|
@@ -118,6 +139,7 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
118
139
|
if (list_visible is not None)
|
|
119
140
|
else (self.list_visible if self.list_visible is not None else True)
|
|
120
141
|
)
|
|
142
|
+
self.list_visible_arg = list_visible
|
|
121
143
|
self.list_collapsed = list_collapsed or self.list_collapsed or False
|
|
122
144
|
self.auto_created = auto_created or self.auto_created or False
|
|
123
145
|
self.formatter = formatter
|
|
@@ -139,6 +161,7 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
139
161
|
)
|
|
140
162
|
if not filter_widget:
|
|
141
163
|
filter_widget = StringFilterWidget()
|
|
164
|
+
filter_widget = configuration.get_filter_widget(self, filter_widget)
|
|
142
165
|
if filter_widget:
|
|
143
166
|
filter_widget.init_filter_widget_static(self, self.view, configuration)
|
|
144
167
|
self.filter_widget = filter_widget
|
|
@@ -179,7 +202,6 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
179
202
|
if self.model_field and not self.annotate:
|
|
180
203
|
self.annotate = F(field_name)
|
|
181
204
|
self.filter_field = self.filter_field or field_name
|
|
182
|
-
self.formatter = "html"
|
|
183
205
|
if self.view.model and not self.model_field:
|
|
184
206
|
self.model_field = self.get_model_field_from_model(self.name)
|
|
185
207
|
if (
|
|
@@ -199,7 +221,9 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
199
221
|
if self.model_field:
|
|
200
222
|
self.editable = self.model_field.editable
|
|
201
223
|
if self.model_field.is_relation:
|
|
202
|
-
self.list_visible =
|
|
224
|
+
self.list_visible = (
|
|
225
|
+
False if self.list_visible_arg is None else self.list_visible_arg
|
|
226
|
+
)
|
|
203
227
|
if self.model_field.auto_created:
|
|
204
228
|
self.detail_visible = False
|
|
205
229
|
self.title = self.title or getattr(
|
|
@@ -217,10 +241,9 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
217
241
|
self.python_formatter = datetime_formatter
|
|
218
242
|
if isinstance(self.model_field, BooleanField):
|
|
219
243
|
self.python_formatter = boolean_formatter
|
|
220
|
-
if self.python_formatter and not self.formatter:
|
|
221
|
-
self.formatter = "html"
|
|
222
244
|
self.filter_field = self.filter_field or self.field
|
|
223
245
|
self.init_filter_for_field(configuration)
|
|
246
|
+
self.initialized = True
|
|
224
247
|
|
|
225
248
|
def serialize_tabulator(self):
|
|
226
249
|
data = {
|
|
@@ -252,6 +275,7 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
252
275
|
|
|
253
276
|
def get_field_annotates(self, values):
|
|
254
277
|
field_annotates = {}
|
|
278
|
+
supporting_annotates = {}
|
|
255
279
|
if self.annotate:
|
|
256
280
|
field_annotates[self.field] = self.annotate
|
|
257
281
|
if self.annotate_function:
|
|
@@ -261,5 +285,11 @@ class SBAdminField(JSONSerializableMixin):
|
|
|
261
285
|
else:
|
|
262
286
|
field_annotates[self.field] = Value(None, output_field=CharField())
|
|
263
287
|
if self.supporting_annotates:
|
|
264
|
-
|
|
265
|
-
|
|
288
|
+
for key, value in self.supporting_annotates.items():
|
|
289
|
+
# workaround for a django bug
|
|
290
|
+
# https://code.djangoproject.com/ticket/36442#ticket
|
|
291
|
+
if isinstance(value, FilteredRelation):
|
|
292
|
+
supporting_annotates[key] = value.clone()
|
|
293
|
+
else:
|
|
294
|
+
supporting_annotates[key] = value
|
|
295
|
+
return {**supporting_annotates, **field_annotates}
|