django-unfold 0.30.0__tar.gz → 0.31.0__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {django_unfold-0.30.0 → django_unfold-0.31.0}/PKG-INFO +59 -18
- {django_unfold-0.30.0 → django_unfold-0.31.0}/README.md +58 -17
- {django_unfold-0.30.0 → django_unfold-0.31.0}/pyproject.toml +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/admin.py +30 -11
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +3 -3
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/templates/unfold/forms/array.html +3 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html +6 -6
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/templates/unfold/forms/wysiwyg.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/widgets.py +22 -11
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/unfold/guardian/group_form.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/unfold/guardian/user_form.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_form.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_errors.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_preview.html +3 -3
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_validation.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/forms.py +1 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history_list.html +9 -9
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/templates/simple_history/submit_line.html +1 -1
- django_unfold-0.31.0/src/unfold/dataclasses.py +22 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/fields.py +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/settings.py +1 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/sites.py +39 -15
- django_unfold-0.31.0/src/unfold/static/unfold/css/styles.css +1 -0
- django_unfold-0.31.0/src/unfold/static/unfold/js/alpine.anchor.js +1 -0
- django_unfold-0.31.0/src/unfold/static/unfold/js/alpine.js +5 -0
- django_unfold-0.31.0/src/unfold/static/unfold/js/alpine.persist.js +1 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/js/app.js +26 -3
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/styles.css +10 -10
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/actions.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/app_list.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/base.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_list.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_list_results.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/delete_confirmation.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/delete_selected_confirmation.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/edit_inline/stacked.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/edit_inline/tabular.html +3 -3
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/filter.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/includes/fieldset.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/includes/object_delete_summary.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/login.html +8 -8
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/object_history.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/search_form.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/submit_line.html +7 -5
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/auth/widgets/read_only_password_hash.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/registration/logged_out.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/change_list_filter.html +9 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/account_links.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/actions_row.html +4 -4
- django_unfold-0.31.0/src/unfold/templates/unfold/helpers/app_list.html +99 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/app_list_default.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/breadcrumb_item.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/fieldset_row.html +6 -6
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/fieldsets_tabs.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/header.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/help_text.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/history.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/label.html +1 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/search.html +7 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/search_results.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/tab_action.html +1 -1
- django_unfold-0.31.0/src/unfold/templates/unfold/helpers/tab_list.html +62 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/theme_switch.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/layouts/skeleton.html +6 -1
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/clearable_file_input.html +14 -6
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/clearable_file_input_small.html +4 -4
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/split_datetime.html +2 -2
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templatetags/unfold.py +33 -12
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templatetags/unfold_list.py +16 -6
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/widgets.py +2 -2
- django_unfold-0.30.0/src/unfold/dataclasses.py +0 -13
- django_unfold-0.30.0/src/unfold/static/unfold/css/styles.css +0 -1
- django_unfold-0.30.0/src/unfold/static/unfold/js/alpine.js +0 -5
- django_unfold-0.30.0/src/unfold/static/unfold/js/alpine.persist.js +0 -1
- django_unfold-0.30.0/src/unfold/templates/unfold/helpers/app_list.html +0 -89
- django_unfold-0.30.0/src/unfold/templates/unfold/helpers/tab_list.html +0 -40
- {django_unfold-0.30.0 → django_unfold-0.31.0}/LICENSE.md +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/apps.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/checks.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/admin.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/apps.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/forms.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/css/nouislider.min.css +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/js/DateTimeShortcuts.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/js/nouislider.min.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/static/unfold/filters/js/wNumb.min.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_date_range.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_datetime_range.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_field.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_range.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_single.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/apps.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/static/unfold/forms/css/trix.css +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix.config.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/apps.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/change_form.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/field.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_group.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_user.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/apps.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/forms.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/base.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_export.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_export_item.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_import_export.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_import_item.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/export.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_confirm.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_form.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/import_export/templates/admin/import_export/resource_fields_list.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/admin.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/apps.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/inlines/checks.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/apps.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history_form.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/decorators.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/exceptions.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/forms.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/css/simplebar.css +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/Inter-Bold.woff2 +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/Inter-Medium.woff2 +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/Inter-Regular.woff2 +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/Inter-SemiBold.woff2 +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/inter/styles.css +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/material-symbols/Material-Symbols-Outlined.woff2 +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/fonts/material-symbols/styles.css +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/js/chart.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/js/htmx.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/static/unfold/js/simplebar.js +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/app_index.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/auth/user/add_form.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/auth/user/change_password.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/base_site.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_form.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_form_object_tools.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/change_list_object_tools.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/date_hierarchy.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/index.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/nav_sidebar.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/admin/pagination.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/registration/password_change_done.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/registration/password_change_form.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/button.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/card.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/chart/bar.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/chart/line.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/container.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/flex.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/navigation.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/progress.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/separator.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/text.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/components/title.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/add_link.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/attrs.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/boolean.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/display_header.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/display_label.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/field.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/field_readonly.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/form_errors.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/form_label.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/messages/error.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/messages/errornote.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/messages/info.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/messages.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/navigation.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/pagination_current_item.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/pagination_ellipsis.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/site_icon.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/site_logo.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/submit.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/userlinks.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/helpers/welcomemsg.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/layouts/base.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/layouts/base_simple.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/date.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/foreign_key_raw_id.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/radio.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/radio_option.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/range.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/related_widget_wrapper.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/split_datetime_vertical.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/split_money.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/textarea.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/textarea_expandable.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templates/unfold/widgets/time.html +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/templatetags/__init__.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/typing.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/utils.py +0 -0
- {django_unfold-0.30.0 → django_unfold-0.31.0}/src/unfold/views.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: django-unfold
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.31.0
|
4
4
|
Summary: Modern Django admin theme for seamless interface development
|
5
5
|
Home-page: https://unfoldadmin.com
|
6
6
|
License: MIT
|
@@ -33,7 +33,7 @@ Description-Content-Type: text/markdown
|
|
33
33
|

