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,5 +1,5 @@
1
1
  import copy
2
- from typing import Any, Optional
2
+ from typing import Any
3
3
 
4
4
  from django.contrib.admin import helpers
5
5
  from django.contrib.admin.sites import AdminSite
@@ -31,9 +31,9 @@ class BaseModelAdminMixin:
31
31
  def changeform_view(
32
32
  self,
33
33
  request: HttpRequest,
34
- object_id: Optional[str] = None,
34
+ object_id: str | None = None,
35
35
  form_url: str = "",
36
- extra_context: Optional[dict[str, Any]] = None,
36
+ extra_context: dict[str, Any] | None = None,
37
37
  ) -> Any:
38
38
  from unfold.forms import AdminForm, Fieldline
39
39
 
@@ -61,7 +61,7 @@ class BaseModelAdminMixin:
61
61
 
62
62
  def formfield_for_foreignkey(
63
63
  self, db_field: ForeignKey, request: HttpRequest, **kwargs
64
- ) -> Optional[ModelChoiceField]:
64
+ ) -> ModelChoiceField | None:
65
65
  db = kwargs.get("using")
66
66
 
67
67
  # Overrides widgets for all related fields
@@ -102,7 +102,7 @@ class BaseModelAdminMixin:
102
102
 
103
103
  def formfield_for_nullboolean_field(
104
104
  self, db_field: Field, request: HttpRequest, **kwargs
105
- ) -> Optional[Field]:
105
+ ) -> Field | None:
106
106
  if "widget" not in kwargs:
107
107
  if db_field.choices:
108
108
  kwargs["widget"] = widgets.UnfoldAdminSelectWidget(
@@ -115,7 +115,7 @@ class BaseModelAdminMixin:
115
115
 
116
116
  def formfield_for_dbfield(
117
117
  self, db_field: Field, request: HttpRequest, **kwargs
118
- ) -> Optional[Field]:
118
+ ) -> Field | None:
119
119
  if isinstance(db_field, models.BooleanField) and db_field.null is True:
120
120
  return self.formfield_for_nullboolean_field(db_field, request, **kwargs)
121
121
 
unfold/sites.py CHANGED
@@ -1,7 +1,8 @@
1
1
  import copy
2
2
  import time
3
+ from collections.abc import Callable
3
4
  from http import HTTPStatus
4
- from typing import Any, Callable, Optional, Union
5
+ from typing import Any
5
6
  from urllib.parse import parse_qs, urlparse
6
7
 
7
8
  from django.contrib.admin import AdminSite
@@ -141,7 +142,7 @@ class UnfoldAdminSite(AdminSite):
141
142
  return context
142
143
 
143
144
  def index(
144
- self, request: HttpRequest, extra_context: Optional[dict[str, Any]] = None
145
+ self, request: HttpRequest, extra_context: dict[str, Any] | None = None
145
146
  ) -> TemplateResponse:
146
147
  app_list = self.get_app_list(request)
147
148
 
@@ -166,7 +167,7 @@ class UnfoldAdminSite(AdminSite):
166
167
  )
167
168
 
168
169
  def toggle_sidebar(
169
- self, request: HttpRequest, extra_context: Optional[dict[str, Any]] = None
170
+ self, request: HttpRequest, extra_context: dict[str, Any] | None = None
170
171
  ) -> HttpResponse:
171
172
  if "toggle_sidebar" not in request.session:
172
173
  request.session["toggle_sidebar"] = True
@@ -214,14 +215,14 @@ class UnfoldAdminSite(AdminSite):
214
215
  request: HttpRequest,
215
216
  app_list: list[dict[str, Any]],
216
217
  search_term: str,
217
- allowed_models: Optional[list[str]] = None,
218
+ allowed_models: list[str] | None = None,
218
219
  ) -> list[SearchResult]:
219
220
  results = []
220
221
 
221
222
  for app in app_list:
222
223
  for model in app["models"]:
223
224
  # Skip models which are not allowed
224
- if isinstance(allowed_models, (list, tuple)):
225
+ if isinstance(allowed_models, list | tuple):
225
226
  if model["model"]._meta.label.lower() not in [
226
227
  m.lower() for m in allowed_models
227
228
  ]:
@@ -263,7 +264,7 @@ class UnfoldAdminSite(AdminSite):
263
264
  return results
264
265
 
265
266
  def search(
266
- self, request: HttpRequest, extra_context: Optional[dict[str, Any]] = None
267
+ self, request: HttpRequest, extra_context: dict[str, Any] | None = None
267
268
  ) -> TemplateResponse:
268
269
  start_time = time.time()
269
270
 
@@ -302,10 +303,10 @@ class UnfoldAdminSite(AdminSite):
302
303
  self._get_config("COMMAND", request).get("search_models"), request
303
304
  )
304
305
 
305
- if search_models is True or isinstance(search_models, (list, tuple)):
306
+ if search_models is True or isinstance(search_models, list | tuple):
306
307
  allowed_models = (
307
308
  search_models
308
- if isinstance(search_models, (list, tuple))
309
+ if isinstance(search_models, list | tuple)
309
310
  else None
310
311
  )
311
312
 
@@ -340,7 +341,7 @@ class UnfoldAdminSite(AdminSite):
340
341
  )
341
342
 
342
343
  def password_change(
343
- self, request: HttpRequest, extra_context: Optional[dict[str, Any]] = None
344
+ self, request: HttpRequest, extra_context: dict[str, Any] | None = None
344
345
  ) -> HttpResponse:
345
346
  from django.contrib.auth.views import PasswordChangeView
346
347
 
@@ -462,7 +463,7 @@ class UnfoldAdminSite(AdminSite):
462
463
  return tabs
463
464
 
464
465
  def _call_permission_callback(
465
- self, callback: Union[str, Callable, None], request: HttpRequest
466
+ self, callback: str | Callable | None, request: HttpRequest
466
467
  ) -> bool:
467
468
  if callback is None:
468
469
  return True
@@ -490,7 +491,7 @@ class UnfoldAdminSite(AdminSite):
490
491
  return target
491
492
 
492
493
  def _get_is_active(
493
- self, request: HttpRequest, link: Union[str, Callable], is_tab: bool = False
494
+ self, request: HttpRequest, link: str | Callable, is_tab: bool = False
494
495
  ) -> bool:
495
496
  if not isinstance(link, str):
496
497
  link = str(link)
@@ -545,9 +546,7 @@ class UnfoldAdminSite(AdminSite):
545
546
  if key in config and config[key]:
546
547
  return self._get_value(config[key], *args)
547
548
 
548
- def _get_theme_images(
549
- self, key: str, *args: Any
550
- ) -> Union[dict[str, str], str, None]:
549
+ def _get_theme_images(self, key: str, *args: Any) -> dict[str, str] | str | None:
551
550
  images = self._get_config(key, *args)
552
551
 
553
552
  if isinstance(images, dict):
@@ -613,9 +612,7 @@ class UnfoldAdminSite(AdminSite):
613
612
  for item in items
614
613
  ]
615
614
 
616
- def _get_value(
617
- self, value: Union[str, Callable, lazy, None], *args: Any
618
- ) -> Optional[str]:
615
+ def _get_value(self, value: str | Callable | None, *args: Any) -> str | None:
619
616
  if value is None:
620
617
  return None
621
618