django-unfold 0.66.0__py3-none-any.whl → 0.68.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. {django_unfold-0.66.0.dist-info → django_unfold-0.68.0.dist-info}/METADATA +8 -5
  2. {django_unfold-0.66.0.dist-info → django_unfold-0.68.0.dist-info}/RECORD +46 -42
  3. unfold/admin.py +73 -13
  4. unfold/components.py +2 -2
  5. unfold/contrib/filters/admin/choice_filters.py +13 -1
  6. unfold/contrib/filters/admin/mixins.py +3 -3
  7. unfold/contrib/filters/admin/numeric_filters.py +8 -6
  8. unfold/contrib/filters/forms.py +25 -4
  9. unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js +62 -28
  10. unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +2 -11
  11. unfold/contrib/forms/widgets.py +5 -5
  12. unfold/contrib/inlines/admin.py +3 -3
  13. unfold/contrib/inlines/forms.py +5 -4
  14. unfold/dataclasses.py +13 -13
  15. unfold/datasets.py +69 -0
  16. unfold/decorators.py +19 -19
  17. unfold/fields.py +40 -1
  18. unfold/forms.py +19 -7
  19. unfold/mixins/action_model_admin.py +11 -10
  20. unfold/mixins/base_model_admin.py +6 -6
  21. unfold/sites.py +14 -17
  22. unfold/static/unfold/css/styles.css +1 -1
  23. unfold/static/unfold/js/app.js +65 -5
  24. unfold/static/unfold/js/select2.init.js +2 -9
  25. unfold/styles.css +22 -21
  26. unfold/templates/admin/change_form.html +5 -1
  27. unfold/templates/admin/change_list_results.html +10 -62
  28. unfold/templates/admin/edit_inline/stacked.html +1 -1
  29. unfold/templates/admin/search_form.html +5 -3
  30. unfold/templates/unfold/components/card.html +12 -3
  31. unfold/templates/unfold/components/progress.html +9 -3
  32. unfold/templates/unfold/helpers/change_list_headers.html +65 -0
  33. unfold/templates/unfold/helpers/dataset.html +19 -0
  34. unfold/templates/unfold/helpers/edit_inline/tabular_field.html +1 -1
  35. unfold/templates/unfold/helpers/empty_results.html +6 -4
  36. unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
  37. unfold/templates/unfold/helpers/field_readonly_value_file.html +18 -0
  38. unfold/templates/unfold/helpers/tab_items.html +6 -0
  39. unfold/templatetags/unfold.py +18 -13
  40. unfold/templatetags/unfold_list.py +64 -8
  41. unfold/typing.py +5 -6
  42. unfold/utils.py +9 -9
  43. unfold/views.py +15 -1
  44. unfold/widgets.py +30 -29
  45. {django_unfold-0.66.0.dist-info → django_unfold-0.68.0.dist-info}/WHEEL +0 -0
  46. {django_unfold-0.66.0.dist-info → django_unfold-0.68.0.dist-info}/licenses/LICENSE.md +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: django-unfold
3
- Version: 0.66.0
3
+ Version: 0.68.0
4
4
  Summary: Modern Django admin theme for seamless interface development
5
5
  License: MIT
6
6
  License-File: LICENSE.md
7
7
  Keywords: django,admin,tailwind,theme
8
- Requires-Python: >=3.9
8
+ Requires-Python: >=3.10,<4.0
9
9
  Classifier: Environment :: Web Environment
10
10
  Classifier: Framework :: Django
11
11
  Classifier: Intended Audience :: Developers
@@ -13,7 +13,6 @@ Classifier: License :: OSI Approved :: MIT License
13
13
  Classifier: Operating System :: OS Independent
14
14
  Classifier: Programming Language :: Python
15
15
  Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.9
17
16
  Classifier: Programming Language :: Python :: 3.10
18
17
  Classifier: Programming Language :: Python :: 3.11
19
18
  Classifier: Programming Language :: Python :: 3.12
@@ -24,7 +23,7 @@ Project-URL: Homepage, https://unfoldadmin.com
24
23
  Project-URL: Repository, https://github.com/unfoldadmin/django-unfold
25
24
  Description-Content-Type: text/markdown
26
25
 
27
- ![screenshot](https://github.com/user-attachments/assets/87aaad04-f454-42aa-b9ac-e14d41f189ac)
26
+ [![screenshot](https://github.com/user-attachments/assets/8c2dc5c1-480b-49ad-bd2e-57369ca4e306)](https://unfoldadmin.com)
28
27
 
29
28
  ## Unfold - Django Admin Theme
30
29
 
@@ -59,13 +58,16 @@ If you need assistance with integrating or customizing Unfold, support packages
59
58
 
60
59
  Unfold Studio lets you visually customize your Django admin without writing code — update colors, logos, sidebar, and interface styles to match your brand in minutes. Give your admin a polished, professional look that feels truly yours. Available at [unfoldadmin.com/studio](https://unfoldadmin.com/studio).
61
60
 
61
+ [![dashboards](https://github.com/user-attachments/assets/7c3124ab-2f59-4254-9222-8a57970f51a6)](https://unfoldadmin.com/studio)
62
+
63
+
62
64
  ## Fresh Features & Enhancements
63
65
 
66
+ - **Command**: Offers a command palette for quick searching across all models or custom-injected data
64
67
  - **django-constance**: Official support with a completely new design and UX improvements
65
68
  - **Paginated inlines:** Break down large record sets into pages within inlines for better admin performance
66
69
  - **Conditional fields:** Show or hide fields dynamically based on the values of other fields in the form
67
70
  - **Infinite paginator:** Efficiently handle large datasets with seamless pagination that reduces server load
68
- - **Checkbox & radio filters:** Enhanced filter options with checkbox and radio interfaces for intuitive filtering
69
71
 
70
72
  ## Core Features & Capabilities
71
73
 
@@ -84,6 +86,7 @@ Unfold Studio lets you visually customize your Django admin without writing code
84
86
  - **Model tabs:** Allow defining custom tab navigation for models
85
87
  - **Fieldset tabs:** Merge multiple fieldsets into tabs in the change form
86
88
  - **Sortable inlines:** Allow sorting inlines by dragging and dropping
89
+ - **Command**: Offers a command palette for quick searching across all models or custom-injected data
87
90
  - **Environment label:** Distinguish between environments by displaying a label
88
91
  - **Nonrelated inlines:** Display nonrelated models as inlines in the change form
89
92
  - **Paginated inlines:** Break down large record sets into pages within inlines for better admin performance
@@ -1,8 +1,8 @@
1
1
  unfold/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- unfold/admin.py,sha256=UeAG6y53kX5P7esCzCcqNztQ9WCujtscrjCyULeapvQ,7422
2
+ unfold/admin.py,sha256=sLRfwfDy6rr9asgV4niufrg2ObMQ05VGBnmr33hStyo,9685
3
3
  unfold/apps.py,sha256=SlBXPYrUd2uXn67qFbRvbXSUk3XFWrF4-5WELgDCvho,381
4
4
  unfold/checks.py,sha256=e5HEhbXRcu3FwZDT_d-IbimeVpjJ6jgCUPXWvsUjEw0,2601
5
- unfold/components.py,sha256=vqkQzseYUvLXDohmTVAlbKopALjyX4WA9yglvdfhqu4,1283
5
+ unfold/components.py,sha256=E5sl0y3XDPSswHbRLVnJrdKNpZzZ-e5q4tLwMGACyZo,1270
6
6
  unfold/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  unfold/contrib/constance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  unfold/contrib/constance/apps.py,sha256=636jGQ_C15fp5WRccmuSeZCZ4GOQ2PhXSEe4769uqrQ,139
@@ -12,18 +12,18 @@ unfold/contrib/constance/templates/admin/constance/includes/results_list.html,sh
12
12
  unfold/contrib/filters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  unfold/contrib/filters/admin/__init__.py,sha256=7pooAoA2Y9MbBL_RTJBZeIAwV5ECrOvMbe0_egoHfew,1663
14
14
  unfold/contrib/filters/admin/autocomplete_filters.py,sha256=Jh3m3iQ8YubZRQDVzHPGfpk9RulOhHkZc0N7L6KV9wc,514
15
- unfold/contrib/filters/admin/choice_filters.py,sha256=wI_m5k8SLwHkWoFeCPvI0bN_RuF0RNyzRP3z8jor684,5651
15
+ unfold/contrib/filters/admin/choice_filters.py,sha256=_IoZaPlcpFLlr7j09lcJ6ALb4olShzKF8rJWKNKJMzo,6010
16
16
  unfold/contrib/filters/admin/datetime_filters.py,sha256=cVari_7jsfeYxJoRBhcAUOr6v9XdtDtMuMs-S1Irafo,7757
17
17
  unfold/contrib/filters/admin/dropdown_filters.py,sha256=exiIyU6c_as7XBJsaAPPx5b8eY3IDbuCFGPJu1b0ux4,3856
18
- unfold/contrib/filters/admin/mixins.py,sha256=Z8BrdqbnjM1Ldr7qfhb6aWeOXKc5NqUgp-1NDU7SqS4,5839
19
- unfold/contrib/filters/admin/numeric_filters.py,sha256=8GNmesgMmMIfEZb2IrGbaBoJuvB2FpIc7wPIPBpHat4,6420
18
+ unfold/contrib/filters/admin/mixins.py,sha256=A0G4pwmpaEg4VHk6fBXHHtiancpsJl9JsQSefmMLZso,5823
19
+ unfold/contrib/filters/admin/numeric_filters.py,sha256=dRjerPcdKb0yMrdCDR_zOSzju3s9-1RCBshg1654r2U,6475
20
20
  unfold/contrib/filters/admin/text_filters.py,sha256=19cOEGpSaXafcM8QuGiYaWmNi5UIQnCXEhKG-vCTfe8,2088
21
21
  unfold/contrib/filters/apps.py,sha256=wEySJy0gMLzFLb9XNKE-RexiO05X7NaQ5QmxZyziJ_k,136
22
- unfold/contrib/filters/forms.py,sha256=xROYON0ZaTLOE7gIhHXEgDAcYz0eY6LO2uxc3oXzfcA,8097
22
+ unfold/contrib/filters/forms.py,sha256=cebAmMPKtofdwvUhAVaoP5V3rNhwYe0Df5k06TJwZfo,8560
23
23
  unfold/contrib/filters/static/unfold/filters/css/nouislider/LICENSE,sha256=DR_G6Ykr-xlGx4DwQFeKTRcGAYL3ch33e44GisGdHOQ,1069
24
24
  unfold/contrib/filters/static/unfold/filters/css/nouislider/nouislider.min.css,sha256=rddL_jOGGVEY6wR-aw0VYovAfz5fPeAIsulrlSNb1hc,4221
25
25
  unfold/contrib/filters/static/unfold/filters/js/DateTimeShortcuts.js,sha256=jgFNBDf6aHvUlyv0LEDHggXO-xA8pWOCWFWcVupdA30,19332
26
- unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js,sha256=nTkiiJk4Abn9d6KigxPSEsereFhFq-v5n_boiiY1eII,1668
26
+ unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js,sha256=TnLzgMRzcePLHSMpvwCEA8CowifobGuCIS6IXRAU5XM,2363
27
27
  unfold/contrib/filters/static/unfold/filters/js/nouislider/LICENSE,sha256=DR_G6Ykr-xlGx4DwQFeKTRcGAYL3ch33e44GisGdHOQ,1069
28
28
  unfold/contrib/filters/static/unfold/filters/js/nouislider/nouislider.min.js,sha256=aIEt5UlLNnEv4-HPyxcLqu9dTS7gXiMm35Mm0rFmQ0Q,26683
29
29
  unfold/contrib/filters/static/unfold/filters/js/wnumb/LICENSE,sha256=ifeAa0-l35lCSesni0e-3xcD2BXwP7GXG6TdQiMW16I,1069
@@ -33,7 +33,7 @@ unfold/contrib/filters/templates/unfold/filters/filters_datetime_range.html,sha2
33
33
  unfold/contrib/filters/templates/unfold/filters/filters_field.html,sha256=UTlSZlpg-gAc_a-EJLLF0NI_ofuSHQ2kMMoAs99nL2E,164
34
34
  unfold/contrib/filters/templates/unfold/filters/filters_numeric_range.html,sha256=TnklQxXhe17UaImoiHahhtN6d1xVdXt2dhIMQESJY68,661
35
35
  unfold/contrib/filters/templates/unfold/filters/filters_numeric_single.html,sha256=uELVrDzFgmzGwkm37SpZeXXbfpijDnSBIJVtf6evWjM,598
36
- unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html,sha256=ihRdegeKkP2R3XQ_Z3_wujkjnc7ZByGqhfuDw4zjtNU,1880
36
+ unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html,sha256=82H0q9Bta_ng4k6BYpV5ECspmBwqAUXnVGKdrEOLc18,1165
37
37
  unfold/contrib/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  unfold/contrib/forms/apps.py,sha256=Di0TMzVuRpVxLG-8Bjdq5ALCSf5r7u2xVhD0jU6H5Sc,132
39
39
  unfold/contrib/forms/static/unfold/forms/css/trix/LICENSE,sha256=-g0UVDdcvHcBvBPZFsOuceYTuK5xgyFkHmeOCUCTk8Q,1053
@@ -44,7 +44,7 @@ unfold/contrib/forms/static/unfold/forms/js/trix.config.js,sha256=spkNBlJVk_pqid
44
44
  unfold/contrib/forms/templates/unfold/forms/array.html,sha256=EKN_Tk1YKrdhZfOcC9aMKZMKyIiBk9frF0tYDWXqiDA,1799
45
45
  unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html,sha256=_sPtxaK14XzdfB6sAwA7ZYHbfIMtaKbORByxjxXoNh8,10130
46
46
  unfold/contrib/forms/templates/unfold/forms/wysiwyg.html,sha256=uLLf59jsD3apAm9Uh1TH4pwCOtO7pL2djAeZLOHyNAI,399
47
- unfold/contrib/forms/widgets.py,sha256=ctGrtqEnT9Azdr6oMTpqe7vCd_lECx7QKzaPE8-McLs,3394
47
+ unfold/contrib/forms/widgets.py,sha256=qjQ7al5CTVpBhsvTVr-6dTplJHB4dWeMxgh1tjU7Crc,3356
48
48
  unfold/contrib/guardian/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  unfold/contrib/guardian/apps.py,sha256=ObJqwh4vHxkD4XfduP5IQAiYiWZxsXUOUqF1_R1GsRI,136
50
50
  unfold/contrib/guardian/templates/admin/guardian/model/change_form.html,sha256=FSJc4MYYWyzZAy8Ay0b7Ov-cUo-oELHOM5fQehM54Lg,403
@@ -73,10 +73,10 @@ unfold/contrib/import_export/templates/admin/import_export/import_preview.html,s
73
73
  unfold/contrib/import_export/templates/admin/import_export/import_validation.html,sha256=K7j5OlWMQUTcSVulJtIraKfWIupSvmN4R5bZ2hH4tRA,5117
74
74
  unfold/contrib/import_export/templates/admin/import_export/resource_fields_list.html,sha256=Bc6uD8aHA5YYbZgLAPpGUckFjnxn9uq19YuKKFxTj4Y,887
75
75
  unfold/contrib/inlines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
- unfold/contrib/inlines/admin.py,sha256=__U86gR2OfdEiLPmOsKwTu7t8X2be8_jL-NL1SSNb3Q,6066
76
+ unfold/contrib/inlines/admin.py,sha256=7KNC1vikoOcpIwFu6oc1UvaS7u02VsnRypF5Z7qno9I,6050
77
77
  unfold/contrib/inlines/apps.py,sha256=Z9JBnzywq-DanZbD56fG0ndBfLXbojzkjVBleqoOBSU,136
78
78
  unfold/contrib/inlines/checks.py,sha256=0vkHUh-MtNSTrcOjCLbZmtI4961fFOygOv_dBAps6zw,534
79
- unfold/contrib/inlines/forms.py,sha256=noZdrBgvsu9tCBbRW3f9p7o6xKSuXtWR14qbZPdZBPA,1395
79
+ unfold/contrib/inlines/forms.py,sha256=yqhYxiNfcjMwMrNrCpN7wCnJtZytwt90jmPNfV_WWP0,1403
80
80
  unfold/contrib/location_field/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
81
81
  unfold/contrib/location_field/apps.py,sha256=qbNLfWXWf9q_gZxnuwFNVj20liSk_OT29uWMAi1she8,150
82
82
  unfold/contrib/location_field/templates/location_field/map_widget.html,sha256=vIBWNxIiCZipMnnPkZBFEZa-F3qXTKz9t4DbMmiBSSM,184
@@ -86,26 +86,27 @@ unfold/contrib/simple_history/templates/simple_history/object_history.html,sha25
86
86
  unfold/contrib/simple_history/templates/simple_history/object_history_form.html,sha256=TuQ_Fwrefjo3p9A-2asBxVq9bRJ9j5r11Jy-uS7K0TU,751
87
87
  unfold/contrib/simple_history/templates/simple_history/object_history_list.html,sha256=kMtxD5II32etsk05IArxe_wGvVjrizMVVH8uRl5RjR0,6816
88
88
  unfold/contrib/simple_history/templates/simple_history/submit_line.html,sha256=PEoPmWcWiiBIMs6XtXcoXswDtxp3FgntR3maieLDt4Y,1618
89
- unfold/dataclasses.py,sha256=XDQp7fcvto7YC8A68tc6TUhXY7s3je9nm3AVUdxrJ7Y,859
90
- unfold/decorators.py,sha256=jPiYFy1p0WGFn68VZhAZkYCPDF7argb9SDFaH6aemHk,4922
89
+ unfold/dataclasses.py,sha256=nCzcUufg60HHlJcAAgfSI_YPjXil3s2uMMhlJI0Lidk,803
90
+ unfold/datasets.py,sha256=ufWFJylqOiSJX2CYlQC8SpkAv2q84Fn63RvSkPdzIFc,2106
91
+ unfold/decorators.py,sha256=WWDhYipXs-z9ppyAteC9HVWJGvv8B-gIigrTF6hj4KM,4844
91
92
  unfold/enums.py,sha256=9sTfyEycMWeoGPBa-ft6ZhQGnW1vkFg108RMBVf9nko,187
92
93
  unfold/exceptions.py,sha256=gcCj1ox61E137bk_0Cqy4YC3SttdPgB-fiJUqpmyHSE,43
93
- unfold/fields.py,sha256=wvkdeMCIYs3vNB_QDtRo191tXoYVrP-uRFfzFCTYY3c,7314
94
- unfold/forms.py,sha256=0u4TFw7oQ96S7njzJ2G79Qzt1X-4P4px-kfMgjVt49o,7762
94
+ unfold/fields.py,sha256=883cbZFen5Ss8OKxAVrIbFynYn4em3TkWkyCksMcPWo,8344
95
+ unfold/forms.py,sha256=HE4F_WqVgywk1u5J54WP94yeGGFuGxK6UrIsxtB-9k4,8133
95
96
  unfold/layout.py,sha256=Q-dFTA6UlvvPCA4PsGyTkHQmBLO7PL56xBfZi-bdt0c,1459
96
97
  unfold/mixins/__init__.py,sha256=YlhoDs9Y_DXQ8Ejr3enxuHMS1-Ij9fwukxNwpeOS4Co,190
97
- unfold/mixins/action_model_admin.py,sha256=9Zt4FLrQWEQSO2vrpwjzpFo_I3_yE000uEwHndsW5kg,12365
98
- unfold/mixins/base_model_admin.py,sha256=Vr_Sd4xEsdekeKX8N70oiheYBzk2EwXbOX_frRw4JnE,4802
98
+ unfold/mixins/action_model_admin.py,sha256=h5z1ZqjIdqzSbe-pTrV8Yrw7ipp1OXATLXMjBe9Q6Hk,12332
99
+ unfold/mixins/base_model_admin.py,sha256=rAZspMkeESgSsbyFpubCr4gDbi7SopvT6--stRhqGRI,4777
99
100
  unfold/overrides.py,sha256=ERVY9boZiXgjDYcTEZcIp7KWoeBZ45VM_zN31yAOjyQ,2922
100
101
  unfold/paginator.py,sha256=bZiEY-1kqZy_6CYGs9fHo6WntMgpnFCH-LJPoXkEESk,533
101
102
  unfold/sections.py,sha256=Lcg3xCZ76fqjm4vD4x7YdE5VsbTKluL-sX5QTEBlHxA,2379
102
103
  unfold/settings.py,sha256=o_yjhM1OgW2KSrae4oeUqjLw3lI9HZ1lkKGUW4nuC4Q,3432
103
- unfold/sites.py,sha256=NIO2vjCmSabI4aWZmpEbjgiSv4m3q0qKPoQjaAdxwIA,21380
104
+ unfold/sites.py,sha256=qDdUBX6Q0TYSNQXovn7h9vuCZXopX8v_4vmxYbs_4t0,21314
104
105
  unfold/static/admin/js/admin/RelatedObjectLookups.js,sha256=ubKKhWmX_QborwPnaLHuQshTwQw6tK1pAViWdKIjw4E,9222
105
106
  unfold/static/admin/js/inlines.js,sha256=UXtFzCWHZWIJbxRghlNsNsz8HuRHjcaH1Mvb5e6uJms,16222
106
107
  unfold/static/unfold/css/simplebar/LICENSE,sha256=okNJf6UFl2NrEiC4iqORNBa16IKgUgV88acdcl9FbtY,1081
107
108
  unfold/static/unfold/css/simplebar/simplebar.css,sha256=5LLaEM11pKi6JFCOLt4XKuZxTpT9rpdq_tNlaQytFlU,4647
108
- unfold/static/unfold/css/styles.css,sha256=MZEBfoBM6rUi0pkIoQw0hi2lChPsdCFIchyBOm4oF8c,211708
109
+ unfold/static/unfold/css/styles.css,sha256=H22ldb2tEY0zCuTISs3_gNmt2k37erO5XAXFkiGWPRM,211578
109
110
  unfold/static/unfold/fonts/inter/Inter-Bold.woff2,sha256=-oiBJ7baAVtlVp8DUfO1w5GtkokElR8cIOn4RiqNleo,114840
110
111
  unfold/static/unfold/fonts/inter/Inter-Medium.woff2,sha256=D_PpRhThST61VjFP0keubEqFp3g7TMhr5TmUDPg_Kkg,114348
111
112
  unfold/static/unfold/fonts/inter/Inter-Regular.woff2,sha256=4G9rG8VTqupORmgCPtCrChRxKcMQf1Ebx9A9NhsK4IU,111268
@@ -121,15 +122,15 @@ unfold/static/unfold/js/alpine/alpine.js,sha256=PtHu0lJIiSHfZeNj1nFd6wTX-Squ255S
121
122
  unfold/static/unfold/js/alpine/alpine.persist.js,sha256=jFBwr6faTqqhp3sVi4_VTxJ0FpaF9YGZN1ZGLl_5QYM,837
122
123
  unfold/static/unfold/js/alpine/alpine.resize.js,sha256=mXR2L6neT584cfNLY5_imDq5DKjW1noXys7fhb1yxY4,703
123
124
  unfold/static/unfold/js/alpine/alpine.sort.js,sha256=q6LxgConwu8M8R03mZSBcsKwJv6fF7oomP8sqLxVQ0w,37891
124
- unfold/static/unfold/js/app.js,sha256=rz5y-wOzUpXN1Gk23bot3XMyB6P3rTSSz6kqdDtuyMU,14775
125
+ unfold/static/unfold/js/app.js,sha256=GW-kAIuEW56h0Eaws0opoK1Ck-eTVjnj5hcbwzeZxIA,16352
125
126
  unfold/static/unfold/js/chart/LICENSE,sha256=QahKosq6ZF-WahjZwgVrc-bTqB2AvABGvAARomNNTM4,1093
126
127
  unfold/static/unfold/js/chart/chart.js,sha256=22W6cFERR-CElMOKRgMMicueMVP0Vf7FBEBYH8Z8tCk,200633
127
128
  unfold/static/unfold/js/htmx/LICENSE,sha256=09JFb3ZBTyRWEEZg69Za_xwEzXlmuUK9q9Y_PNsxajg,642
128
129
  unfold/static/unfold/js/htmx/htmx.js,sha256=acrv0NqSJpBm5yXX_hdeJrnVDJYuMFZFnAxHcVTNudM,50918
129
- unfold/static/unfold/js/select2.init.js,sha256=E1BhZ_a16_wxMb3zFq346HIrzvfQz8PRSB_o5CH_i2E,1196
130
+ unfold/static/unfold/js/select2.init.js,sha256=SeUUXgwLi26Tmh1Sgl3al4WeqlvmbZgixmTtwhJMMq0,1009
130
131
  unfold/static/unfold/js/simplebar/LICENSE,sha256=okNJf6UFl2NrEiC4iqORNBa16IKgUgV88acdcl9FbtY,1081
131
132
  unfold/static/unfold/js/simplebar/simplebar.js,sha256=t-uG1FAD6ZoiMeN--wac0XRS7SxoDVG6zvRnGuEp7X8,27176
132
- unfold/styles.css,sha256=hNU0840jnbJB20nLuE12sbKX3jCqjWR76mmsLN9uZic,21739
133
+ unfold/styles.css,sha256=4GfTn3K3y-X1xa6w2V6489XqmsxTSOwqtrKlCEaRE6c,21527
133
134
  unfold/templates/admin/actions.html,sha256=iuuubcAILkOoYBgV6cpXqFIyZUh4zMqyFp0JaDFlPKU,3096
134
135
  unfold/templates/admin/app_index.html,sha256=hcXcaEwqKYTaClnGzlBEsTzy3YJn_37AiFs4YVbvX8A,585
135
136
  unfold/templates/admin/app_list.html,sha256=-DEZKFdmkdTq3rix_cgZurPZ1r8PHg5pBL3i7ZtzVdI,2972
@@ -137,15 +138,15 @@ unfold/templates/admin/auth/user/add_form.html,sha256=-_YY4guGdAbw2rCskrQfRAAvQF
137
138
  unfold/templates/admin/auth/user/change_password.html,sha256=3NIopJ8JFN4iv428kUTqRthZvmden9sb0-D7AKohRjA,1577
138
139
  unfold/templates/admin/base.html,sha256=CuttiTMMtEiPNIEv4VXt27UGITgqPZaz5V8BJlBEOdk,1663
139
140
  unfold/templates/admin/base_site.html,sha256=UOsecaCycpyn_ygJNIKO7MQtDFJuHv--r83-mzaVY30,300
140
- unfold/templates/admin/change_form.html,sha256=yY0XLtN52_XHN5EofvQ1bGdhlkG38qhDvGxePhM1_Ak,4690
141
+ unfold/templates/admin/change_form.html,sha256=GSDucoXPJdGjuG9ji8fM3CJhW0bTtDhZ18hKxAgIZpM,4876
141
142
  unfold/templates/admin/change_form_object_tools.html,sha256=eyeH-i2HgEM0Yi-OJA2D1VnKJyC19A_my1IDGxxoP8Y,593
142
143
  unfold/templates/admin/change_list.html,sha256=aesNLu_b4j90Q08nWpMlVembYuH0TMGhwO7DJMMrSsI,4503
143
144
  unfold/templates/admin/change_list_object_tools.html,sha256=cmMiT2nT20Ph5yfpj9aHPr76Z-JP4aSXp0o-Rnad28s,147
144
- unfold/templates/admin/change_list_results.html,sha256=NZmqOajOP9-TSJSUZxU7z-6_cpJX8rgrcvPoQfehMb8,8193
145
+ unfold/templates/admin/change_list_results.html,sha256=G4OJb7Quqc5qQeWT0zl6kN-BzUVaOtN2nYoiPdrUS_w,5069
145
146
  unfold/templates/admin/date_hierarchy.html,sha256=A-sIqBKzZTMqSn3NSHORIL1yTEAqhj4Atff0OvWtqT0,1413
146
147
  unfold/templates/admin/delete_confirmation.html,sha256=0vHhrbUAOW8CXfkEB20JoA9qV5xRbyb5xGc1jpWcrN4,3661
147
148
  unfold/templates/admin/delete_selected_confirmation.html,sha256=mtRZyZH5xBRk60KktA8PZviAeI3yOH34cS_FDHaZOu0,3401
148
- unfold/templates/admin/edit_inline/stacked.html,sha256=EpTG-HPExprnY833xeFcqY8qTOnNXvDHYicgl2NkIZI,8628
149
+ unfold/templates/admin/edit_inline/stacked.html,sha256=TcYSqEiuFWvwbse1ehVDVQD2vIRaLJtzb0jIKFzdQJ0,8625
149
150
  unfold/templates/admin/edit_inline/tabular.html,sha256=DtXaKC_0HEKPIphbqiykixQa1cRrEYcnLV7I3VlynhU,3020
150
151
  unfold/templates/admin/filter.html,sha256=DEyrLgCWuncS1O1WR0vlt1evGQFvKoZV2pABkHzSoGU,2039
151
152
  unfold/templates/admin/includes/fieldset.html,sha256=UWcatsmHzfdcjZP58P94YL7BI3F-CP-BgYi2uC7FSb4,1471
@@ -155,14 +156,14 @@ unfold/templates/admin/login.html,sha256=E963dlzjZlkNc6WPJg9DiqijWAhRp1QLVCxFHkR
155
156
  unfold/templates/admin/nav_sidebar.html,sha256=NiNcLF-0eZwwv2arsikChzwbH7FTI1vEch427KddFlk,772
156
157
  unfold/templates/admin/object_history.html,sha256=4S9xpBtywUdFPUmvAuH2lMOG6jxCFZ-rFZYnhbajkRw,3726
157
158
  unfold/templates/admin/pagination.html,sha256=-9kjc_lKEeqvDVHMrnTfnlXDxMSkM8GNRGZGuI9D8os,912
158
- unfold/templates/admin/search_form.html,sha256=7ckco8llu5paptroZgr3jZw54DtowX-NiwFvxsCV898,1713
159
+ unfold/templates/admin/search_form.html,sha256=bo0WXtAZZi1uw-D1UDQ_Q0mUt8z5FDEEwseShdngN48,1862
159
160
  unfold/templates/admin/submit_line.html,sha256=9FDZ5HOfiJG11HSMtA4rfqjKe3ucC-_OChpx1CGTLac,4626
160
161
  unfold/templates/auth/widgets/read_only_password_hash.html,sha256=MlaNXJ2PLEbv8Nd01BBp-AQEfMB13LNxD_DzRemXhCg,775
161
162
  unfold/templates/registration/logged_out.html,sha256=ytjIz3abnpERwUp1F8zn89HyrimSrb9wgUna3Iz0CJE,1202
162
163
  unfold/templates/registration/password_change_done.html,sha256=TjzRQ476BNkz3To2S7MhEXxA-zoqCI8Op_FjY0cRod0,364
163
164
  unfold/templates/registration/password_change_form.html,sha256=E9fRkSh7n5N7UQIy0oWpcvI1mVPQ0nYGlBrM_WTi9kw,1517
164
165
  unfold/templates/unfold/components/button.html,sha256=oJEamHBxDIjoQ1xqWuJWDMY5ItUo8jpkZrqFp_cCH5U,933
165
- unfold/templates/unfold/components/card.html,sha256=ntmFJcHWDQ1M6Xp9mE9BpIBeOfV-huSayDqz1Ajnd0k,1410
166
+ unfold/templates/unfold/components/card.html,sha256=inSlz0IbriTQwA-I9sAa8A15NAfjqOWRka28vB-Eu_Q,1565
166
167
  unfold/templates/unfold/components/chart/bar.html,sha256=nDdDCUXvFd793OpNgNPQo0vBmvYngMsQyPHVTf1vfOw,297
167
168
  unfold/templates/unfold/components/chart/cohort.html,sha256=L00WR-igYv0C3t2yT_nZqeI-M5gVHpoaGv5RooRojqU,2402
168
169
  unfold/templates/unfold/components/chart/line.html,sha256=DHaZUFTlCs5cX7ioYdTzoN4ITHWNcEoNSUp7v3hlo_E,298
@@ -171,7 +172,7 @@ unfold/templates/unfold/components/flex.html,sha256=_hBsQLJ6-7MfEfXNp5Wy-ykNtPMn
171
172
  unfold/templates/unfold/components/icon.html,sha256=Qlhcf41FOwNVJ-nvA0RJ_Dn6JW6PUFXO6tOR3Xtf6e8,99
172
173
  unfold/templates/unfold/components/layer.html,sha256=c2EY2rr64rJ5BPj97UdFAJTNWAommGoYL9J8gmjzEPE,15
173
174
  unfold/templates/unfold/components/navigation.html,sha256=0imW9pQs9kUZy2iROeAsGJDXC5tMRq9ABRcN85fJPeQ,866
174
- unfold/templates/unfold/components/progress.html,sha256=W55ByXiM-Ig_3fcpsZAG8N3HjQAl60sl7XsLsIZABrA,1001
175
+ unfold/templates/unfold/components/progress.html,sha256=voyLSflK08x7SP9mdsEixAsGiZj7YVfnZlfqntdw8ok,1480
175
176
  unfold/templates/unfold/components/separator.html,sha256=yvHywT_MFkx5dNC2K53OFHRGxLDsEjRpptujXyGeoTY,168
176
177
  unfold/templates/unfold/components/table.html,sha256=5Ghmaw3mHhKOlBKKRBfhmSx0-HkRx1sHpX6NDItgdv4,7911
177
178
  unfold/templates/unfold/components/text.html,sha256=-GjxvdiaBQIaNfPSzT6SSIwnc3R27FkSDQMoF3FDPso,102
@@ -188,23 +189,26 @@ unfold/templates/unfold/helpers/breadcrumb_item.html,sha256=9T6ojN7LOXIlgwSwlIwH
188
189
  unfold/templates/unfold/helpers/change_list_actions.html,sha256=xuFMZel6kH014H9sl0hKvQo7LP0UxwlhFQHIUeyQxVM,643
189
190
  unfold/templates/unfold/helpers/change_list_filter.html,sha256=WwU-AG4U5qZQ_sFs1z_jaaYBWqIv3ASmtKIQIhAp2gs,1908
190
191
  unfold/templates/unfold/helpers/change_list_filter_actions.html,sha256=K99hHgpCLaAHxv-eqIf4nOUfq6CeTQHekEeudKTRYME,2036
192
+ unfold/templates/unfold/helpers/change_list_headers.html,sha256=_pGLbrTuzmlowfydbCEjbKCqCf3z6juhGxMdb8l9j0M,3545
191
193
  unfold/templates/unfold/helpers/command.html,sha256=VDy7b6mlDL9kpt2VrCuUQwzjwUOPztUL3hrU2kp0tVs,2885
192
194
  unfold/templates/unfold/helpers/command_history.html,sha256=AB5elGPyY51aHuaWnwXddZmdcSadcqBOzdzjYqR4lfU,2866
193
195
  unfold/templates/unfold/helpers/command_results.html,sha256=3sYaBePPt9o_WDS9UeZojW-QZzbOGd474r2Elfn_33Q,3679
196
+ unfold/templates/unfold/helpers/dataset.html,sha256=mweBoXLW2vpMiJvwEGedXsOc4OdEBsr_O9f15zSgvWY,784
194
197
  unfold/templates/unfold/helpers/delete_submit_line.html,sha256=7SNS0axGytvUih9KxtOzy9ZC5rwG9u99iQxlnUZQfdE,700
195
198
  unfold/templates/unfold/helpers/display_dropdown.html,sha256=IpOy8-hww4arAVjPIRsHrip30J3IEd2p-2BzD3BjIaA,2906
196
199
  unfold/templates/unfold/helpers/display_header.html,sha256=2u-5Vc3mA6rS3ZlOWm3WRNLUX1wmZy4OSmGY2mdPZYs,1714
197
200
  unfold/templates/unfold/helpers/display_label.html,sha256=LS9DWzYjHkYLV27sZDwyXlg2sLJ0AlId9FbjnXpsbfg,317
198
201
  unfold/templates/unfold/helpers/edit_inline/tabular_delete.html,sha256=wr8zmSUhKcoxxms6gJsBqBrANFTOXELYUvlr3XjnjnE,931
199
202
  unfold/templates/unfold/helpers/edit_inline/tabular_error.html,sha256=8XGlgUJ47JllmXhwPZDlcl81NzZmvuBIp8FZBWoeu9Q,336
200
- unfold/templates/unfold/helpers/edit_inline/tabular_field.html,sha256=QETtgDYirbFBMCRH0sRU8IkODS0fBouA6crZ_K4ufTA,1007
203
+ unfold/templates/unfold/helpers/edit_inline/tabular_field.html,sha256=xw4Mrxf6AirZcOyLeg5sRjlHBftWlCOE-_A9F-OEdEo,1004
201
204
  unfold/templates/unfold/helpers/edit_inline/tabular_heading.html,sha256=wvnpGFJVHFvamGLpRCpGoP7WALFKqR1KKvVIIRhWFQc,1520
202
205
  unfold/templates/unfold/helpers/edit_inline/tabular_row.html,sha256=eCyWEYvvDDCr9SR4_0ua5-GqCLIlFzgQYIZP0ip8cp8,2145
203
206
  unfold/templates/unfold/helpers/edit_inline/tabular_title.html,sha256=2sk1TRzpmwy8PPPMNdf6CJx0zVSk-I2q3yX8uEPjuxE,2710
204
- unfold/templates/unfold/helpers/empty_results.html,sha256=zN1XM6_9_Oj-inMZlDxEnicYfBRr4HhwS9ODAnMiRYc,1947
207
+ unfold/templates/unfold/helpers/empty_results.html,sha256=X0cno3qZ2nbiRQSMjH1zB97Z_nSVM7M0EOOGV6mx734,2117
205
208
  unfold/templates/unfold/helpers/field.html,sha256=KEs1SQRxzJ0x11zithlxVyv5zfQ9a_XGoJJ9AiWk1Vc,1038
206
209
  unfold/templates/unfold/helpers/field_readonly.html,sha256=4qtXjWE7SA2qZSTYLOv0lT4pQfD0TE34mvWQJY7jhS8,237
207
- unfold/templates/unfold/helpers/field_readonly_value.html,sha256=FI_CFEsCN7ELQux9gF-IaZ7nT7jyzidqwR2Med-E52g,504
210
+ unfold/templates/unfold/helpers/field_readonly_value.html,sha256=dQHLb3eWeTZnXVzT8vaCbFNb4H9NwwNAv3qOKpOfDtM,531
211
+ unfold/templates/unfold/helpers/field_readonly_value_file.html,sha256=1oHAVkn71WbVxKTjwQMyW03yIZBbKY-ZSorZA5wlrgI,710
208
212
  unfold/templates/unfold/helpers/fieldset_row.html,sha256=LriorPLXU4VmqstjX1oBc3T49H8CbhCrRxwQ7YfUSkI,1219
209
213
  unfold/templates/unfold/helpers/fieldset_row_checkbox.html,sha256=z4aRab--zJS2PC0jfKPez85IptKGRrqgkPpwW6_IKoo,1467
210
214
  unfold/templates/unfold/helpers/fieldset_row_field.html,sha256=cqLT1fHsCCszOHxvYlDFDTAd-6RRoOjdqfdBdhFgHOo,647
@@ -245,7 +249,7 @@ unfold/templates/unfold/helpers/site_logo.html,sha256=S_QJoT2qh0xw0ciaKxoT4GJ6QI
245
249
  unfold/templates/unfold/helpers/submit.html,sha256=6bfZ7V2PTJfSXGg4K3IEZ42oREkMdAVjfP8yaM8Tu0k,226
246
250
  unfold/templates/unfold/helpers/tab_action.html,sha256=mJd87_2qkSNQEwDZZCDkvll5ZbizBkPxWFnBR-kH89o,3431
247
251
  unfold/templates/unfold/helpers/tab_actions.html,sha256=koe4D-vm7PRPqZ4FPjo3KEfWARebcpt1KuUJ7oa7PK4,685
248
- unfold/templates/unfold/helpers/tab_items.html,sha256=GE1-5pC6CZShn666AxpZ548mfs3lKWzMkrBedjaKJfo,1945
252
+ unfold/templates/unfold/helpers/tab_items.html,sha256=VNdzOnjH-vCIhgnyqIXyu3S8p91i_qLRKez3BwX5LZQ,2297
249
253
  unfold/templates/unfold/helpers/tab_list.html,sha256=7Jy4QrGfmKq4ORBi9w_Wya_b2QJZOZndvILDaM1unBc,386
250
254
  unfold/templates/unfold/helpers/theme_switch.html,sha256=Y46KKpULH_G-fKQuc5LzfSB7Pubcgj_dBJPRMwZoWxE,2408
251
255
  unfold/templates/unfold/helpers/unauthenticated_header.html,sha256=nBTHKonEmR87zMAivl48E4c1xOVcTujodn6H9rAf_6U,601
@@ -298,13 +302,13 @@ unfold/templates/unfold_crispy/uni_form.html,sha256=l9UNCUrIycgJ0p_B6qhtO_YxdARy
298
302
  unfold/templates/unfold_crispy/whole_uni_form.html,sha256=ufXRKCIGqkqKFOsh166rpKUnHpFMyBV4eYUCRhs3iws,475
299
303
  unfold/templates/unfold_crispy/whole_uni_formset.html,sha256=CYksfG2hRUdi5n691KW2ih-FfBxpOU4qVBfbOvcu1zs,873
300
304
  unfold/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
301
- unfold/templatetags/unfold.py,sha256=zzIQyP1O8j1KfzYbCT0TW3gJROj3dZJOq5Y6MbwUe8I,24376
302
- unfold/templatetags/unfold_list.py,sha256=WWQSCM4QmQMr8YddA4krFztuuUXo2y28RA7jZfOiewE,14415
303
- unfold/typing.py,sha256=i7LM2LiwYTAjT5-OLDUPVn5b9X-DMmHnjlZG2toWwSE,692
304
- unfold/utils.py,sha256=UY7ZvkQ6KXkY0OkThppZ1k1HggyUhV_2bZok-HpFBDA,6827
305
- unfold/views.py,sha256=SA6mtv3aJD861-aL5VNreQUP7GRZH6hK_60MChjm2MM,1641
306
- unfold/widgets.py,sha256=nu2oqcKhs3lhj9ueYfs3BqDzZT5raAE6jeAEgU4WrHE,24751
307
- django_unfold-0.66.0.dist-info/METADATA,sha256=03YKKQ-HAzpxOxPlLKN9ps2rYqatp9HZf_cJpjjVXM0,10074
308
- django_unfold-0.66.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
309
- django_unfold-0.66.0.dist-info/licenses/LICENSE.md,sha256=Ltk_quRyyvV3J5v3brtOqmibeZSw2Hrb8bY1W3ya0Ik,1077
310
- django_unfold-0.66.0.dist-info/RECORD,,
305
+ unfold/templatetags/unfold.py,sha256=j50CfXpT-Mq9_ggvmvXhZiTiDnkuRgzat4bZoRpB2HI,24575
306
+ unfold/templatetags/unfold_list.py,sha256=ld95N81rIjPyZ2DsDQXpoiFQ0YQ8zbqIMYRCtrGBuLQ,16096
307
+ unfold/typing.py,sha256=N3W54YqV2Kig0y3sP2gHKM4ZuHxpzYe2L9J4ve9rnPg,651
308
+ unfold/utils.py,sha256=qNwL3Wsv3u8nzB5l9PXAXRp6w4p4qXDbQHJAScbXSy4,6804
309
+ unfold/views.py,sha256=4hnLureeD-5xVABO-EDFPoGHpmtOgAuyB7cE4QLkfos,2255
310
+ unfold/widgets.py,sha256=q29qq7mC32DHZ7DxXd7Fo_nOFFDtdpRBeY7TsQA067I,24659
311
+ django_unfold-0.68.0.dist-info/METADATA,sha256=1dQ37Cyg2ucjwCuN43SbMm9Y0Esa1lHjcdcL3nBykoQ,10277
312
+ django_unfold-0.68.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
313
+ django_unfold-0.68.0.dist-info/licenses/LICENSE.md,sha256=Ltk_quRyyvV3J5v3brtOqmibeZSw2Hrb8bY1W3ya0Ik,1077
314
+ django_unfold-0.68.0.dist-info/RECORD,,
unfold/admin.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from functools import update_wrapper
2
- from typing import Any, Optional
2
+ from typing import Any
3
3
 
4
4
  from django import forms
5
5
  from django.contrib.admin import ModelAdmin as BaseModelAdmin
@@ -7,6 +7,8 @@ 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
9
  from django.contrib.admin.options import InlineModelAdmin
10
+ from django.contrib.admin.views import main
11
+ from django.contrib.admin.views.main import IGNORED_PARAMS
10
12
  from django.contrib.contenttypes.admin import (
11
13
  GenericStackedInline as BaseGenericStackedInline,
12
14
  )
@@ -23,6 +25,7 @@ from django.utils.translation import gettext_lazy as _
23
25
  from django.views import View
24
26
 
25
27
  from unfold.checks import UnfoldModelAdminChecks
28
+ from unfold.datasets import BaseDataset
26
29
  from unfold.forms import (
27
30
  ActionForm,
28
31
  PaginationGenericInlineFormSet,
@@ -47,6 +50,8 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
47
50
  action_form = ActionForm
48
51
  custom_urls = ()
49
52
  add_fieldsets = ()
53
+ ordering_field = None
54
+ hide_ordering_field = False
50
55
  list_horizontal_scrollbar_top = False
51
56
  list_filter_submit = False
52
57
  list_filter_sheet = True
@@ -58,6 +63,7 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
58
63
  change_form_after_template = None
59
64
  change_form_outer_before_template = None
60
65
  change_form_outer_after_template = None
66
+ change_form_datasets = ()
61
67
  compressed_fields = False
62
68
  readonly_preprocess_fields = {}
63
69
  warn_unsaved_form = False
@@ -72,7 +78,7 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
72
78
 
73
79
  for filter in self.get_list_filter(self.request):
74
80
  if (
75
- isinstance(filter, (tuple, list))
81
+ isinstance(filter, tuple | list)
76
82
  and hasattr(filter[1], "form_class")
77
83
  and hasattr(filter[1].form_class, "Media")
78
84
  ):
@@ -83,12 +89,61 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
83
89
  return media
84
90
 
85
91
  def changelist_view(
86
- self, request: HttpRequest, extra_context: Optional[dict[str, str]] = None
92
+ self, request: HttpRequest, extra_context: dict[str, str] | None = None
87
93
  ) -> TemplateResponse:
88
94
  self.request = request
95
+
96
+ if self.ordering_field and self.ordering_field not in self.list_editable:
97
+ list_editable = list(getattr(self, "list_editable", []))
98
+ list_editable.append(self.ordering_field)
99
+ self.list_editable = list_editable
100
+
89
101
  return super().changelist_view(request, extra_context)
90
102
 
91
- def get_fieldsets(self, request: HttpRequest, obj=None) -> FieldsetsType:
103
+ def changeform_view(
104
+ self,
105
+ request: HttpRequest,
106
+ object_id: str | None = None,
107
+ form_url: str = "",
108
+ extra_context: dict[str, Any] | None = None,
109
+ ) -> TemplateResponse:
110
+ self.request = request
111
+ extra_context = extra_context or {}
112
+ datasets = self.get_changeform_datasets(request)
113
+
114
+ # Monkeypatch IGNORED_PARAMS to add dataset page and search arguments into ignored params
115
+ ignored_params = []
116
+ for dataset in datasets:
117
+ ignored_params.append(f"{dataset.model._meta.model_name}-q")
118
+ ignored_params.append(f"{dataset.model._meta.model_name}-p")
119
+
120
+ main.IGNORED_PARAMS = (*IGNORED_PARAMS, *ignored_params)
121
+
122
+ rendered_datasets = []
123
+ for dataset in datasets:
124
+ rendered_datasets.append(
125
+ dataset(
126
+ request=request,
127
+ extra_context={
128
+ "object": object_id,
129
+ },
130
+ )
131
+ )
132
+
133
+ extra_context["datasets"] = rendered_datasets
134
+ return super().changeform_view(request, object_id, form_url, extra_context)
135
+
136
+ def get_list_display(self, request: HttpRequest) -> list[str]:
137
+ list_display = super().get_list_display(request)
138
+
139
+ if self.ordering_field and self.ordering_field not in list_display:
140
+ list_display.append(self.ordering_field)
141
+
142
+ return list_display
143
+
144
+ def get_fieldsets(
145
+ self, request: HttpRequest, obj: Model | None = None
146
+ ) -> FieldsetsType:
92
147
  if not obj and self.add_fieldsets:
93
148
  return self.add_fieldsets
94
149
  return super().get_fieldsets(request, obj)
@@ -119,7 +174,7 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
119
174
 
120
175
  actions_list_urls = [
121
176
  path(
122
- action.path,
177
+ f"{action.path.removesuffix('/')}/",
123
178
  wrap(action.method),
124
179
  name=action.action_name,
125
180
  )
@@ -128,7 +183,7 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
128
183
 
129
184
  action_detail_urls = [
130
185
  path(
131
- f"<path:object_id>/{action.path}",
186
+ f"<path:object_id>/{action.path.removesuffix('/')}/",
132
187
  wrap(action.method),
133
188
  name=action.action_name,
134
189
  )
@@ -137,7 +192,7 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
137
192
 
138
193
  action_row_urls = [
139
194
  path(
140
- f"<path:object_id>/{action.path}",
195
+ f"<path:object_id>/{action.path.removesuffix('/')}/",
141
196
  wrap(action.method),
142
197
  name=action.action_name,
143
198
  )
@@ -152,7 +207,7 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
152
207
  + urls
153
208
  )
154
209
 
155
- def _path_from_custom_url(self, custom_url) -> URLPattern:
210
+ def _path_from_custom_url(self, custom_url: tuple[str, str, View]) -> URLPattern:
156
211
  return path(
157
212
  custom_url[0],
158
213
  self.admin_site.admin_view(custom_url[2]),
@@ -161,13 +216,15 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
161
216
  )
162
217
 
163
218
  def get_action_choices(
164
- self, request: HttpRequest, default_choices=BLANK_CHOICE_DASH
165
- ):
219
+ self,
220
+ request: HttpRequest,
221
+ default_choices: list[tuple[str, str]] = BLANK_CHOICE_DASH,
222
+ ) -> list[tuple[str, str]]:
166
223
  default_choices = [("", _("Select action"))]
167
224
  return super().get_action_choices(request, default_choices)
168
225
 
169
226
  @display(description=mark_safe(checkbox.render("action_toggle_all", 1)))
170
- def action_checkbox(self, obj: Model):
227
+ def action_checkbox(self, obj: Model) -> str:
171
228
  return checkbox.render(helpers.ACTION_CHECKBOX_NAME, str(obj.pk))
172
229
 
173
230
  def response_change(self, request: HttpRequest, obj: Model) -> HttpResponse:
@@ -177,14 +234,14 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
177
234
  return res
178
235
 
179
236
  def response_add(
180
- self, request: HttpRequest, obj: Model, post_url_continue: Optional[str] = None
237
+ self, request: HttpRequest, obj: Model, post_url_continue: str | None = None
181
238
  ) -> HttpResponse:
182
239
  res = super().response_add(request, obj, post_url_continue)
183
240
  if "next" in request.GET:
184
241
  return redirect(request.GET["next"])
185
242
  return res
186
243
 
187
- def get_changelist(self, request, **kwargs):
244
+ def get_changelist(self, request: HttpRequest, **kwargs: Any) -> ChangeList:
188
245
  return ChangeList
189
246
 
190
247
  def get_formset_kwargs(
@@ -198,6 +255,9 @@ class ModelAdmin(BaseModelAdminMixin, ActionModelAdminMixin, BaseModelAdmin):
198
255
 
199
256
  return formset_kwargs
200
257
 
258
+ def get_changeform_datasets(self, request: HttpRequest) -> list[type[BaseDataset]]:
259
+ return self.change_form_datasets
260
+
201
261
 
202
262
  class BaseInlineMixin:
203
263
  formfield_overrides = FORMFIELD_OVERRIDES_INLINE
unfold/components.py CHANGED
@@ -1,4 +1,4 @@
1
- from typing import Any, Optional
1
+ from typing import Any
2
2
 
3
3
  from django.http import HttpRequest
4
4
 
@@ -21,7 +21,7 @@ class ComponentRegistry:
21
21
  cls._registry[class_name] = component_cls
22
22
 
23
23
  @classmethod
24
- def get_class(cls, class_name: str) -> Optional[type]:
24
+ def get_class(cls, class_name: str) -> type | None:
25
25
  return cls._registry.get(class_name)
26
26
 
27
27
  @classmethod
@@ -4,10 +4,11 @@ from typing import Any
4
4
  from django.contrib import admin
5
5
  from django.contrib.admin.views.main import ChangeList
6
6
  from django.core.validators import EMPTY_VALUES
7
- from django.db.models import QuerySet
7
+ from django.db.models import Model, QuerySet
8
8
  from django.http import HttpRequest
9
9
  from django.utils.translation import gettext_lazy as _
10
10
 
11
+ from unfold.admin import ModelAdmin
11
12
  from unfold.contrib.filters.admin.mixins import (
12
13
  ChoicesMixin,
13
14
  MultiValueMixin,
@@ -56,6 +57,17 @@ class CheckboxFilter(RadioFilter):
56
57
  form_class = CheckboxForm
57
58
  all_option = None
58
59
 
60
+ # TODO: remove once django 4.x is not supported
61
+ def __init__(
62
+ self,
63
+ request: HttpRequest,
64
+ params: dict[str, Any],
65
+ model: type[Model],
66
+ model_admin: ModelAdmin,
67
+ ) -> None:
68
+ self.request = request
69
+ super().__init__(request, params, model, model_admin)
70
+
59
71
  def value(self) -> list[Any]:
60
72
  return self.request.GET.getlist(self.parameter_name)
61
73
 
@@ -1,5 +1,5 @@
1
1
  from collections.abc import Generator
2
- from typing import Any, Optional
2
+ from typing import Any
3
3
 
4
4
  from django.contrib.admin.views.main import ChangeList
5
5
  from django.core.validators import EMPTY_VALUES
@@ -18,7 +18,7 @@ from unfold.contrib.filters.forms import (
18
18
 
19
19
 
20
20
  class ValueMixin:
21
- def value(self) -> Optional[str]:
21
+ def value(self) -> str | None:
22
22
  return (
23
23
  self.lookup_val[0]
24
24
  if self.lookup_val not in EMPTY_VALUES
@@ -29,7 +29,7 @@ class ValueMixin:
29
29
 
30
30
 
31
31
  class MultiValueMixin:
32
- def value(self) -> Optional[list[str]]:
32
+ def value(self) -> list[str] | None:
33
33
  return (
34
34
  self.lookup_val
35
35
  if self.lookup_val not in EMPTY_VALUES
@@ -1,4 +1,4 @@
1
- from typing import Any, Optional
1
+ from typing import Any
2
2
 
3
3
  from django.contrib import admin
4
4
  from django.contrib.admin.options import ModelAdmin
@@ -35,7 +35,7 @@ class SingleNumericFilter(admin.FieldListFilter):
35
35
  ) -> None:
36
36
  super().__init__(field, request, params, model, model_admin, field_path)
37
37
 
38
- if not isinstance(field, (DecimalField, IntegerField, FloatField, AutoField)):
38
+ if not isinstance(field, DecimalField | IntegerField | FloatField | AutoField):
39
39
  raise TypeError(
40
40
  f"Class {type(self.field)} is not supported for {self.__class__.__name__}."
41
41
  )
@@ -54,7 +54,7 @@ class SingleNumericFilter(admin.FieldListFilter):
54
54
 
55
55
  def queryset(
56
56
  self, request: HttpRequest, queryset: QuerySet[Any]
57
- ) -> Optional[QuerySet]:
57
+ ) -> QuerySet | None:
58
58
  if self.value():
59
59
  try:
60
60
  return queryset.filter(**{self.parameter_name: self.value()})
@@ -64,7 +64,7 @@ class SingleNumericFilter(admin.FieldListFilter):
64
64
  def value(self) -> Any:
65
65
  return self.used_parameters.get(self.parameter_name, None)
66
66
 
67
- def expected_parameters(self) -> list[Optional[str]]:
67
+ def expected_parameters(self) -> list[str | None]:
68
68
  return [self.parameter_name]
69
69
 
70
70
  def choices(self, changelist: ChangeList) -> tuple[dict[str, Any], ...]:
@@ -111,7 +111,7 @@ class RangeNumericFilter(RangeNumericMixin, admin.FieldListFilter):
111
111
  field_path: str,
112
112
  ) -> None:
113
113
  super().__init__(field, request, params, model, model_admin, field_path)
114
- if not isinstance(field, (DecimalField, IntegerField, FloatField, AutoField)):
114
+ if not isinstance(field, DecimalField | IntegerField | FloatField | AutoField):
115
115
  raise TypeError(
116
116
  f"Class {type(self.field)} is not supported for {self.__class__.__name__}."
117
117
  )
@@ -156,7 +156,7 @@ class SliderNumericFilter(RangeNumericFilter):
156
156
  else:
157
157
  max_value = None
158
158
 
159
- if isinstance(self.field, (FloatField, DecimalField)):
159
+ if isinstance(self.field, FloatField | DecimalField):
160
160
  decimals = self.MAX_DECIMALS
161
161
  step = self.STEP if self.STEP else self._get_min_step(self.MAX_DECIMALS)
162
162
  else:
@@ -179,6 +179,8 @@ class SliderNumericFilter(RangeNumericFilter):
179
179
  ),
180
180
  "form": self.form_class(
181
181
  name=self.parameter_name,
182
+ min=min_value,
183
+ max=max_value,
182
184
  data={
183
185
  self.parameter_name + "_from": self.used_parameters.get(
184
186
  self.parameter_name + "_from", min_value