|
34
34
|

|
35
35
|
|
36
|
-
Unfold is theme for Django admin incorporating most common
|
36
|
+
Unfold is a theme for Django admin incorporating most common practices for building full-fledged admin areas. It is designed to work on top of default administration provided by Django.
|
37
37
|
|
38
38
|
- **Unfold:** demo site is available at [unfoldadmin.com](https://unfoldadmin.com?utm_medium=github&utm_source=unfold)
|
39
39
|
- **Formula:** repository with demo implementation at [github.com/unfoldadmin/formula](https://github.com/unfoldadmin/formula)
|
@@ -45,7 +45,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
|
|
45
45
|
|
46
46
|
## Features <!-- omit from toc -->
|
47
47
|
|
48
|
-
- **Visual**: provides new user interface based on Tailwind CSS framework
|
48
|
+
- **Visual**: provides a new user interface based on Tailwind CSS framework
|
49
49
|
- **Sidebar:** simplifies definition of custom sidebar navigation with icons
|
50
50
|
- **Dark mode:** supports both light and dark mode versions
|
51
51
|
- **Configuration:** most of the basic options can be changed in settings.py
|
@@ -55,14 +55,16 @@ Did you decide to start using Unfold but you don't have time to make the switch
|
|
55
55
|
- **Array widget:** built-in widget for `django.contrib.postgres.fields.ArrayField`
|
56
56
|
- **Filters:** custom dropdown, numeric, datetime, and text fields
|
57
57
|
- **Dashboard:** custom components for rapid dashboard development
|
58
|
+
- **Inline tabs:** group inlines into tab navigation in the change form
|
58
59
|
- **Model tabs:** define custom tab navigations for models
|
59
|
-
- **Fieldset tabs:** merge several
|
60
|
-
- **Colors:** possibility to override default color scheme
|
61
|
-
- **Changeform modes:** display fields in
|
60
|
+
- **Fieldset tabs:** merge several fieldsets into tabs in the change form
|
61
|
+
- **Colors:** possibility to override the default color scheme
|
62
|
+
- **Changeform modes:** display fields in the change form in compressed mode
|
62
63
|
- **Third party packages:** default support for multiple popular applications
|
63
64
|
- **Environment label**: distinguish between environments by displaying a label
|
64
65
|
- **Nonrelated inlines**: displays nonrelated model as inline in changeform
|
65
66
|
- **Parallel admin**: support for default admin in parallel with Unfold. [Admin migration guide](https://unfoldadmin.com/blog/migrating-django-admin-unfold/?utm_medium=github&utm_source=unfold)
|
67
|
+
- **Favicons**: built-in support for configuring various site favicons
|
66
68
|
- **VS Code**: project configuration and development container is included
|
67
69
|
|
68
70
|
## Table of contents <!-- omit from toc -->
|
@@ -111,7 +113,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
|
|
111
113
|
|
112
114
|
## Installation
|
113
115
|
|
114
|
-
The installation process is minimal. Everything
|
116
|
+
The installation process is minimal. Everything that is needed after installation is to put new application at the beginning of **INSTALLED_APPS**. The default admin configuration in urls.py can stay as it is, and no changes are required.
|
115
117
|
|
116
118
|
```python
|
117
119
|
# settings.py
|
@@ -170,17 +172,24 @@ class CustomAdminClass(ModelAdmin):
|
|
170
172
|
|
171
173
|
from django.contrib import admin
|
172
174
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
175
|
+
from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
|
173
176
|
from django.contrib.auth.models import User
|
174
177
|
|
175
178
|
from unfold.admin import ModelAdmin
|
176
179
|
|
177
180
|
|
178
181
|
admin.site.unregister(User)
|
182
|
+
admin.site.unregister(Group)
|
179
183
|
|
180
184
|
|
181
185
|
@admin.register(User)
|
182
186
|
class UserAdmin(BaseUserAdmin, ModelAdmin):
|
183
187
|
pass
|
188
|
+
|
189
|
+
|
190
|
+
@admin.register(Group)
|
191
|
+
class GroupAdmin(BaseGroupAdmin, ModelAdmin):
|
192
|
+
pass
|
184
193
|
```
|
185
194
|
|
186
195
|
## Configuration
|
@@ -209,6 +218,14 @@ UNFOLD = {
|
|
209
218
|
"dark": lambda request: static("logo-dark.svg"), # dark mode
|
210
219
|
},
|
211
220
|
"SITE_SYMBOL": "speed", # symbol from icon set
|
221
|
+
"SITE_FAVICONS": [
|
222
|
+
{
|
223
|
+
"rel": "icon",
|
224
|
+
"sizes": "32x32",
|
225
|
+
"type": "image/svg+xml",
|
226
|
+
"href": lambda request: static("favicon.svg"),
|
227
|
+
},
|
228
|
+
],
|
212
229
|
"SHOW_HISTORY": True, # show/hide "History" button, default: True
|
213
230
|
"SHOW_VIEW_ON_SITE": True, # show/hide "View on site" button, default: True
|
214
231
|
"ENVIRONMENT": "sample_app.environment_callback",
|
@@ -255,6 +272,7 @@ UNFOLD = {
|
|
255
272
|
{
|
256
273
|
"title": _("Navigation"),
|
257
274
|
"separator": True, # Top border
|
275
|
+
"collapsible": True, # Collapsible group of links
|
258
276
|
"items": [
|
259
277
|
{
|
260
278
|
"title": _("Dashboard"),
|
@@ -345,6 +363,9 @@ class CustomAdminClass(ModelAdmin):
|
|
345
363
|
# Display submit button in filters
|
346
364
|
list_filter_submit = False
|
347
365
|
|
366
|
+
# Display changelist in fullwidth
|
367
|
+
list_fullwidth = False
|
368
|
+
|
348
369
|
# Position horizontal scrollbar in changelist at the top
|
349
370
|
list_horizontal_scrollbar_top = False
|
350
371
|
|
@@ -441,7 +462,7 @@ class UserAdmin(ModelAdmin):
|
|
441
462
|
actions_detail = ["change_detail_action_block"]
|
442
463
|
actions_submit_line = ["submit_line_action_activate"]
|
443
464
|
|
444
|
-
@action(description=_("Save & Activate"))
|
465
|
+
@action(description=_("Save & Activate"), permissions=["submit_line_action_activate"])
|
445
466
|
def submit_line_action_activate(self, request: HttpRequest, obj: User):
|
446
467
|
"""
|
447
468
|
If instance is modified in any way, it also needs to be saved,
|
@@ -453,6 +474,9 @@ class UserAdmin(ModelAdmin):
|
|
453
474
|
obj.is_active = True
|
454
475
|
obj.save()
|
455
476
|
|
477
|
+
def has_submit_line_action_activate_permission(self, request: HttpRequest, object_id: Union[str, int]):
|
478
|
+
pass
|
479
|
+
|
456
480
|
@action(description=_("Import"), url_path="import")
|
457
481
|
def changelist_global_action_import(self, request: HttpRequest):
|
458
482
|
"""
|
@@ -477,7 +501,7 @@ class UserAdmin(ModelAdmin):
|
|
477
501
|
"""
|
478
502
|
return redirect(f"https://example.com/{object_id}")
|
479
503
|
|
480
|
-
@action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"})
|
504
|
+
@action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"}, permissions=["change_detail_action_block"])
|
481
505
|
def change_detail_action_block(self, request: HttpRequest, object_id: int):
|
482
506
|
"""
|
483
507
|
Handler for detail action.
|
@@ -492,6 +516,10 @@ class UserAdmin(ModelAdmin):
|
|
492
516
|
return redirect(
|
493
517
|
reverse_lazy("admin:users_user_change", args=(object_id,))
|
494
518
|
)
|
519
|
+
|
520
|
+
|
521
|
+
def has_change_detail_action_block_permission(self, request: HttpRequest, object_id: Union[str, int]):
|
522
|
+
pass
|
495
523
|
```
|
496
524
|
|
497
525
|
### Action with form example
|
@@ -563,7 +591,7 @@ Text input field which allows filtering by the free string submitted by the user
|
|
563
591
|
|
564
592
|
`FieldTextFilter` requires just a model field name and the filter will make `__icontains` search on this field. There are no other things to configure so the integration in `list_filter` will be just one new row looking like `("model_field_name", FieldTextFilter)`.
|
565
593
|
|
566
|
-
In the case of the `TextFilter`, it is needed
|
594
|
+
In the case of the `TextFilter`, it is needed to write a whole new class inheriting from `TextFilter` with a custom implementation of the `queryset` method and the `parameter_name` attribute. This attribute will be a representation of the search query parameter name in URI. The benefit of the `TextFilter` is the possibility of writing complex queries.
|
567
595
|
|
568
596
|
```python
|
569
597
|
from django.contrib import admin
|
@@ -598,7 +626,7 @@ class MyAdmin(ModelAdmin):
|
|
598
626
|
|
599
627
|
Dropdown filters will display a select field with a list of options. Unfold contains two types of dropdowns: `ChoicesDropdownFilter` and `RelatedDropdownFilter`.
|
600
628
|
|
601
|
-
The difference between them is that `ChoicesDropdownFilter` will collect a list of options based on the `choices` attribute of the model field so most commonly it will be used in combination with `CharField` with specified `choices`. On the other
|
629
|
+
The difference between them is that `ChoicesDropdownFilter` will collect a list of options based on the `choices` attribute of the model field so most commonly it will be used in combination with `CharField` with specified `choices`. On the other hand, `RelatedDropdownFilter` needs a one-to-many or many-to-many foreign key to display options.
|
602
630
|
|
603
631
|
**Note:** At the moment Unfold does not implement a dropdown with an autocomplete functionality, so it is important not to use dropdowns displaying large datasets.
|
604
632
|
|
@@ -907,6 +935,19 @@ class MyModelAdmin(ModelAdmin):
|
|
907
935
|
)
|
908
936
|
```
|
909
937
|
|
938
|
+
Inlines can be grouped into tab navigation by specifying `tab` attribute in the inline class.
|
939
|
+
|
940
|
+
```python
|
941
|
+
# admin.py
|
942
|
+
|
943
|
+
from unfold.admin import TabularInline
|
944
|
+
|
945
|
+
|
946
|
+
class MyInline(TabularInline):
|
947
|
+
model = User
|
948
|
+
tab = True
|
949
|
+
```
|
950
|
+
|
910
951
|
## Third party packages
|
911
952
|
|
912
953
|
### django-celery-beat
|
@@ -976,11 +1017,11 @@ class ClockedScheduleAdmin(BaseClockedScheduleAdmin, ModelAdmin):
|
|
976
1017
|
|
977
1018
|
### django-guardian
|
978
1019
|
|
979
|
-
Adding support for django-guardian is
|
1020
|
+
Adding support for django-guardian is quite straightforward in Unfold, just add `unfold.contrib.guardian` to `INSTALLED_APPS` at the beginning of the file. This action will override all templates coming from the django-guardian. Please note that **Object permissions** link is available in top right dropdown navigation.
|
980
1021
|
|
981
1022
|
### django-import-export
|
982
1023
|
|
983
|
-
1. Add `unfold.contrib.import_export` to `INSTALLED_APPS` at the
|
1024
|
+
1. Add `unfold.contrib.import_export` to `INSTALLED_APPS` at the beginning of the file. This action will override all templates coming from the application.
|
984
1025
|
2. Change `import_form_class` and `export_form_class` in ModelAdmin which is inheriting from `ImportExportModelAdmin`. This chunk of code is responsible for adding proper styling to form elements.
|
985
1026
|
|
986
1027
|
```python
|
@@ -1052,7 +1093,7 @@ This application is supported in Unfold by default. It is not needed to add any
|
|
1052
1093
|
|
1053
1094
|
### django-simple-history
|
1054
1095
|
|
1055
|
-
To make this application work, add `unfold.contrib.simple_history` into `settings.py` in `INSTALLED_APPS` variable before right after `unfold`. This app should ensure that templates coming from django-simple-history are
|
1096
|
+
To make this application work, add `unfold.contrib.simple_history` into `settings.py` in `INSTALLED_APPS` variable before right after `unfold`. This app should ensure that templates coming from django-simple-history are overridden by Unfold.
|
1056
1097
|
|
1057
1098
|
## User Admin Form
|
1058
1099
|
|
@@ -1133,7 +1174,7 @@ npx tailwindcss -o your_project/static/css/styles.css --watch --minify
|
|
1133
1174
|
|
1134
1175
|
### Overriding template
|
1135
1176
|
|
1136
|
-
Create `templates/admin/index.html` in your project and paste the base template below into it. By default, all your custom styles here are not compiled because CSS classes are located in your specific project. Here it is needed to set up the Tailwind for your project and all
|
1177
|
+
Create `templates/admin/index.html` in your project and paste the base template below into it. By default, all your custom styles here are not compiled because CSS classes are located in your specific project. Here it is needed to set up the Tailwind for your project and all required instructions are located in [Project Level Tailwind Stylesheet](#project-level-tailwind-stylesheet) chapter.
|
1137
1178
|
|
1138
1179
|
```html+django
|
1139
1180
|
{% extends 'unfold/layouts/base_simple.html' %}
|
@@ -1255,7 +1296,7 @@ Below you can find a more complex example which is using multiple components and
|
|
1255
1296
|
|
1256
1297
|
### Pre-commit
|
1257
1298
|
|
1258
|
-
Before adding any source code, it is recommended to have pre-commit installed on your local computer to check for all potential issues when
|
1299
|
+
Before adding any source code, it is recommended to have pre-commit installed on your local computer to check for all potential issues when committing the code.
|
1259
1300
|
|
1260
1301
|
```bash
|
1261
1302
|
pip install pre-commit
|
@@ -1275,7 +1316,7 @@ To add a new feature or fix the easiest approach is to use django-unfold in comb
|
|
1275
1316
|
|
1276
1317
|
### Compiling Tailwind
|
1277
1318
|
|
1278
|
-
At the moment project contains package.json with all dependencies required to compile new CSS file. Tailwind configuration file is set to check all html, js and py files for Tailwind's
|
1319
|
+
At the moment project contains package.json with all dependencies required to compile new CSS file. Tailwind configuration file is set to check all html, js and py files for Tailwind's classes occurrences.
|
1279
1320
|
|
1280
1321
|
```bash
|
1281
1322
|
npm install
|
@@ -1285,7 +1326,7 @@ npm run tailwind:watch # run after each change in code
|
|
1285
1326
|
npm run tailwind:build # run once
|
1286
1327
|
```
|
1287
1328
|
|
1288
|
-
Some components like datepickers, calendars or selectors in admin was not possible to style by overriding html templates so their default styles are
|
1329
|
+
Some components like datepickers, calendars or selectors in admin was not possible to style by overriding html templates so their default styles are overridden in **styles.css**.
|
1289
1330
|
|
1290
1331
|
**Note:** most of the custom styles located in style.css are created via `@apply some-tailwind-class;` as is not possible to manually add CSS class to element which are for example created via jQuery.
|
1291
1332
|
|
@@ -9,7 +9,7 @@
|
|
9
9
|

|
10
10
|

|
11
11
|
|
12
|
-
Unfold is theme for Django admin incorporating most common
|
12
|
+
Unfold is a theme for Django admin incorporating most common practices for building full-fledged admin areas. It is designed to work on top of default administration provided by Django.
|
13
13
|
|
14
14
|
- **Unfold:** demo site is available at [unfoldadmin.com](https://unfoldadmin.com?utm_medium=github&utm_source=unfold)
|
15
15
|
- **Formula:** repository with demo implementation at [github.com/unfoldadmin/formula](https://github.com/unfoldadmin/formula)
|
@@ -21,7 +21,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
|
|
21
21
|
|
22
22
|
## Features <!-- omit from toc -->
|
23
23
|
|
24
|
-
- **Visual**: provides new user interface based on Tailwind CSS framework
|
24
|
+
- **Visual**: provides a new user interface based on Tailwind CSS framework
|
25
25
|
- **Sidebar:** simplifies definition of custom sidebar navigation with icons
|
26
26
|
- **Dark mode:** supports both light and dark mode versions
|
27
27
|
- **Configuration:** most of the basic options can be changed in settings.py
|
@@ -31,14 +31,16 @@ Did you decide to start using Unfold but you don't have time to make the switch
|
|
31
31
|
- **Array widget:** built-in widget for `django.contrib.postgres.fields.ArrayField`
|
32
32
|
- **Filters:** custom dropdown, numeric, datetime, and text fields
|
33
33
|
- **Dashboard:** custom components for rapid dashboard development
|
34
|
+
- **Inline tabs:** group inlines into tab navigation in the change form
|
34
35
|
- **Model tabs:** define custom tab navigations for models
|
35
|
-
- **Fieldset tabs:** merge several
|
36
|
-
- **Colors:** possibility to override default color scheme
|
37
|
-
- **Changeform modes:** display fields in
|
36
|
+
- **Fieldset tabs:** merge several fieldsets into tabs in the change form
|
37
|
+
- **Colors:** possibility to override the default color scheme
|
38
|
+
- **Changeform modes:** display fields in the change form in compressed mode
|
38
39
|
- **Third party packages:** default support for multiple popular applications
|
39
40
|
- **Environment label**: distinguish between environments by displaying a label
|
40
41
|
- **Nonrelated inlines**: displays nonrelated model as inline in changeform
|
41
42
|
- **Parallel admin**: support for default admin in parallel with Unfold. [Admin migration guide](https://unfoldadmin.com/blog/migrating-django-admin-unfold/?utm_medium=github&utm_source=unfold)
|
43
|
+
- **Favicons**: built-in support for configuring various site favicons
|
42
44
|
- **VS Code**: project configuration and development container is included
|
43
45
|
|
44
46
|
## Table of contents <!-- omit from toc -->
|
@@ -87,7 +89,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
|
|
87
89
|
|
88
90
|
## Installation
|
89
91
|
|
90
|
-
The installation process is minimal. Everything
|
92
|
+
The installation process is minimal. Everything that is needed after installation is to put new application at the beginning of **INSTALLED_APPS**. The default admin configuration in urls.py can stay as it is, and no changes are required.
|
91
93
|
|
92
94
|
```python
|
93
95
|
# settings.py
|
@@ -146,17 +148,24 @@ class CustomAdminClass(ModelAdmin):
|
|
146
148
|
|
147
149
|
from django.contrib import admin
|
148
150
|
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
151
|
+
from django.contrib.auth.admin import GroupAdmin as BaseGroupAdmin
|
149
152
|
from django.contrib.auth.models import User
|
150
153
|
|
151
154
|
from unfold.admin import ModelAdmin
|
152
155
|
|
153
156
|
|
154
157
|
admin.site.unregister(User)
|
158
|
+
admin.site.unregister(Group)
|
155
159
|
|
156
160
|
|
157
161
|
@admin.register(User)
|
158
162
|
class UserAdmin(BaseUserAdmin, ModelAdmin):
|
159
163
|
pass
|
164
|
+
|
165
|
+
|
166
|
+
@admin.register(Group)
|
167
|
+
class GroupAdmin(BaseGroupAdmin, ModelAdmin):
|
168
|
+
pass
|
160
169
|
```
|
161
170
|
|
162
171
|
## Configuration
|
@@ -185,6 +194,14 @@ UNFOLD = {
|
|
185
194
|
"dark": lambda request: static("logo-dark.svg"), # dark mode
|
186
195
|
},
|
187
196
|
"SITE_SYMBOL": "speed", # symbol from icon set
|
197
|
+
"SITE_FAVICONS": [
|
198
|
+
{
|
199
|
+
"rel": "icon",
|
200
|
+
"sizes": "32x32",
|
201
|
+
"type": "image/svg+xml",
|
202
|
+
"href": lambda request: static("favicon.svg"),
|
203
|
+
},
|
204
|
+
],
|
188
205
|
"SHOW_HISTORY": True, # show/hide "History" button, default: True
|
189
206
|
"SHOW_VIEW_ON_SITE": True, # show/hide "View on site" button, default: True
|
190
207
|
"ENVIRONMENT": "sample_app.environment_callback",
|
@@ -231,6 +248,7 @@ UNFOLD = {
|
|
231
248
|
{
|
232
249
|
"title": _("Navigation"),
|
233
250
|
"separator": True, # Top border
|
251
|
+
"collapsible": True, # Collapsible group of links
|
234
252
|
"items": [
|
235
253
|
{
|
236
254
|
"title": _("Dashboard"),
|
@@ -321,6 +339,9 @@ class CustomAdminClass(ModelAdmin):
|
|
321
339
|
# Display submit button in filters
|
322
340
|
list_filter_submit = False
|
323
341
|
|
342
|
+
# Display changelist in fullwidth
|
343
|
+
list_fullwidth = False
|
344
|
+
|
324
345
|
# Position horizontal scrollbar in changelist at the top
|
325
346
|
list_horizontal_scrollbar_top = False
|
326
347
|
|
@@ -417,7 +438,7 @@ class UserAdmin(ModelAdmin):
|
|
417
438
|
actions_detail = ["change_detail_action_block"]
|
418
439
|
actions_submit_line = ["submit_line_action_activate"]
|
419
440
|
|
420
|
-
@action(description=_("Save & Activate"))
|
441
|
+
@action(description=_("Save & Activate"), permissions=["submit_line_action_activate"])
|
421
442
|
def submit_line_action_activate(self, request: HttpRequest, obj: User):
|
422
443
|
"""
|
423
444
|
If instance is modified in any way, it also needs to be saved,
|
@@ -429,6 +450,9 @@ class UserAdmin(ModelAdmin):
|
|
429
450
|
obj.is_active = True
|
430
451
|
obj.save()
|
431
452
|
|
453
|
+
def has_submit_line_action_activate_permission(self, request: HttpRequest, object_id: Union[str, int]):
|
454
|
+
pass
|
455
|
+
|
432
456
|
@action(description=_("Import"), url_path="import")
|
433
457
|
def changelist_global_action_import(self, request: HttpRequest):
|
434
458
|
"""
|
@@ -453,7 +477,7 @@ class UserAdmin(ModelAdmin):
|
|
453
477
|
"""
|
454
478
|
return redirect(f"https://example.com/{object_id}")
|
455
479
|
|
456
|
-
@action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"})
|
480
|
+
@action(description=_("Detail"), url_path="detail-action", attrs={"target": "_blank"}, permissions=["change_detail_action_block"])
|
457
481
|
def change_detail_action_block(self, request: HttpRequest, object_id: int):
|
458
482
|
"""
|
459
483
|
Handler for detail action.
|
@@ -468,6 +492,10 @@ class UserAdmin(ModelAdmin):
|
|
468
492
|
return redirect(
|
469
493
|
reverse_lazy("admin:users_user_change", args=(object_id,))
|
470
494
|
)
|
495
|
+
|
496
|
+
|
497
|
+
def has_change_detail_action_block_permission(self, request: HttpRequest, object_id: Union[str, int]):
|
498
|
+
pass
|
471
499
|
```
|
472
500
|
|
473
501
|
### Action with form example
|
@@ -539,7 +567,7 @@ Text input field which allows filtering by the free string submitted by the user
|
|
539
567
|
|
540
568
|
`FieldTextFilter` requires just a model field name and the filter will make `__icontains` search on this field. There are no other things to configure so the integration in `list_filter` will be just one new row looking like `("model_field_name", FieldTextFilter)`.
|
541
569
|
|
542
|
-
In the case of the `TextFilter`, it is needed
|
570
|
+
In the case of the `TextFilter`, it is needed to write a whole new class inheriting from `TextFilter` with a custom implementation of the `queryset` method and the `parameter_name` attribute. This attribute will be a representation of the search query parameter name in URI. The benefit of the `TextFilter` is the possibility of writing complex queries.
|
543
571
|
|
544
572
|
```python
|
545
573
|
from django.contrib import admin
|
@@ -574,7 +602,7 @@ class MyAdmin(ModelAdmin):
|
|
574
602
|
|
575
603
|
Dropdown filters will display a select field with a list of options. Unfold contains two types of dropdowns: `ChoicesDropdownFilter` and `RelatedDropdownFilter`.
|
576
604
|
|
577
|
-
The difference between them is that `ChoicesDropdownFilter` will collect a list of options based on the `choices` attribute of the model field so most commonly it will be used in combination with `CharField` with specified `choices`. On the other
|
605
|
+
The difference between them is that `ChoicesDropdownFilter` will collect a list of options based on the `choices` attribute of the model field so most commonly it will be used in combination with `CharField` with specified `choices`. On the other hand, `RelatedDropdownFilter` needs a one-to-many or many-to-many foreign key to display options.
|
578
606
|
|
579
607
|
**Note:** At the moment Unfold does not implement a dropdown with an autocomplete functionality, so it is important not to use dropdowns displaying large datasets.
|
580
608
|
|
@@ -883,6 +911,19 @@ class MyModelAdmin(ModelAdmin):
|
|
883
911
|
)
|
884
912
|
```
|
885
913
|
|
914
|
+
Inlines can be grouped into tab navigation by specifying `tab` attribute in the inline class.
|
915
|
+
|
916
|
+
```python
|
917
|
+
# admin.py
|
918
|
+
|
919
|
+
from unfold.admin import TabularInline
|
920
|
+
|
921
|
+
|
922
|
+
class MyInline(TabularInline):
|
923
|
+
model = User
|
924
|
+
tab = True
|
925
|
+
```
|
926
|
+
|
886
927
|
## Third party packages
|
887
928
|
|
888
929
|
### django-celery-beat
|
@@ -952,11 +993,11 @@ class ClockedScheduleAdmin(BaseClockedScheduleAdmin, ModelAdmin):
|
|
952
993
|
|
953
994
|
### django-guardian
|
954
995
|
|
955
|
-
Adding support for django-guardian is
|
996
|
+
Adding support for django-guardian is quite straightforward in Unfold, just add `unfold.contrib.guardian` to `INSTALLED_APPS` at the beginning of the file. This action will override all templates coming from the django-guardian. Please note that **Object permissions** link is available in top right dropdown navigation.
|
956
997
|
|
957
998
|
### django-import-export
|
958
999
|
|
959
|
-
1. Add `unfold.contrib.import_export` to `INSTALLED_APPS` at the
|
1000
|
+
1. Add `unfold.contrib.import_export` to `INSTALLED_APPS` at the beginning of the file. This action will override all templates coming from the application.
|
960
1001
|
2. Change `import_form_class` and `export_form_class` in ModelAdmin which is inheriting from `ImportExportModelAdmin`. This chunk of code is responsible for adding proper styling to form elements.
|
961
1002
|
|
962
1003
|
```python
|
@@ -1028,7 +1069,7 @@ This application is supported in Unfold by default. It is not needed to add any
|
|
1028
1069
|
|
1029
1070
|
### django-simple-history
|
1030
1071
|
|
1031
|
-
To make this application work, add `unfold.contrib.simple_history` into `settings.py` in `INSTALLED_APPS` variable before right after `unfold`. This app should ensure that templates coming from django-simple-history are
|
1072
|
+
To make this application work, add `unfold.contrib.simple_history` into `settings.py` in `INSTALLED_APPS` variable before right after `unfold`. This app should ensure that templates coming from django-simple-history are overridden by Unfold.
|
1032
1073
|
|
1033
1074
|
## User Admin Form
|
1034
1075
|
|
@@ -1109,7 +1150,7 @@ npx tailwindcss -o your_project/static/css/styles.css --watch --minify
|
|
1109
1150
|
|
1110
1151
|
### Overriding template
|
1111
1152
|
|
1112
|
-
Create `templates/admin/index.html` in your project and paste the base template below into it. By default, all your custom styles here are not compiled because CSS classes are located in your specific project. Here it is needed to set up the Tailwind for your project and all
|
1153
|
+
Create `templates/admin/index.html` in your project and paste the base template below into it. By default, all your custom styles here are not compiled because CSS classes are located in your specific project. Here it is needed to set up the Tailwind for your project and all required instructions are located in [Project Level Tailwind Stylesheet](#project-level-tailwind-stylesheet) chapter.
|
1113
1154
|
|
1114
1155
|
```html+django
|
1115
1156
|
{% extends 'unfold/layouts/base_simple.html' %}
|
@@ -1231,7 +1272,7 @@ Below you can find a more complex example which is using multiple components and
|
|
1231
1272
|
|
1232
1273
|
### Pre-commit
|
1233
1274
|
|
1234
|
-
Before adding any source code, it is recommended to have pre-commit installed on your local computer to check for all potential issues when
|
1275
|
+
Before adding any source code, it is recommended to have pre-commit installed on your local computer to check for all potential issues when committing the code.
|
1235
1276
|
|
1236
1277
|
```bash
|
1237
1278
|
pip install pre-commit
|
@@ -1251,7 +1292,7 @@ To add a new feature or fix the easiest approach is to use django-unfold in comb
|
|
1251
1292
|
|
1252
1293
|
### Compiling Tailwind
|
1253
1294
|
|
1254
|
-
At the moment project contains package.json with all dependencies required to compile new CSS file. Tailwind configuration file is set to check all html, js and py files for Tailwind's
|
1295
|
+
At the moment project contains package.json with all dependencies required to compile new CSS file. Tailwind configuration file is set to check all html, js and py files for Tailwind's classes occurrences.
|
1255
1296
|
|
1256
1297
|
```bash
|
1257
1298
|
npm install
|
@@ -1261,7 +1302,7 @@ npm run tailwind:watch # run after each change in code
|
|
1261
1302
|
npm run tailwind:build # run once
|
1262
1303
|
```
|
1263
1304
|
|
1264
|
-
Some components like datepickers, calendars or selectors in admin was not possible to style by overriding html templates so their default styles are
|
1305
|
+
Some components like datepickers, calendars or selectors in admin was not possible to style by overriding html templates so their default styles are overridden in **styles.css**.
|
1265
1306
|
|
1266
1307
|
**Note:** most of the custom styles located in style.css are created via `@apply some-tailwind-class;` as is not possible to manually add CSS class to element which are for example created via jQuery.
|
1267
1308
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import copy
|
2
2
|
from functools import update_wrapper
|
3
|
-
from typing import Any, Callable, Dict, List, Optional, Tuple
|
3
|
+
from typing import Any, Callable, Dict, List, Optional, Tuple, Union
|
4
4
|
|
5
5
|
from django import forms
|
6
6
|
from django.contrib.admin import ModelAdmin as BaseModelAdmin
|
@@ -148,6 +148,7 @@ class ModelAdminMixin:
|
|
148
148
|
else:
|
149
149
|
kwargs["widget"] = UnfoldAdminSelectWidget()
|
150
150
|
|
151
|
+
if "choices" not in kwargs:
|
151
152
|
kwargs["choices"] = db_field.get_choices(
|
152
153
|
include_blank=db_field.blank, blank_choice=[("", _("Select value"))]
|
153
154
|
)
|
@@ -229,6 +230,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
229
230
|
add_fieldsets = ()
|
230
231
|
list_horizontal_scrollbar_top = False
|
231
232
|
list_filter_submit = False
|
233
|
+
list_fullwidth = False
|
232
234
|
compressed_fields = False
|
233
235
|
readonly_preprocess_fields = {}
|
234
236
|
checks_class = UnfoldModelAdminChecks
|
@@ -255,7 +257,10 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
255
257
|
return super().get_fieldsets(request, obj)
|
256
258
|
|
257
259
|
def _filter_unfold_actions_by_permissions(
|
258
|
-
self,
|
260
|
+
self,
|
261
|
+
request: HttpRequest,
|
262
|
+
actions: List[UnfoldAction],
|
263
|
+
object_id: Optional[Union[int, str]] = None,
|
259
264
|
) -> List[UnfoldAction]:
|
260
265
|
"""Filter out any Unfold actions that the user doesn't have access to."""
|
261
266
|
filtered_actions = []
|
@@ -263,12 +268,22 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
263
268
|
if not hasattr(action.method, "allowed_permissions"):
|
264
269
|
filtered_actions.append(action)
|
265
270
|
continue
|
271
|
+
|
266
272
|
permission_checks = (
|
267
273
|
getattr(self, f"has_{permission}_permission")
|
268
274
|
for permission in action.method.allowed_permissions
|
269
275
|
)
|
270
|
-
|
271
|
-
|
276
|
+
|
277
|
+
if object_id:
|
278
|
+
if any(
|
279
|
+
has_permission(request, object_id)
|
280
|
+
for has_permission in permission_checks
|
281
|
+
):
|
282
|
+
filtered_actions.append(action)
|
283
|
+
else:
|
284
|
+
if any(has_permission(request) for has_permission in permission_checks):
|
285
|
+
filtered_actions.append(action)
|
286
|
+
|
272
287
|
return filtered_actions
|
273
288
|
|
274
289
|
def get_actions_list(self, request: HttpRequest) -> List[UnfoldAction]:
|
@@ -282,9 +297,11 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
282
297
|
"""
|
283
298
|
return [self.get_unfold_action(action) for action in self.actions_list or []]
|
284
299
|
|
285
|
-
def get_actions_detail(
|
300
|
+
def get_actions_detail(
|
301
|
+
self, request: HttpRequest, object_id: int
|
302
|
+
) -> List[UnfoldAction]:
|
286
303
|
return self._filter_unfold_actions_by_permissions(
|
287
|
-
request, self._get_base_actions_detail()
|
304
|
+
request, self._get_base_actions_detail(), object_id
|
288
305
|
)
|
289
306
|
|
290
307
|
def _get_base_actions_detail(self) -> List[UnfoldAction]:
|
@@ -304,9 +321,11 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
304
321
|
"""
|
305
322
|
return [self.get_unfold_action(action) for action in self.actions_row or []]
|
306
323
|
|
307
|
-
def get_actions_submit_line(
|
324
|
+
def get_actions_submit_line(
|
325
|
+
self, request: HttpRequest, object_id: int
|
326
|
+
) -> List[UnfoldAction]:
|
308
327
|
return self._filter_unfold_actions_by_permissions(
|
309
|
-
request, self._get_base_actions_submit_line()
|
328
|
+
request, self._get_base_actions_submit_line(), object_id
|
310
329
|
)
|
311
330
|
|
312
331
|
def _get_base_actions_submit_line(self) -> List[UnfoldAction]:
|
@@ -404,7 +423,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
404
423
|
|
405
424
|
actions = []
|
406
425
|
if object_id:
|
407
|
-
for action in self.get_actions_detail(request):
|
426
|
+
for action in self.get_actions_detail(request, object_id):
|
408
427
|
actions.append(
|
409
428
|
{
|
410
429
|
"title": action.description,
|
@@ -418,7 +437,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
418
437
|
|
419
438
|
extra_context.update(
|
420
439
|
{
|
421
|
-
"actions_submit_line": self.get_actions_submit_line(request),
|
440
|
+
"actions_submit_line": self.get_actions_submit_line(request, object_id),
|
422
441
|
"actions_detail": actions,
|
423
442
|
}
|
424
443
|
)
|
@@ -485,7 +504,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
485
504
|
) -> None:
|
486
505
|
super().save_model(request, obj, form, change)
|
487
506
|
|
488
|
-
for action in self.get_actions_submit_line(request):
|
507
|
+
for action in self.get_actions_submit_line(request, obj.pk):
|
489
508
|
if action.action_name not in request.POST:
|
490
509
|
continue
|
491
510
|
|
@@ -9,11 +9,11 @@
|
|
9
9
|
|
10
10
|
{% if choice.min is not None and choice.max is not None and choice.step %}
|
11
11
|
<div class="admin-numeric-filter-slider-tooltips">
|
12
|
-
<span class="admin-numeric-filter-slider-tooltip-from border cursor-not-allowed flex flex-grow flex-row items-center mr-auto rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-
|
12
|
+
<span class="admin-numeric-filter-slider-tooltip-from border cursor-not-allowed flex flex-grow flex-row items-center mr-auto rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
|
13
13
|
{{ choice.value_from }}
|
14
14
|
</span>
|
15
15
|
|
16
|
-
<span class="admin-numeric-filter-slider-tooltip-to border cursor-not-allowed flex flex-grow flex-row items-center rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-
|
16
|
+
<span class="admin-numeric-filter-slider-tooltip-to border cursor-not-allowed flex flex-grow flex-row items-center rounded-md shadow-sm px-3 py-2 w-full dark:bg-gray-900 dark:border-gray-700 dark:text-gray-300">
|
17
17
|
{{ choice.value_to }}
|
18
18
|
</span>
|
19
19
|
</div>
|
@@ -25,7 +25,7 @@
|
|
25
25
|
{{ choice.form.as_p }}
|
26
26
|
</div>
|
27
27
|
{% else %}
|
28
|
-
<div class="admin-numeric-filter-slider-error dark:text-gray-
|
28
|
+
<div class="admin-numeric-filter-slider-error dark:text-gray-300">
|
29
29
|
<p>
|
30
30
|
{% trans 'Not enough data.' %}
|
31
31
|
</p>
|
@@ -15,7 +15,9 @@
|
|
15
15
|
|
16
16
|
<template x-for="(item, index) in items" :key="item.key">
|
17
17
|
<div class="flex flex-row">
|
18
|
-
{%
|
18
|
+
{% with widget=template %}
|
19
|
+
{% include template.template_name %}
|
20
|
+
{% endwith %}
|
19
21
|
|
20
22
|
<a x-on:click="items.splice(index, 1)" class="bg-white border cursor-pointer flex items-center h-9.5 justify-center ml-2 rounded shadow-sm shrink-0 text-red-600 text-sm w-9.5 dark:bg-gray-900 dark:border-gray-700 dark:text-red-500">
|
21
23
|
<span class="material-symbols-outlined text-sm">delete</span>
|