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.
Files changed (304) hide show
  1. {django_unfold-0.58.0 → django_unfold-0.60.0}/PKG-INFO +3 -2
  2. {django_unfold-0.58.0 → django_unfold-0.60.0}/README.md +2 -1
  3. {django_unfold-0.58.0 → django_unfold-0.60.0}/pyproject.toml +2 -1
  4. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/admin.py +45 -13
  5. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/checks.py +24 -2
  6. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +2 -2
  7. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/admin.py +11 -6
  8. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/forms.py +3 -1
  9. django_unfold-0.60.0/src/unfold/contrib/location_field/apps.py +6 -0
  10. django_unfold-0.60.0/src/unfold/contrib/location_field/templates/location_field/map_widget.html +5 -0
  11. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/decorators.py +27 -13
  12. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/fields.py +18 -20
  13. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/forms.py +99 -3
  14. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/layout.py +16 -0
  15. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/mixins/action_model_admin.py +22 -14
  16. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/mixins/base_model_admin.py +15 -1
  17. django_unfold-0.60.0/src/unfold/paginator.py +21 -0
  18. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/settings.py +8 -1
  19. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/sites.py +27 -29
  20. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/admin/js/admin/RelatedObjectLookups.js +9 -3
  21. django_unfold-0.60.0/src/unfold/static/unfold/css/styles.css +2 -0
  22. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/styles.css +12 -16
  23. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/app_list.html +4 -1
  24. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/base.html +1 -1
  25. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_form.html +2 -1
  26. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/edit_inline/stacked.html +12 -8
  27. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/edit_inline/tabular.html +2 -0
  28. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/includes/fieldset.html +9 -3
  29. django_unfold-0.60.0/src/unfold/templates/admin/login.html +62 -0
  30. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/pagination.html +1 -1
  31. django_unfold-0.60.0/src/unfold/templates/unfold/components/button.html +13 -0
  32. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/account_links.html +14 -6
  33. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/app_list.html +5 -2
  34. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/app_list_default.html +2 -1
  35. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/change_list_actions.html +2 -2
  36. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/change_list_filter_actions.html +1 -1
  37. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_heading.html +1 -1
  38. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/empty_results.html +2 -2
  39. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/field.html +5 -3
  40. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/header.html +1 -1
  41. django_unfold-0.60.0/src/unfold/templates/unfold/helpers/language_form.html +10 -0
  42. django_unfold-0.60.0/src/unfold/templates/unfold/helpers/language_switch.html +25 -0
  43. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/navigation.html +1 -1
  44. django_unfold-0.60.0/src/unfold/templates/unfold/helpers/pagination_infinite.html +11 -0
  45. django_unfold-0.60.0/src/unfold/templates/unfold/helpers/pagination_inline.html +28 -0
  46. django_unfold-0.60.0/src/unfold/templates/unfold/helpers/theme_switch.html +34 -0
  47. django_unfold-0.60.0/src/unfold/templates/unfold/helpers/unauthenticated_header.html +15 -0
  48. django_unfold-0.60.0/src/unfold/templates/unfold/helpers/unauthenticated_title.html +11 -0
  49. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/userlinks.html +2 -6
  50. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/welcomemsg.html +9 -7
  51. django_unfold-0.60.0/src/unfold/templates/unfold/layouts/unauthenticated.html +37 -0
  52. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/select.html +1 -1
  53. django_unfold-0.60.0/src/unfold/templates/unfold/widgets/text.html +28 -0
  54. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/fieldset.html +3 -1
  55. django_unfold-0.60.0/src/unfold/templates/unfold_crispy/layout/fieldset_subheader.html +3 -0
  56. django_unfold-0.60.0/src/unfold/templatetags/__init__.py +0 -0
  57. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templatetags/unfold.py +37 -2
  58. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/utils.py +2 -2
  59. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/widgets.py +49 -3
  60. django_unfold-0.58.0/src/unfold/paginator.py +0 -10
  61. django_unfold-0.58.0/src/unfold/static/unfold/css/styles.css +0 -2
  62. django_unfold-0.58.0/src/unfold/templates/admin/login.html +0 -105
  63. django_unfold-0.58.0/src/unfold/templates/unfold/components/button.html +0 -4
  64. django_unfold-0.58.0/src/unfold/templates/unfold/helpers/language_switch.html +0 -27
  65. django_unfold-0.58.0/src/unfold/templates/unfold/helpers/pagination_infinite.html +0 -11
  66. django_unfold-0.58.0/src/unfold/templates/unfold/helpers/theme_switch.html +0 -32
  67. {django_unfold-0.58.0 → django_unfold-0.60.0}/LICENSE.md +0 -0
  68. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/__init__.py +0 -0
  69. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/apps.py +0 -0
  70. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/components.py +0 -0
  71. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/__init__.py +0 -0
  72. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/__init__.py +0 -0
  73. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/__init__.py +0 -0
  74. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/autocomplete_filters.py +0 -0
  75. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/choice_filters.py +0 -0
  76. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/datetime_filters.py +0 -0
  77. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/dropdown_filters.py +0 -0
  78. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/mixins.py +0 -0
  79. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/numeric_filters.py +0 -0
  80. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/admin/text_filters.py +0 -0
  81. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/apps.py +0 -0
  82. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/forms.py +0 -0
  83. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/css/nouislider/LICENSE +0 -0
  84. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/css/nouislider/nouislider.min.css +0 -0
  85. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/DateTimeShortcuts.js +0 -0
  86. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js +0 -0
  87. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/nouislider/LICENSE +0 -0
  88. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/nouislider/nouislider.min.js +0 -0
  89. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/wnumb/LICENSE +0 -0
  90. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/static/unfold/filters/js/wnumb/wNumb.min.js +0 -0
  91. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_date_range.html +0 -0
  92. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_datetime_range.html +0 -0
  93. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_field.html +0 -0
  94. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_range.html +0 -0
  95. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/filters/templates/unfold/filters/filters_numeric_single.html +0 -0
  96. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/__init__.py +0 -0
  97. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/apps.py +0 -0
  98. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/css/trix/LICENSE +0 -0
  99. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/css/trix/trix.css +0 -0
  100. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix/LICENSE +0 -0
  101. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix/trix.js +0 -0
  102. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/static/unfold/forms/js/trix.config.js +0 -0
  103. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/templates/unfold/forms/array.html +0 -0
  104. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html +0 -0
  105. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/templates/unfold/forms/wysiwyg.html +0 -0
  106. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/forms/widgets.py +0 -0
  107. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/__init__.py +0 -0
  108. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/apps.py +0 -0
  109. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/change_form.html +0 -0
  110. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/field.html +0 -0
  111. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/admin/guardian/model/obj_perms_manage.html +0 -0
  112. {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
  113. {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
  114. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/unfold/guardian/group_form.html +0 -0
  115. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/guardian/templates/unfold/guardian/user_form.html +0 -0
  116. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/__init__.py +0 -0
  117. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/apps.py +0 -0
  118. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/forms.py +0 -0
  119. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/base.html +0 -0
  120. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/change_form.html +0 -0
  121. {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
  122. {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
  123. {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
  124. {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
  125. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/export.html +0 -0
  126. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import.html +0 -0
  127. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_confirm.html +0 -0
  128. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_errors.html +0 -0
  129. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_form.html +0 -0
  130. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_preview.html +0 -0
  131. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/import_export/templates/admin/import_export/import_validation.html +0 -0
  132. {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
  133. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/__init__.py +0 -0
  134. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/apps.py +0 -0
  135. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/inlines/checks.py +0 -0
  136. {django_unfold-0.58.0/src/unfold/contrib/simple_history → django_unfold-0.60.0/src/unfold/contrib/location_field}/__init__.py +0 -0
  137. {django_unfold-0.58.0/src/unfold/templatetags → django_unfold-0.60.0/src/unfold/contrib/simple_history}/__init__.py +0 -0
  138. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/apps.py +0 -0
  139. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history.html +0 -0
  140. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history_form.html +0 -0
  141. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/templates/simple_history/object_history_list.html +0 -0
  142. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/contrib/simple_history/templates/simple_history/submit_line.html +0 -0
  143. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/dataclasses.py +0 -0
  144. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/enums.py +0 -0
  145. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/exceptions.py +0 -0
  146. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/mixins/__init__.py +0 -0
  147. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/overrides.py +0 -0
  148. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/sections.py +0 -0
  149. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/admin/js/inlines.js +0 -0
  150. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/css/simplebar/LICENSE +0 -0
  151. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/css/simplebar/simplebar.css +0 -0
  152. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/Inter-Bold.woff2 +0 -0
  153. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/Inter-Medium.woff2 +0 -0
  154. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/Inter-Regular.woff2 +0 -0
  155. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/Inter-SemiBold.woff2 +0 -0
  156. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/LICENSE +0 -0
  157. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/inter/styles.css +0 -0
  158. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/material-symbols/LICENSE +0 -0
  159. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/material-symbols/Material-Symbols-Outlined.woff2 +0 -0
  160. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/fonts/material-symbols/styles.css +0 -0
  161. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/LICENSE +0 -0
  162. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.anchor.js +0 -0
  163. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.js +0 -0
  164. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.persist.js +0 -0
  165. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.resize.js +0 -0
  166. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/alpine/alpine.sort.js +0 -0
  167. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/app.js +0 -0
  168. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/chart/LICENSE +0 -0
  169. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/chart/chart.js +0 -0
  170. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/htmx/LICENSE +0 -0
  171. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/htmx/htmx.js +0 -0
  172. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/select2.init.js +0 -0
  173. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/simplebar/LICENSE +0 -0
  174. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/static/unfold/js/simplebar/simplebar.js +0 -0
  175. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/actions.html +0 -0
  176. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/app_index.html +0 -0
  177. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/auth/user/add_form.html +0 -0
  178. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/auth/user/change_password.html +0 -0
  179. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/base_site.html +0 -0
  180. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_form_object_tools.html +0 -0
  181. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_list.html +0 -0
  182. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_list_object_tools.html +0 -0
  183. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/change_list_results.html +0 -0
  184. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/date_hierarchy.html +0 -0
  185. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/delete_confirmation.html +0 -0
  186. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/delete_selected_confirmation.html +0 -0
  187. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/filter.html +0 -0
  188. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/includes/object_delete_summary.html +0 -0
  189. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/index.html +0 -0
  190. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/nav_sidebar.html +0 -0
  191. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/object_history.html +0 -0
  192. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/search_form.html +0 -0
  193. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/admin/submit_line.html +0 -0
  194. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/auth/widgets/read_only_password_hash.html +0 -0
  195. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/registration/logged_out.html +0 -0
  196. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/registration/password_change_done.html +0 -0
  197. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/registration/password_change_form.html +0 -0
  198. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/card.html +0 -0
  199. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/chart/bar.html +0 -0
  200. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/chart/cohort.html +0 -0
  201. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/chart/line.html +0 -0
  202. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/container.html +0 -0
  203. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/flex.html +0 -0
  204. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/icon.html +0 -0
  205. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/navigation.html +0 -0
  206. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/progress.html +0 -0
  207. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/separator.html +0 -0
  208. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/table.html +0 -0
  209. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/text.html +0 -0
  210. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/title.html +0 -0
  211. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/components/tracker.html +0 -0
  212. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/actions_row.html +0 -0
  213. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/add_link.html +0 -0
  214. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/attrs.html +0 -0
  215. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/boolean.html +0 -0
  216. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/breadcrumb_item.html +0 -0
  217. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/change_list_filter.html +0 -0
  218. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/delete_submit_line.html +0 -0
  219. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/display_dropdown.html +0 -0
  220. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/display_header.html +0 -0
  221. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/display_label.html +0 -0
  222. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_delete.html +0 -0
  223. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_error.html +0 -0
  224. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_field.html +0 -0
  225. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_row.html +0 -0
  226. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/edit_inline/tabular_title.html +0 -0
  227. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/field_readonly.html +0 -0
  228. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/field_readonly_value.html +0 -0
  229. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/fieldset_row.html +0 -0
  230. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/fieldset_row_checkbox.html +0 -0
  231. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/fieldset_row_field.html +0 -0
  232. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/fieldsets_tabs.html +0 -0
  233. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/form_errors.html +0 -0
  234. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/form_label.html +0 -0
  235. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/header_back_button.html +0 -0
  236. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/help_text.html +0 -0
  237. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/history.html +0 -0
  238. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/label.html +0 -0
  239. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/debug.html +0 -0
  240. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/error.html +0 -0
  241. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/errornote.html +0 -0
  242. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/info.html +0 -0
  243. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/success.html +0 -0
  244. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages/warning.html +0 -0
  245. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/messages.html +0 -0
  246. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/navigation_header.html +0 -0
  247. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/pagination.html +0 -0
  248. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/pagination_current_item.html +0 -0
  249. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/pagination_default.html +0 -0
  250. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/pagination_ellipsis.html +0 -0
  251. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/search.html +0 -0
  252. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/search_results.html +0 -0
  253. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/site_branding.html +0 -0
  254. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/site_dropdown.html +0 -0
  255. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/site_icon.html +0 -0
  256. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/site_logo.html +0 -0
  257. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/submit.html +0 -0
  258. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/tab_action.html +0 -0
  259. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/tab_actions.html +0 -0
  260. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/tab_items.html +0 -0
  261. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/helpers/tab_list.html +0 -0
  262. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/layouts/base.html +0 -0
  263. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/layouts/base_simple.html +0 -0
  264. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/layouts/skeleton.html +0 -0
  265. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/templatetags/preserve_changelist_filters.html +0 -0
  266. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/clearable_file_input.html +0 -0
  267. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/clearable_file_input_small.html +0 -0
  268. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/date.html +0 -0
  269. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/foreign_key_raw_id.html +0 -0
  270. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/radio.html +0 -0
  271. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/radio_option.html +0 -0
  272. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/range.html +0 -0
  273. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/related_widget_wrapper.html +0 -0
  274. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/split_datetime.html +0 -0
  275. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/split_datetime_vertical.html +0 -0
  276. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/split_money.html +0 -0
  277. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/textarea.html +0 -0
  278. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/time.html +0 -0
  279. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold/widgets/url.html +0 -0
  280. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/display_form.html +0 -0
  281. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/errors.html +0 -0
  282. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/errors_formset.html +0 -0
  283. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/field.html +0 -0
  284. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/inputs.html +0 -0
  285. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/attrs.html +0 -0
  286. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/baseinput.html +0 -0
  287. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/button.html +0 -0
  288. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/buttonholder.html +0 -0
  289. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/checkbox.html +0 -0
  290. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/column.html +0 -0
  291. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/div.html +0 -0
  292. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/field_errors.html +0 -0
  293. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/help_text.html +0 -0
  294. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/help_text_and_errors.html +0 -0
  295. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/hr.html +0 -0
  296. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/radio_checkbox_select.html +0 -0
  297. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/row.html +0 -0
  298. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/layout/table_inline_formset.html +0 -0
  299. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/uni_form.html +0 -0
  300. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/whole_uni_form.html +0 -0
  301. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templates/unfold_crispy/whole_uni_formset.html +0 -0
  302. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/templatetags/unfold_list.py +0 -0
  303. {django_unfold-0.58.0 → django_unfold-0.60.0}/src/unfold/typing.py +0 -0
  304. {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.58.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.58.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.fields import UnfoldAdminField, UnfoldAdminReadonlyField
20
- from unfold.forms import ActionForm
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
- class TabularInline(BaseModelAdminMixin, BaseTabularInline):
187
- formfield_overrides = FORMFIELD_OVERRIDES_INLINE
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
- class StackedInline(BaseModelAdminMixin, BaseStackedInline):
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.__name__} action.",
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 StackedInline, TabularInline
16
-
17
- from .checks import NonrelatedModelAdminChecks
18
- from .forms import NonrelatedInlineModelFormSet, nonrelated_inline_formset_factory
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
- pass
143
+ formset = NonrelatedInlineModelFormSet
139
144
 
140
145
 
141
146
  class NonrelatedTabularInline(NonrelatedInlineMixin, TabularInline):
142
- pass
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
- class NonrelatedInlineModelFormSet(BaseModelFormSet):
8
+
9
+ class NonrelatedInlineModelFormSet(PaginationFormSetMixin, BaseModelFormSet):
8
10
  def __init__(
9
11
  self,
10
12
  instance: Optional[Model] = None,
@@ -0,0 +1,6 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class DefaultAppConfig(AppConfig):
5
+ name = "unfold.contrib.location_field"
6
+ label = "unfold_location_field"
@@ -0,0 +1,5 @@
1
+ <div class="map-widget flex flex-col gap-2">
2
+ {{ field_input }}
3
+
4
+ <div id="map_{{ field_name }}" class="border gap-2 h-72 max-w-2xl rounded-default shadow-xs"></div>
5
+ </div>
@@ -29,13 +29,19 @@ def action(
29
29
  **kwargs,
30
30
  ) -> Optional[HttpResponse]:
31
31
  if permissions:
32
- permission_checks = (
33
- getattr(model_admin, f"has_{permission}_permission")
34
- for permission in permissions
35
- )
36
- # Permissions methods have following syntax: has_<some>_permission(self, request, obj=None):
37
- # But obj is not examined by default in django admin and it would also require additional
38
- # fetch from database, therefore it is not supported yet
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
- if not all(
50
- has_permission(request, kwargs.get("object_id"))
51
- if has_detail_action or has_submit_line_action
52
- else has_permission(request)
53
- for has_permission in permission_checks
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 CHECKBOX_LABEL_CLASSES, LABEL_CLASSES
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
- permission_checks = (
320
- getattr(self, f"has_{permission}_permission")
321
- for permission in action.method.allowed_permissions
322
- )
323
-
324
- if object_id:
325
- if all(
326
- has_permission(request, object_id)
327
- for has_permission in permission_checks
328
- ):
329
- filtered_actions.append(action)
330
- else:
331
- if all(has_permission(request) for has_permission in permission_checks):
332
- filtered_actions.append(action)
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: