django-unfold 0.58.0__tar.gz → 0.60.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {django_unfold-0.58.0 → django_unfold-0.60.0}/PKG-INFO +3 -2
- {django_unfold-0.58.0 → django_unfold-0.60.0}/README.md +2 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/pyproject.toml +2 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/admin.py +45 -13
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/checks.py +24 -2
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +2 -2
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/admin.py +11 -6
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/forms.py +3 -1
- django_unfold-0.60.0/src/unfold/contrib/location_field/apps.py +6 -0
- django_unfold-0.60.0/src/unfold/contrib/location_field/templates/location_field/map_widget.html +5 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/decorators.py +27 -13
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/fields.py +18 -20
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/forms.py +99 -3
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/layout.py +16 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/mixins/action_model_admin.py +22 -14
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/mixins/base_model_admin.py +15 -1
- django_unfold-0.60.0/src/unfold/paginator.py +21 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/settings.py +8 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/sites.py +27 -29
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/admin/js/admin/RelatedObjectLookups.js +9 -3
- django_unfold-0.60.0/src/unfold/static/unfold/css/styles.css +2 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/styles.css +12 -16
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/app_list.html +4 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/base.html +1 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_form.html +2 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/edit_inline/stacked.html +12 -8
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/edit_inline/tabular.html +2 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/includes/fieldset.html +9 -3
- django_unfold-0.60.0/src/unfold/templates/admin/login.html +62 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/pagination.html +1 -1
- django_unfold-0.60.0/src/unfold/templates/unfold/components/button.html +13 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/account_links.html +14 -6
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/app_list.html +5 -2
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/app_list_default.html +2 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/change_list_actions.html +2 -2
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/change_list_filter_actions.html +1 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_heading.html +1 -1
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/empty_results.html +2 -2
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/field.html +5 -3
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/header.html +1 -1
- django_unfold-0.60.0/src/unfold/templates/unfold/helpers/language_form.html +10 -0
- django_unfold-0.60.0/src/unfold/templates/unfold/helpers/language_switch.html +25 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/navigation.html +1 -1
- django_unfold-0.60.0/src/unfold/templates/unfold/helpers/pagination_infinite.html +11 -0
- django_unfold-0.60.0/src/unfold/templates/unfold/helpers/pagination_inline.html +28 -0
- django_unfold-0.60.0/src/unfold/templates/unfold/helpers/theme_switch.html +34 -0
- django_unfold-0.60.0/src/unfold/templates/unfold/helpers/unauthenticated_header.html +15 -0
- django_unfold-0.60.0/src/unfold/templates/unfold/helpers/unauthenticated_title.html +11 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/userlinks.html +2 -6
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/welcomemsg.html +9 -7
- django_unfold-0.60.0/src/unfold/templates/unfold/layouts/unauthenticated.html +37 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/select.html +1 -1
- django_unfold-0.60.0/src/unfold/templates/unfold/widgets/text.html +28 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/fieldset.html +3 -1
- django_unfold-0.60.0/src/unfold/templates/unfold_crispy/layout/fieldset_subheader.html +3 -0
- django_unfold-0.60.0/src/unfold/templatetags/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templatetags/unfold.py +37 -2
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/utils.py +2 -2
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/widgets.py +49 -3
- django_unfold-0.58.0/src/unfold/paginator.py +0 -10
- django_unfold-0.58.0/src/unfold/static/unfold/css/styles.css +0 -2
- django_unfold-0.58.0/src/unfold/templates/admin/login.html +0 -105
- django_unfold-0.58.0/src/unfold/templates/unfold/components/button.html +0 -4
- django_unfold-0.58.0/src/unfold/templates/unfold/helpers/language_switch.html +0 -27
- django_unfold-0.58.0/src/unfold/templates/unfold/helpers/pagination_infinite.html +0 -11
- django_unfold-0.58.0/src/unfold/templates/unfold/helpers/theme_switch.html +0 -32
- {django_unfold-0.58.0 → django_unfold-0.60.0}/LICENSE.md +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/apps.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/components.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/autocomplete_filters.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/choice_filters.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/datetime_filters.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/dropdown_filters.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/mixins.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/numeric_filters.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/text_filters.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/apps.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/forms.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/css/nouislider/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/css/nouislider/nouislider.min.css +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/DateTimeShortcuts.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/nouislider/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/nouislider/nouislider.min.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/wnumb/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/wnumb/wNumb.min.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_date_range.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_datetime_range.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_field.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_range.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_single.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/apps.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/css/trix/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/css/trix/trix.css +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix/trix.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix.config.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/templates/unfold/forms/array.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/templates/unfold/forms/wysiwyg.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/widgets.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/apps.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/change_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/field.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_group.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage_user.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/unfold/guardian/group_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/unfold/guardian/user_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/apps.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/forms.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/base.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_export.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_export_item.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_import_export.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_list_import_item.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/export.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_confirm.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_errors.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_preview.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_validation.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/resource_fields_list.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/apps.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/checks.py +0 -0
- {django_unfold-0.58.0/src/unfold/contrib/simple_history → django_unfold-0.60.0/src/unfold/contrib/location_field}/__init__.py +0 -0
- {django_unfold-0.58.0/src/unfold/templatetags → django_unfold-0.60.0/src/unfold/contrib/simple_history}/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/apps.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history_list.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/templates/simple_history/submit_line.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/dataclasses.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/enums.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/exceptions.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/mixins/__init__.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/overrides.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/sections.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/admin/js/inlines.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/css/simplebar/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/css/simplebar/simplebar.css +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/Inter-Bold.woff2 +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/Inter-Medium.woff2 +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/Inter-Regular.woff2 +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/Inter-SemiBold.woff2 +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/styles.css +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/material-symbols/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/material-symbols/Material-Symbols-Outlined.woff2 +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/material-symbols/styles.css +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.anchor.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.persist.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.resize.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.sort.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/app.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/chart/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/chart/chart.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/htmx/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/htmx/htmx.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/select2.init.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/simplebar/LICENSE +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/simplebar/simplebar.js +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/actions.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/app_index.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/auth/user/add_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/auth/user/change_password.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/base_site.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_form_object_tools.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_list.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_list_object_tools.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_list_results.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/date_hierarchy.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/delete_confirmation.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/delete_selected_confirmation.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/filter.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/includes/object_delete_summary.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/index.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/nav_sidebar.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/object_history.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/search_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/submit_line.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/auth/widgets/read_only_password_hash.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/registration/logged_out.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/registration/password_change_done.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/registration/password_change_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/card.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/chart/bar.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/chart/cohort.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/chart/line.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/container.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/flex.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/icon.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/navigation.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/progress.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/separator.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/table.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/text.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/title.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/tracker.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/actions_row.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/add_link.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/attrs.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/boolean.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/breadcrumb_item.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/change_list_filter.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/delete_submit_line.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/display_dropdown.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/display_header.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/display_label.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_delete.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_error.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_field.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_row.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_title.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/field_readonly.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/field_readonly_value.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/fieldset_row.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/fieldset_row_checkbox.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/fieldset_row_field.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/fieldsets_tabs.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/form_errors.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/form_label.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/header_back_button.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/help_text.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/history.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/label.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/debug.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/error.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/errornote.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/info.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/success.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/warning.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/navigation_header.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/pagination.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/pagination_current_item.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/pagination_default.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/pagination_ellipsis.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/search.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/search_results.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/site_branding.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/site_dropdown.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/site_icon.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/site_logo.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/submit.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/tab_action.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/tab_actions.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/tab_items.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/tab_list.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/layouts/base.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/layouts/base_simple.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/layouts/skeleton.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/templatetags/preserve_changelist_filters.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/clearable_file_input.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/clearable_file_input_small.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/date.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/foreign_key_raw_id.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/radio.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/radio_option.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/range.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/related_widget_wrapper.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/split_datetime.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/split_datetime_vertical.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/split_money.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/textarea.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/time.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/url.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/display_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/errors.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/errors_formset.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/field.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/inputs.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/attrs.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/baseinput.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/button.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/buttonholder.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/checkbox.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/column.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/div.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/field_errors.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/help_text.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/help_text_and_errors.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/hr.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/radio_checkbox_select.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/row.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/table_inline_formset.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/uni_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/whole_uni_form.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/whole_uni_formset.html +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templatetags/unfold_list.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/typing.py +0 -0
- {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/views.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: django-unfold
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.60.0
|
4
4
|
Summary: Modern Django admin theme for seamless interface development
|
5
5
|
License: MIT
|
6
6
|
Keywords: django,admin,tailwind,theme
|
@@ -50,11 +50,11 @@ Unfold Studio is a theme customizer for Django admin that helps you create a bra
|
|
50
50
|
|
51
51
|
## Fresh Features & Enhancements
|
52
52
|
|
53
|
+
- **Paginated inlines:** Break down large record sets into pages within inlines for better admin performance
|
53
54
|
- **Conditional fields:** Show or hide fields dynamically based on the values of other fields in the form
|
54
55
|
- **Infinite paginator:** Efficiently handle large datasets with seamless pagination that reduces server load
|
55
56
|
- **Checkbox & radio filters:** Enhanced filter options with checkbox and radio interfaces for intuitive filtering
|
56
57
|
- **Site dropdown:** Configurable dropdown menu in the header area for managing custom navigation links
|
57
|
-
- **Dropdown actions:** Organize action items in customizable dropdown menus
|
58
58
|
|
59
59
|
## Core Features & Capabilities
|
60
60
|
|
@@ -74,6 +74,7 @@ Unfold Studio is a theme customizer for Django admin that helps you create a bra
|
|
74
74
|
- **Sortable inlines:** Allow sorting inlines by dragging and dropping
|
75
75
|
- **Environment label:** Distinguish between environments by displaying a label
|
76
76
|
- **Nonrelated inlines:** Display nonrelated models as inlines in the change form
|
77
|
+
- **Paginated inlines:** Break down large record sets into pages within inlines for better admin performance
|
77
78
|
- **Favicons:** Built-in support for configuring various site favicons
|
78
79
|
- **Themes:** Allow customization of color scheme, background color, border radius, and more
|
79
80
|
- **Font colors:** Adjust font colors for better readability
|
@@ -26,11 +26,11 @@ Unfold Studio is a theme customizer for Django admin that helps you create a bra
|
|
26
26
|
|
27
27
|
## Fresh Features & Enhancements
|
28
28
|
|
29
|
+
- **Paginated inlines:** Break down large record sets into pages within inlines for better admin performance
|
29
30
|
- **Conditional fields:** Show or hide fields dynamically based on the values of other fields in the form
|
30
31
|
- **Infinite paginator:** Efficiently handle large datasets with seamless pagination that reduces server load
|
31
32
|
- **Checkbox & radio filters:** Enhanced filter options with checkbox and radio interfaces for intuitive filtering
|
32
33
|
- **Site dropdown:** Configurable dropdown menu in the header area for managing custom navigation links
|
33
|
-
- **Dropdown actions:** Organize action items in customizable dropdown menus
|
34
34
|
|
35
35
|
## Core Features & Capabilities
|
36
36
|
|
@@ -50,6 +50,7 @@ Unfold Studio is a theme customizer for Django admin that helps you create a bra
|
|
50
50
|
- **Sortable inlines:** Allow sorting inlines by dragging and dropping
|
51
51
|
- **Environment label:** Distinguish between environments by displaying a label
|
52
52
|
- **Nonrelated inlines:** Display nonrelated models as inlines in the change form
|
53
|
+
- **Paginated inlines:** Break down large record sets into pages within inlines for better admin performance
|
53
54
|
- **Favicons:** Built-in support for configuring various site favicons
|
54
55
|
- **Themes:** Allow customization of color scheme, background color, border radius, and more
|
55
56
|
- **Font colors:** Adjust font colors for better readability
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "django-unfold"
|
3
|
-
version = "0.
|
3
|
+
version = "0.60.0"
|
4
4
|
description = "Modern Django admin theme for seamless interface development"
|
5
5
|
license = "MIT"
|
6
6
|
readme = "README.md"
|
@@ -29,6 +29,7 @@ django = ">=4.2"
|
|
29
29
|
[tool.poetry.group.test.dependencies]
|
30
30
|
pytest = "^8.3"
|
31
31
|
pytest-django = "^4.11"
|
32
|
+
pytest-factoryboy = "^2.7.0"
|
32
33
|
tox = "^4.26"
|
33
34
|
django-money = "^3.5"
|
34
35
|
|
@@ -1,11 +1,18 @@
|
|
1
1
|
from functools import update_wrapper
|
2
|
-
from typing import Optional
|
2
|
+
from typing import Any, Optional
|
3
3
|
|
4
4
|
from django import forms
|
5
5
|
from django.contrib.admin import ModelAdmin as BaseModelAdmin
|
6
6
|
from django.contrib.admin import StackedInline as BaseStackedInline
|
7
7
|
from django.contrib.admin import TabularInline as BaseTabularInline
|
8
8
|
from django.contrib.admin import display, helpers
|
9
|
+
from django.contrib.admin.options import InlineModelAdmin
|
10
|
+
from django.contrib.contenttypes.admin import (
|
11
|
+
GenericStackedInline as BaseGenericStackedInline,
|
12
|
+
)
|
13
|
+
from django.contrib.contenttypes.admin import (
|
14
|
+
GenericTabularInline as BaseGenericTabularInline,
|
15
|
+
)
|
9
16
|
from django.db.models import BLANK_CHOICE_DASH, Model
|
10
17
|
from django.http import HttpRequest, HttpResponse
|
11
18
|
from django.shortcuts import redirect
|
@@ -16,8 +23,11 @@ from django.utils.translation import gettext_lazy as _
|
|
16
23
|
from django.views import View
|
17
24
|
|
18
25
|
from unfold.checks import UnfoldModelAdminChecks
|
19
|
-
from unfold.
|
20
|
-
|
26
|
+
from unfold.forms import (
|
27
|
+
ActionForm,
|
28
|
+
PaginationGenericInlineFormSet,
|
29
|
+
PaginationInlineFormSet,
|
30
|
+
)
|
21
31
|
from unfold.mixins import ActionModelAdminMixin, BaseModelAdminMixin
|
22
32
|
from unfold.overrides import FORMFIELD_OVERRIDES_INLINE
|
23
33
|
from unfold.typing import FieldsetsType
|
@@ -32,10 +42,6 @@ checkbox = UnfoldBooleanWidget(
|
|
32
42
|
lambda value: False,
|
33
43
|
)
|
34
44
|
|
35
|
-
helpers.AdminField = UnfoldAdminField
|
36
|
-
|
37
|
-
helpers.AdminReadonlyField = UnfoldAdminReadonlyField
|
38
|
-
|
39
45
|
|
40
46
|
class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
|
41
47
|
action_form = ActionForm
|
@@ -182,16 +188,42 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
|
|
182
188
|
def get_changelist(self, request, **kwargs):
|
183
189
|
return ChangeList
|
184
190
|
|
191
|
+
def get_formset_kwargs(
|
192
|
+
self, request: HttpRequest, obj: Model, inline: InlineModelAdmin, prefix: str
|
193
|
+
) -> dict[str, Any]:
|
194
|
+
formset_kwargs = super().get_formset_kwargs(request, obj, inline, prefix)
|
195
|
+
formset_kwargs["request"] = request
|
185
196
|
|
186
|
-
|
187
|
-
|
188
|
-
readonly_preprocess_fields = {}
|
189
|
-
ordering_field = None
|
190
|
-
hide_ordering_field = False
|
197
|
+
if hasattr(inline, "per_page"):
|
198
|
+
formset_kwargs["per_page"] = inline.per_page
|
191
199
|
|
200
|
+
return formset_kwargs
|
192
201
|
|
193
|
-
|
202
|
+
|
203
|
+
class BaseInlineMixin:
|
194
204
|
formfield_overrides = FORMFIELD_OVERRIDES_INLINE
|
195
205
|
readonly_preprocess_fields = {}
|
196
206
|
ordering_field = None
|
207
|
+
per_page = None
|
197
208
|
hide_ordering_field = False
|
209
|
+
collapsible = False
|
210
|
+
|
211
|
+
|
212
|
+
class TabularInline(BaseInlineMixin, BaseModelAdminMixin, BaseTabularInline):
|
213
|
+
formset = PaginationInlineFormSet
|
214
|
+
|
215
|
+
|
216
|
+
class StackedInline(BaseInlineMixin, BaseModelAdminMixin, BaseStackedInline):
|
217
|
+
formset = PaginationInlineFormSet
|
218
|
+
|
219
|
+
|
220
|
+
class GenericStackedInline(
|
221
|
+
BaseInlineMixin, BaseModelAdminMixin, BaseGenericStackedInline
|
222
|
+
):
|
223
|
+
formset = PaginationGenericInlineFormSet
|
224
|
+
|
225
|
+
|
226
|
+
class GenericTabularInline(
|
227
|
+
BaseInlineMixin, BaseModelAdminMixin, BaseGenericTabularInline
|
228
|
+
):
|
229
|
+
formset = PaginationGenericInlineFormSet
|
@@ -2,9 +2,10 @@ from typing import Any
|
|
2
2
|
|
3
3
|
from django.contrib.admin.checks import ModelAdminChecks
|
4
4
|
from django.contrib.admin.options import BaseModelAdmin
|
5
|
+
from django.contrib.auth.models import Permission
|
5
6
|
from django.core import checks
|
6
7
|
|
7
|
-
from .dataclasses import UnfoldAction
|
8
|
+
from unfold.dataclasses import UnfoldAction
|
8
9
|
|
9
10
|
|
10
11
|
class UnfoldModelAdminChecks(ModelAdminChecks):
|
@@ -29,14 +30,35 @@ class UnfoldModelAdminChecks(ModelAdminChecks):
|
|
29
30
|
for action in actions:
|
30
31
|
if not hasattr(action.method, "allowed_permissions"):
|
31
32
|
continue
|
33
|
+
|
32
34
|
for permission in action.method.allowed_permissions:
|
35
|
+
# Check the existence of Django permission
|
36
|
+
if "." in permission:
|
37
|
+
app_label, codename = permission.split(".")
|
38
|
+
|
39
|
+
if not Permission.objects.filter(
|
40
|
+
content_type__app_label=app_label,
|
41
|
+
codename=codename,
|
42
|
+
).exists():
|
43
|
+
errors.append(
|
44
|
+
checks.Error(
|
45
|
+
f"@action decorator on {action.method.original_function_name}() in class {obj.__class__.__name__} specifies permission {permission} which does not exists.",
|
46
|
+
obj=obj.__class__,
|
47
|
+
id="admin.E129",
|
48
|
+
)
|
49
|
+
)
|
50
|
+
|
51
|
+
continue
|
52
|
+
|
53
|
+
# Check the permission method existence
|
33
54
|
method_name = f"has_{permission}_permission"
|
34
55
|
if not hasattr(obj, method_name):
|
35
56
|
errors.append(
|
36
57
|
checks.Error(
|
37
|
-
f"{obj.__class__.__name__} must define a {method_name}() method for the {action.method.
|
58
|
+
f"{obj.__class__.__name__} must define a {method_name}() method for the {action.method.original_function_name}() action.",
|
38
59
|
obj=obj.__class__,
|
39
60
|
id="admin.E129",
|
40
61
|
)
|
41
62
|
)
|
63
|
+
|
42
64
|
return errors
|
@@ -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 grow flex-row items-center mr-auto rounded-default shadow-xs px-3 py-2 w-full dark:bg-base-900 dark:border-base-700 dark:text-font-default-dark">
|
12
|
+
<span class="admin-numeric-filter-slider-tooltip-from border border-base-200 cursor-not-allowed flex grow flex-row items-center mr-auto rounded-default shadow-xs px-3 py-2 w-full dark:bg-base-900 dark:border-base-700 dark:text-font-default-dark">
|
13
13
|
{{ choice.value_from }}
|
14
14
|
</span>
|
15
15
|
|
16
|
-
<span class="admin-numeric-filter-slider-tooltip-to border cursor-not-allowed flex grow flex-row items-center rounded-default shadow-xs px-3 py-2 w-full dark:bg-base-900 dark:border-base-700 dark:text-font-default-dark">
|
16
|
+
<span class="admin-numeric-filter-slider-tooltip-to border border-base-200 cursor-not-allowed flex grow flex-row items-center rounded-default shadow-xs px-3 py-2 w-full dark:bg-base-900 dark:border-base-700 dark:text-font-default-dark">
|
17
17
|
{{ choice.value_to }}
|
18
18
|
</span>
|
19
19
|
</div>
|
@@ -12,10 +12,15 @@ from django.http import HttpRequest
|
|
12
12
|
from django.utils.text import get_text_list
|
13
13
|
from django.utils.translation import gettext_lazy as _
|
14
14
|
|
15
|
-
from unfold.admin import
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
from unfold.admin import (
|
16
|
+
StackedInline,
|
17
|
+
TabularInline,
|
18
|
+
)
|
19
|
+
from unfold.contrib.inlines.checks import NonrelatedModelAdminChecks
|
20
|
+
from unfold.contrib.inlines.forms import (
|
21
|
+
NonrelatedInlineModelFormSet,
|
22
|
+
nonrelated_inline_formset_factory,
|
23
|
+
)
|
19
24
|
|
20
25
|
|
21
26
|
class NonrelatedInlineMixin:
|
@@ -135,8 +140,8 @@ class NonrelatedInlineMixin:
|
|
135
140
|
|
136
141
|
|
137
142
|
class NonrelatedStackedInline(NonrelatedInlineMixin, StackedInline):
|
138
|
-
|
143
|
+
formset = NonrelatedInlineModelFormSet
|
139
144
|
|
140
145
|
|
141
146
|
class NonrelatedTabularInline(NonrelatedInlineMixin, TabularInline):
|
142
|
-
|
147
|
+
formset = NonrelatedInlineModelFormSet
|
@@ -3,8 +3,10 @@ from typing import Any, Callable, Optional
|
|
3
3
|
from django.db.models import Model, QuerySet
|
4
4
|
from django.forms import BaseModelFormSet, ModelForm, modelformset_factory
|
5
5
|
|
6
|
+
from unfold.forms import PaginationFormSetMixin
|
6
7
|
|
7
|
-
|
8
|
+
|
9
|
+
class NonrelatedInlineModelFormSet(PaginationFormSetMixin, BaseModelFormSet):
|
8
10
|
def __init__(
|
9
11
|
self,
|
10
12
|
instance: Optional[Model] = None,
|
@@ -29,13 +29,19 @@ def action(
|
|
29
29
|
**kwargs,
|
30
30
|
) -> Optional[HttpResponse]:
|
31
31
|
if permissions:
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
permission_rules = []
|
33
|
+
|
34
|
+
for permission in permissions:
|
35
|
+
if "." in permission:
|
36
|
+
permission_rules.append(permission)
|
37
|
+
else:
|
38
|
+
# Permissions methods have following syntax: has_<some>_permission(self, request, obj=None):
|
39
|
+
# But obj is not examined by default in django admin and it would also require additional
|
40
|
+
# fetch from database, therefore it is not supported yet
|
41
|
+
permission_rules.append(
|
42
|
+
getattr(model_admin, f"has_{permission}_permission")
|
43
|
+
)
|
44
|
+
|
39
45
|
has_detail_action = func.__name__ in model_admin._extract_action_names(
|
40
46
|
model_admin.actions_detail
|
41
47
|
)
|
@@ -46,12 +52,19 @@ def action(
|
|
46
52
|
)
|
47
53
|
)
|
48
54
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
permission_checks = []
|
56
|
+
|
57
|
+
for permission_rule in permission_rules:
|
58
|
+
if isinstance(permission_rule, str) and "." in permission_rule:
|
59
|
+
permission_checks.append(request.user.has_perm(permission_rule))
|
60
|
+
elif has_detail_action or has_submit_line_action:
|
61
|
+
permission_checks.append(
|
62
|
+
permission_rule(request, kwargs.get("object_id"))
|
63
|
+
)
|
64
|
+
else:
|
65
|
+
permission_checks.append(permission_rule(request))
|
66
|
+
|
67
|
+
if not all(permission_checks):
|
55
68
|
raise PermissionDenied
|
56
69
|
return func(model_admin, request, *args, **kwargs)
|
57
70
|
|
@@ -73,6 +86,7 @@ def action(
|
|
73
86
|
inner.variant = ActionVariant.DEFAULT
|
74
87
|
|
75
88
|
inner.attrs = attrs or {}
|
89
|
+
inner.original_function_name = func.__name__
|
76
90
|
return inner
|
77
91
|
|
78
92
|
if function is None:
|
@@ -17,33 +17,24 @@ from django.utils.module_loading import import_string
|
|
17
17
|
from django.utils.safestring import SafeText, mark_safe
|
18
18
|
from django.utils.text import capfirst
|
19
19
|
|
20
|
-
from unfold.mixins import BaseModelAdminMixin
|
21
20
|
from unfold.settings import get_config
|
22
21
|
from unfold.utils import display_for_field, prettify_json
|
23
|
-
from unfold.widgets import
|
22
|
+
from unfold.widgets import (
|
23
|
+
CHECKBOX_LABEL_CLASSES,
|
24
|
+
INPUT_CLASSES,
|
25
|
+
LABEL_CLASSES,
|
26
|
+
)
|
24
27
|
|
25
28
|
|
26
29
|
class UnfoldAdminReadonlyField(helpers.AdminReadonlyField):
|
27
30
|
def label_tag(self) -> SafeText:
|
28
|
-
from .admin import ModelAdmin
|
29
|
-
|
30
|
-
if not isinstance(self.model_admin, ModelAdmin) and not isinstance(
|
31
|
-
self.model_admin, BaseModelAdminMixin
|
32
|
-
):
|
33
|
-
return super().label_tag()
|
34
|
-
|
35
31
|
attrs = {
|
36
32
|
"class": " ".join(LABEL_CLASSES + ["mb-2"]),
|
37
33
|
}
|
38
34
|
|
39
35
|
label = self.field["label"]
|
40
36
|
|
41
|
-
return format_html(
|
42
|
-
"<label{}>{}{}</label>",
|
43
|
-
flatatt(attrs),
|
44
|
-
capfirst(label),
|
45
|
-
self.form.label_suffix,
|
46
|
-
)
|
37
|
+
return format_html("<label{}>{}</label>", flatatt(attrs), capfirst(label))
|
47
38
|
|
48
39
|
def is_json(self) -> bool:
|
49
40
|
field, obj, model_admin = (
|
@@ -140,7 +131,7 @@ class UnfoldAdminReadonlyField(helpers.AdminReadonlyField):
|
|
140
131
|
):
|
141
132
|
result_repr = self.get_admin_url(f.remote_field, value)
|
142
133
|
elif isinstance(f, models.JSONField):
|
143
|
-
formatted_output = prettify_json(value)
|
134
|
+
formatted_output = prettify_json(value, f.encoder)
|
144
135
|
|
145
136
|
if formatted_output:
|
146
137
|
return formatted_output
|
@@ -174,12 +165,19 @@ class UnfoldAdminReadonlyField(helpers.AdminReadonlyField):
|
|
174
165
|
|
175
166
|
|
176
167
|
class UnfoldAdminField(helpers.AdminField):
|
168
|
+
def __init__(self, *args, **kwargs):
|
169
|
+
super().__init__(*args, **kwargs)
|
170
|
+
|
171
|
+
try:
|
172
|
+
from location_field.widgets import LocationWidget
|
173
|
+
|
174
|
+
if isinstance(self.field.field.widget, LocationWidget):
|
175
|
+
self.field.field.widget.attrs["class"] = " ".join(INPUT_CLASSES)
|
176
|
+
except ImportError:
|
177
|
+
pass
|
178
|
+
|
177
179
|
def label_tag(self) -> SafeText:
|
178
180
|
classes = []
|
179
|
-
if not self.field.field.widget.__class__.__name__.startswith(
|
180
|
-
"Unfold"
|
181
|
-
) and not self.field.field.widget.template_name.startswith("unfold"):
|
182
|
-
return super().label_tag()
|
183
181
|
|
184
182
|
# TODO load config from current AdminSite (override Fieldline.__iter__ method)
|
185
183
|
for lang, flag in get_config()["EXTENSIONS"]["modeltranslation"][
|
@@ -1,3 +1,4 @@
|
|
1
|
+
from collections.abc import Generator
|
1
2
|
from typing import Optional
|
2
3
|
|
3
4
|
from django import forms
|
@@ -11,14 +12,23 @@ from django.contrib.auth.forms import (
|
|
11
12
|
AdminPasswordChangeForm as BaseAdminPasswordChangeForm,
|
12
13
|
)
|
13
14
|
from django.contrib.auth.models import User
|
15
|
+
from django.contrib.contenttypes.forms import BaseGenericInlineFormSet
|
16
|
+
from django.core.paginator import Page, Paginator
|
17
|
+
from django.db.models import QuerySet
|
18
|
+
from django.forms import BaseInlineFormSet
|
19
|
+
from django.http import HttpRequest
|
20
|
+
|
21
|
+
from unfold.fields import UnfoldAdminField, UnfoldAdminReadonlyField
|
14
22
|
|
15
23
|
try:
|
16
24
|
from django.contrib.auth.forms import AdminUserCreationForm as BaseUserCreationForm
|
17
25
|
except ImportError:
|
18
26
|
from django.contrib.auth.forms import UserCreationForm as BaseUserCreationForm
|
27
|
+
from django.contrib.admin.helpers import AdminForm as BaseAdminForm
|
28
|
+
from django.contrib.admin.helpers import Fieldline as BaseFieldline
|
29
|
+
from django.contrib.admin.helpers import Fieldset as BaseFieldset
|
19
30
|
from django.contrib.auth.forms import ReadOnlyPasswordHashWidget
|
20
31
|
from django.contrib.auth.forms import UserChangeForm as BaseUserChangeForm
|
21
|
-
from django.http import HttpRequest
|
22
32
|
from django.utils.safestring import mark_safe
|
23
33
|
from django.utils.translation import gettext_lazy as _
|
24
34
|
|
@@ -43,15 +53,17 @@ class ActionForm(forms.Form):
|
|
43
53
|
"class": " ".join(
|
44
54
|
[
|
45
55
|
"appearance-none",
|
46
|
-
"bg-white/20",
|
56
|
+
"!bg-white/20",
|
47
57
|
"font-medium",
|
48
58
|
"grow",
|
49
59
|
"px-3",
|
50
60
|
"py-2",
|
51
61
|
"pr-8",
|
52
62
|
"rounded-default",
|
53
|
-
"text-white",
|
63
|
+
"!text-white",
|
54
64
|
"truncate",
|
65
|
+
"!outline-primary-400",
|
66
|
+
"dark:!outline-primary-700",
|
55
67
|
"*:text-base-700",
|
56
68
|
"lg:w-72",
|
57
69
|
]
|
@@ -144,3 +156,87 @@ class AdminOwnPasswordChangeForm(BaseAdminOwnPasswordChangeForm):
|
|
144
156
|
self.fields["old_password"].widget.attrs["class"] = " ".join(INPUT_CLASSES)
|
145
157
|
self.fields["new_password1"].widget.attrs["class"] = " ".join(INPUT_CLASSES)
|
146
158
|
self.fields["new_password2"].widget.attrs["class"] = " ".join(INPUT_CLASSES)
|
159
|
+
|
160
|
+
|
161
|
+
class AdminForm(BaseAdminForm):
|
162
|
+
def __iter__(self) -> Generator["Fieldset", None, None]:
|
163
|
+
for name, options in self.fieldsets:
|
164
|
+
yield Fieldset(
|
165
|
+
self.form,
|
166
|
+
name,
|
167
|
+
readonly_fields=self.readonly_fields,
|
168
|
+
model_admin=self.model_admin,
|
169
|
+
**options,
|
170
|
+
)
|
171
|
+
|
172
|
+
|
173
|
+
class Fieldset(BaseFieldset):
|
174
|
+
def __iter__(self) -> Generator["Fieldline", None, None]:
|
175
|
+
for field in self.fields:
|
176
|
+
yield Fieldline(
|
177
|
+
self.form, field, self.readonly_fields, model_admin=self.model_admin
|
178
|
+
)
|
179
|
+
|
180
|
+
|
181
|
+
class Fieldline(BaseFieldline):
|
182
|
+
def __iter__(
|
183
|
+
self,
|
184
|
+
) -> Generator["UnfoldAdminReadonlyField | UnfoldAdminField", None, None]:
|
185
|
+
for i, field in enumerate(self.fields):
|
186
|
+
if field in self.readonly_fields:
|
187
|
+
yield UnfoldAdminReadonlyField(
|
188
|
+
self.form, field, is_first=(i == 0), model_admin=self.model_admin
|
189
|
+
)
|
190
|
+
else:
|
191
|
+
yield UnfoldAdminField(self.form, field, is_first=(i == 0))
|
192
|
+
|
193
|
+
|
194
|
+
class PaginationFormSetMixin:
|
195
|
+
queryset: Optional[QuerySet] = None
|
196
|
+
request: Optional[HttpRequest] = None
|
197
|
+
per_page: Optional[int] = None
|
198
|
+
|
199
|
+
def __init__(
|
200
|
+
self,
|
201
|
+
request: Optional[HttpRequest] = None,
|
202
|
+
per_page: Optional[int] = None,
|
203
|
+
*args,
|
204
|
+
**kwargs,
|
205
|
+
):
|
206
|
+
self.request = request
|
207
|
+
self.per_page = per_page
|
208
|
+
|
209
|
+
super().__init__(*args, **kwargs)
|
210
|
+
|
211
|
+
if self.per_page:
|
212
|
+
self.paginator = Paginator(self.queryset, self.per_page)
|
213
|
+
self.page = self.get_page(self.paginator, self.get_page_num())
|
214
|
+
self._queryset = self.page.object_list
|
215
|
+
|
216
|
+
def get_pagination_key(self) -> str:
|
217
|
+
return f"{self.prefix}-page"
|
218
|
+
|
219
|
+
def get_page_num(self) -> int:
|
220
|
+
page = self.request.GET.get(self.get_pagination_key())
|
221
|
+
if page and page.isnumeric() and page > "0":
|
222
|
+
return int(page)
|
223
|
+
|
224
|
+
page = self.request.POST.get(self.get_pagination_key())
|
225
|
+
if page and page.isnumeric() and page > "0":
|
226
|
+
return int(page)
|
227
|
+
|
228
|
+
return 1
|
229
|
+
|
230
|
+
def get_page(self, paginator: Paginator, page: int) -> Page:
|
231
|
+
if page <= paginator.num_pages:
|
232
|
+
return paginator.page(page)
|
233
|
+
|
234
|
+
return paginator.page(1)
|
235
|
+
|
236
|
+
|
237
|
+
class PaginationInlineFormSet(PaginationFormSetMixin, BaseInlineFormSet):
|
238
|
+
pass
|
239
|
+
|
240
|
+
|
241
|
+
class PaginationGenericInlineFormSet(PaginationFormSetMixin, BaseGenericInlineFormSet):
|
242
|
+
pass
|
@@ -25,6 +25,22 @@ class Button(ButtonClassesMixin, BaseInput):
|
|
25
25
|
input_type = "button"
|
26
26
|
|
27
27
|
|
28
|
+
class FieldsetSubheader(LayoutObject):
|
29
|
+
template = "unfold_crispy/layout/fieldset_subheader.html"
|
30
|
+
|
31
|
+
def __init__(self, title=None, *args, **kwargs):
|
32
|
+
self.title = title
|
33
|
+
super().__init__(*args, **kwargs)
|
34
|
+
|
35
|
+
def render(self, form, context, template_pack=TEMPLATE_PACK, **kwargs):
|
36
|
+
return render_to_string(
|
37
|
+
self.template,
|
38
|
+
{
|
39
|
+
"title": self.title,
|
40
|
+
},
|
41
|
+
)
|
42
|
+
|
43
|
+
|
28
44
|
class Hr(LayoutObject):
|
29
45
|
template = "unfold_crispy/layout/hr.html"
|
30
46
|
|
@@ -316,19 +316,27 @@ class ActionModelAdminMixin:
|
|
316
316
|
filtered_actions.append(action)
|
317
317
|
continue
|
318
318
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
319
|
+
permission_rules = []
|
320
|
+
|
321
|
+
for permission in action.method.allowed_permissions:
|
322
|
+
if "." in permission:
|
323
|
+
permission_rules.append(permission)
|
324
|
+
else:
|
325
|
+
permission_rules.append(
|
326
|
+
getattr(self, f"has_{permission}_permission")
|
327
|
+
)
|
328
|
+
|
329
|
+
permission_checks = []
|
330
|
+
|
331
|
+
for permission_rule in permission_rules:
|
332
|
+
if isinstance(permission_rule, str) and "." in permission_rule:
|
333
|
+
permission_checks.append(request.user.has_perm(permission_rule))
|
334
|
+
elif object_id:
|
335
|
+
permission_checks.append(permission_rule(request, object_id))
|
336
|
+
else:
|
337
|
+
permission_checks.append(permission_rule(request))
|
338
|
+
|
339
|
+
if all(permission_checks):
|
340
|
+
filtered_actions.append(action)
|
333
341
|
|
334
342
|
return filtered_actions
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import copy
|
2
|
-
from typing import Optional
|
2
|
+
from typing import Any, Optional
|
3
3
|
|
4
|
+
from django.contrib.admin import helpers
|
4
5
|
from django.contrib.admin.sites import AdminSite
|
5
6
|
from django.contrib.admin.widgets import RelatedFieldWidgetWrapper
|
6
7
|
from django.db import models
|
@@ -27,6 +28,19 @@ class BaseModelAdminMixin:
|
|
27
28
|
|
28
29
|
super().__init__(model, admin_site)
|
29
30
|
|
31
|
+
def changeform_view(
|
32
|
+
self,
|
33
|
+
request: HttpRequest,
|
34
|
+
object_id: Optional[str] = None,
|
35
|
+
form_url: str = "",
|
36
|
+
extra_context: Optional[dict[str, bool]] = None,
|
37
|
+
) -> Any:
|
38
|
+
from unfold.forms import AdminForm, Fieldline
|
39
|
+
|
40
|
+
helpers.AdminForm = AdminForm
|
41
|
+
helpers.Fieldline = Fieldline
|
42
|
+
return super().changeform_view(request, object_id, form_url, extra_context)
|
43
|
+
|
30
44
|
def formfield_for_choice_field(
|
31
45
|
self, db_field: Field, request: HttpRequest, **kwargs
|
32
46
|
) -> TypedChoiceField:
|