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.
- {django_unfold-0.66.0.dist-info → django_unfold-0.68.0.dist-info}/METADATA +8 -5
- {django_unfold-0.66.0.dist-info → django_unfold-0.68.0.dist-info}/RECORD +46 -42
- unfold/admin.py +73 -13
- unfold/components.py +2 -2
- unfold/contrib/filters/admin/choice_filters.py +13 -1
- unfold/contrib/filters/admin/mixins.py +3 -3
- unfold/contrib/filters/admin/numeric_filters.py +8 -6
- unfold/contrib/filters/forms.py +25 -4
- unfold/contrib/filters/static/unfold/filters/js/admin-numeric-filter.js +62 -28
- unfold/contrib/filters/templates/unfold/filters/filters_numeric_slider.html +2 -11
- unfold/contrib/forms/widgets.py +5 -5
- unfold/contrib/inlines/admin.py +3 -3
- unfold/contrib/inlines/forms.py +5 -4
- unfold/dataclasses.py +13 -13
- unfold/datasets.py +69 -0
- unfold/decorators.py +19 -19
- unfold/fields.py +40 -1
- unfold/forms.py +19 -7
- unfold/mixins/action_model_admin.py +11 -10
- unfold/mixins/base_model_admin.py +6 -6
- unfold/sites.py +14 -17
- unfold/static/unfold/css/styles.css +1 -1
- unfold/static/unfold/js/app.js +65 -5
- unfold/static/unfold/js/select2.init.js +2 -9
- unfold/styles.css +22 -21
- unfold/templates/admin/change_form.html +5 -1
- unfold/templates/admin/change_list_results.html +10 -62
- unfold/templates/admin/edit_inline/stacked.html +1 -1
- unfold/templates/admin/search_form.html +5 -3
- unfold/templates/unfold/components/card.html +12 -3
- unfold/templates/unfold/components/progress.html +9 -3
- unfold/templates/unfold/helpers/change_list_headers.html +65 -0
- unfold/templates/unfold/helpers/dataset.html +19 -0
- unfold/templates/unfold/helpers/edit_inline/tabular_field.html +1 -1
- unfold/templates/unfold/helpers/empty_results.html +6 -4
- unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
- unfold/templates/unfold/helpers/field_readonly_value_file.html +18 -0
- unfold/templates/unfold/helpers/tab_items.html +6 -0
- unfold/templatetags/unfold.py +18 -13
- unfold/templatetags/unfold_list.py +64 -8
- unfold/typing.py +5 -6
- unfold/utils.py +9 -9
- unfold/views.py +15 -1
- unfold/widgets.py +30 -29
- {django_unfold-0.66.0.dist-info → django_unfold-0.68.0.dist-info}/WHEEL +0 -0
- {django_unfold-0.66.0.dist-info → django_unfold-0.68.0.dist-info}/licenses/LICENSE.md +0 -0
unfold/templatetags/unfold.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import json
|
2
2
|
from collections.abc import Iterable, Mapping
|
3
|
-
from typing import Any
|
3
|
+
from typing import Any
|
4
4
|
|
5
5
|
from django import template
|
6
6
|
from django.contrib.admin.helpers import AdminForm, Fieldset
|
@@ -27,7 +27,7 @@ register = Library()
|
|
27
27
|
|
28
28
|
|
29
29
|
def _get_tabs_list(
|
30
|
-
context: RequestContext, page: str, opts:
|
30
|
+
context: RequestContext, page: str, opts: Options | None = None
|
31
31
|
) -> list:
|
32
32
|
tabs_list = []
|
33
33
|
page_id = None
|
@@ -63,9 +63,9 @@ def _get_tabs_list(
|
|
63
63
|
|
64
64
|
|
65
65
|
@register.simple_tag(name="tab_list", takes_context=True)
|
66
|
-
def tab_list(context: RequestContext, page: str, opts:
|
66
|
+
def tab_list(context: RequestContext, page: str, opts: Options | None = None) -> str:
|
67
67
|
inlines_list = []
|
68
|
-
|
68
|
+
datasets_list = []
|
69
69
|
data = {
|
70
70
|
"nav_global": context.get("nav_global"),
|
71
71
|
"actions_detail": context.get("actions_detail"),
|
@@ -85,6 +85,13 @@ def tab_list(context: RequestContext, page: str, opts: Optional[Options] = None)
|
|
85
85
|
if len(inlines_list) > 0:
|
86
86
|
data["inlines_list"] = inlines_list
|
87
87
|
|
88
|
+
for dataset in context.get("datasets", []):
|
89
|
+
if dataset and hasattr(dataset, "tab"):
|
90
|
+
datasets_list.append(dataset)
|
91
|
+
|
92
|
+
if len(datasets_list) > 0:
|
93
|
+
data["datasets_list"] = datasets_list
|
94
|
+
|
88
95
|
return render_to_string(
|
89
96
|
"unfold/helpers/tab_list.html",
|
90
97
|
request=context["request"],
|
@@ -150,7 +157,7 @@ class CaptureNode(Node):
|
|
150
157
|
self.varname = varname
|
151
158
|
self.silent = silent
|
152
159
|
|
153
|
-
def render(self, context: dict[str, Any]) ->
|
160
|
+
def render(self, context: dict[str, Any]) -> str | SafeText:
|
154
161
|
output = self.nodelist.render(context)
|
155
162
|
context[self.varname] = output
|
156
163
|
if self.silent:
|
@@ -219,7 +226,7 @@ class RenderComponentNode(template.Node):
|
|
219
226
|
self,
|
220
227
|
template_name: str,
|
221
228
|
nodelist: NodeList,
|
222
|
-
extra_context:
|
229
|
+
extra_context: dict | None = None,
|
223
230
|
include_context: bool = False,
|
224
231
|
*args,
|
225
232
|
**kwargs,
|
@@ -308,7 +315,7 @@ def do_component(parser: Parser, token: Token) -> str:
|
|
308
315
|
|
309
316
|
|
310
317
|
@register.filter
|
311
|
-
def add_css_class(field: Field, classes:
|
318
|
+
def add_css_class(field: Field, classes: list | tuple) -> Field:
|
312
319
|
if type(classes) in (list, tuple):
|
313
320
|
classes = " ".join(classes)
|
314
321
|
|
@@ -329,8 +336,8 @@ def preserve_changelist_filters(context: Context) -> dict[str, dict[str, str]]:
|
|
329
336
|
"""
|
330
337
|
Generate hidden input fields to preserve filters for POST forms.
|
331
338
|
"""
|
332
|
-
request:
|
333
|
-
changelist:
|
339
|
+
request: HttpRequest | None = context.get("request")
|
340
|
+
changelist: ChangeList | None = context.get("cl")
|
334
341
|
|
335
342
|
if not request or not changelist:
|
336
343
|
return {"params": {}}
|
@@ -348,7 +355,7 @@ def preserve_changelist_filters(context: Context) -> dict[str, dict[str, str]]:
|
|
348
355
|
@register.simple_tag(takes_context=True)
|
349
356
|
def element_classes(context: Context, key: str) -> str:
|
350
357
|
if key in context.get("element_classes", {}):
|
351
|
-
if isinstance(context["element_classes"][key],
|
358
|
+
if isinstance(context["element_classes"][key], list | tuple):
|
352
359
|
return " ".join(context["element_classes"][key])
|
353
360
|
|
354
361
|
return context["element_classes"][key]
|
@@ -585,9 +592,7 @@ def infinite_paginator_url(cl, i):
|
|
585
592
|
|
586
593
|
|
587
594
|
@register.simple_tag
|
588
|
-
def elided_page_range(
|
589
|
-
paginator: Paginator, number: int
|
590
|
-
) -> Optional[list[Union[int, str]]]:
|
595
|
+
def elided_page_range(paginator: Paginator, number: int) -> list[int | str] | None:
|
591
596
|
if not paginator or not number:
|
592
597
|
return None
|
593
598
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import datetime
|
2
2
|
from collections.abc import Generator
|
3
|
-
from typing import Any
|
3
|
+
from typing import Any
|
4
4
|
|
5
5
|
from django.contrib.admin.templatetags.admin_list import (
|
6
6
|
ResultList,
|
@@ -11,8 +11,10 @@ from django.contrib.admin.templatetags.admin_urls import add_preserved_filters
|
|
11
11
|
from django.contrib.admin.templatetags.base import InclusionAdminNode
|
12
12
|
from django.contrib.admin.utils import label_for_field, lookup_field
|
13
13
|
from django.contrib.admin.views.main import (
|
14
|
+
IS_POPUP_VAR,
|
14
15
|
ORDER_VAR,
|
15
16
|
PAGE_VAR,
|
17
|
+
SEARCH_VAR,
|
16
18
|
ChangeList,
|
17
19
|
)
|
18
20
|
from django.core.exceptions import ObjectDoesNotExist
|
@@ -34,8 +36,15 @@ from unfold.utils import (
|
|
34
36
|
display_for_label,
|
35
37
|
display_for_value,
|
36
38
|
)
|
39
|
+
from unfold.views import DatasetChangeList
|
37
40
|
from unfold.widgets import UnfoldBooleanWidget
|
38
41
|
|
42
|
+
try:
|
43
|
+
from django.contrib.admin.views.main import IS_FACETS_VAR
|
44
|
+
except ImportError:
|
45
|
+
# TODO: remove once django 4.x is not supported
|
46
|
+
IS_FACETS_VAR = None
|
47
|
+
|
39
48
|
register = Library()
|
40
49
|
|
41
50
|
LINK_CLASSES = [
|
@@ -99,6 +108,9 @@ def result_headers(cl):
|
|
99
108
|
Generate the list column headers.
|
100
109
|
"""
|
101
110
|
ordering_field_columns = cl.get_ordering_field_columns()
|
111
|
+
ordering_field = getattr(cl.model_admin, "ordering_field", None)
|
112
|
+
hide_ordering_field = getattr(cl.model_admin, "hide_ordering_field", False)
|
113
|
+
|
102
114
|
for i, field_name in enumerate(cl.list_display):
|
103
115
|
text, attr = label_for_field(
|
104
116
|
field_name, cl.model, model_admin=cl.model_admin, return_attr=True
|
@@ -145,6 +157,10 @@ def result_headers(cl):
|
|
145
157
|
order_type = ""
|
146
158
|
new_order_type = "asc"
|
147
159
|
sort_priority = 0
|
160
|
+
|
161
|
+
if ordering_field and field_name == ordering_field and hide_ordering_field:
|
162
|
+
th_classes.append("!hidden")
|
163
|
+
|
148
164
|
# Is it currently being sorted on?
|
149
165
|
is_sorted = i in ordering_field_columns
|
150
166
|
if is_sorted:
|
@@ -209,6 +225,9 @@ def items_for_result(
|
|
209
225
|
|
210
226
|
for field_index, field_name in enumerate(cl.list_display):
|
211
227
|
empty_value_display = cl.model_admin.get_empty_value_display()
|
228
|
+
ordering_field = getattr(cl.model_admin, "ordering_field", None)
|
229
|
+
hide_ordering_field = getattr(cl.model_admin, "hide_ordering_field", False)
|
230
|
+
|
212
231
|
row_classes = [
|
213
232
|
f"field-{_coerce_field_name(field_name, field_index)}",
|
214
233
|
*ROW_CLASSES,
|
@@ -241,7 +260,7 @@ def items_for_result(
|
|
241
260
|
else:
|
242
261
|
result_repr = display_for_value(value, empty_value_display, boolean)
|
243
262
|
|
244
|
-
if isinstance(value,
|
263
|
+
if isinstance(value, datetime.date | datetime.time):
|
245
264
|
row_classes.append("nowrap")
|
246
265
|
else:
|
247
266
|
if isinstance(f.remote_field, models.ManyToOneRel):
|
@@ -253,7 +272,7 @@ def items_for_result(
|
|
253
272
|
else:
|
254
273
|
result_repr = display_for_field(value, f, empty_value_display)
|
255
274
|
if isinstance(
|
256
|
-
f,
|
275
|
+
f, models.DateField | models.TimeField | models.ForeignKey
|
257
276
|
):
|
258
277
|
row_classes.append("nowrap")
|
259
278
|
|
@@ -321,6 +340,9 @@ def items_for_result(
|
|
321
340
|
if bf.errors:
|
322
341
|
row_classes += ["group", "errors"]
|
323
342
|
|
343
|
+
if ordering_field and field_name == ordering_field and hide_ordering_field:
|
344
|
+
row_classes.append("!hidden")
|
345
|
+
|
324
346
|
row_class = mark_safe(f' class="{" ".join(row_classes)}"')
|
325
347
|
|
326
348
|
if field_index != 0:
|
@@ -346,7 +368,7 @@ class UnfoldResultList(ResultList):
|
|
346
368
|
def __init__(
|
347
369
|
self,
|
348
370
|
instance: Model,
|
349
|
-
form:
|
371
|
+
form: Form | None,
|
350
372
|
*items: Any,
|
351
373
|
) -> None:
|
352
374
|
self.instance = instance
|
@@ -395,23 +417,57 @@ def result_list_tag(parser: Parser, token: Token) -> InclusionAdminNode:
|
|
395
417
|
|
396
418
|
|
397
419
|
@register.simple_tag
|
398
|
-
def paginator_number(cl: ChangeList, i:
|
420
|
+
def paginator_number(cl: ChangeList, i: str | int) -> str | SafeText:
|
399
421
|
"""
|
400
422
|
Generate an individual page index link in a paginated list.
|
401
423
|
"""
|
402
424
|
if i == cl.paginator.ELLIPSIS:
|
403
425
|
return render_to_string(
|
404
426
|
"unfold/helpers/pagination_ellipsis.html",
|
405
|
-
{
|
427
|
+
{
|
428
|
+
"ellipsis": cl.paginator.ELLIPSIS,
|
429
|
+
},
|
406
430
|
)
|
407
431
|
elif i == cl.page_num:
|
408
432
|
return render_to_string(
|
409
433
|
"unfold/helpers/pagination_current_item.html", {"number": i}
|
410
434
|
)
|
411
435
|
else:
|
436
|
+
page_param = PAGE_VAR
|
437
|
+
|
438
|
+
if isinstance(cl, DatasetChangeList):
|
439
|
+
page_param = f"{cl.model._meta.model_name}-p"
|
440
|
+
|
412
441
|
return format_html(
|
413
|
-
'<a href="{}"{}>{}</a> ',
|
414
|
-
cl.get_query_string(
|
442
|
+
'<a href="{}"{} x-data x-on:click.prevent="window.location.href = $el.href + window.location.hash">{}</a> ',
|
443
|
+
cl.get_query_string(
|
444
|
+
{
|
445
|
+
page_param: i,
|
446
|
+
}
|
447
|
+
),
|
415
448
|
mark_safe(' class="end"' if i == cl.paginator.num_pages else ""),
|
416
449
|
i,
|
417
450
|
)
|
451
|
+
|
452
|
+
|
453
|
+
def unfold_search_form(cl):
|
454
|
+
model_name = cl.model_admin.model._meta.model_name
|
455
|
+
|
456
|
+
return {
|
457
|
+
"cl": cl,
|
458
|
+
"show_result_count": cl.result_count != cl.full_result_count,
|
459
|
+
"search_var": f"{model_name}-{SEARCH_VAR}",
|
460
|
+
"is_popup_var": IS_POPUP_VAR,
|
461
|
+
"is_facets_var": IS_FACETS_VAR,
|
462
|
+
}
|
463
|
+
|
464
|
+
|
465
|
+
@register.tag(name="unfold_search_form")
|
466
|
+
def unfold_search_form_tag(parser, token):
|
467
|
+
return InclusionAdminNode(
|
468
|
+
parser,
|
469
|
+
token,
|
470
|
+
func=unfold_search_form,
|
471
|
+
template_name="search_form.html",
|
472
|
+
takes_context=False,
|
473
|
+
)
|
unfold/typing.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from collections.abc import Iterable
|
2
|
-
from typing import Any,
|
2
|
+
from typing import Any, Protocol
|
3
3
|
|
4
4
|
|
5
5
|
class ActionFunction(Protocol):
|
@@ -13,13 +13,12 @@ class ActionFunction(Protocol):
|
|
13
13
|
short_description: str
|
14
14
|
url_path: str
|
15
15
|
attrs: dict[str, Any]
|
16
|
-
icon:
|
16
|
+
icon: str | None = None
|
17
17
|
|
18
18
|
def __call__(self, *args, **kwargs):
|
19
19
|
pass
|
20
20
|
|
21
21
|
|
22
|
-
FieldsetsType =
|
23
|
-
list[tuple[
|
24
|
-
|
25
|
-
]
|
22
|
+
FieldsetsType = (
|
23
|
+
list[tuple[str | None, dict[str, Any]]] | tuple[tuple[str | None, dict[str, Any]]]
|
24
|
+
)
|
unfold/utils.py
CHANGED
@@ -2,7 +2,7 @@ import datetime
|
|
2
2
|
import decimal
|
3
3
|
import json
|
4
4
|
from collections.abc import Iterable
|
5
|
-
from typing import Any
|
5
|
+
from typing import Any
|
6
6
|
|
7
7
|
from django.conf import settings
|
8
8
|
from django.db import models
|
@@ -94,13 +94,13 @@ def display_for_value(
|
|
94
94
|
return str(value)
|
95
95
|
elif isinstance(value, datetime.datetime):
|
96
96
|
return formats.localize(timezone.template_localtime(value))
|
97
|
-
elif isinstance(value,
|
97
|
+
elif isinstance(value, datetime.date | datetime.time):
|
98
98
|
return formats.localize(value)
|
99
99
|
elif Money is not None and isinstance(value, Money):
|
100
100
|
return str(value)
|
101
|
-
elif isinstance(value,
|
101
|
+
elif isinstance(value, int | decimal.Decimal | float):
|
102
102
|
return formats.number_format(value)
|
103
|
-
elif isinstance(value,
|
103
|
+
elif isinstance(value, list | tuple):
|
104
104
|
return ", ".join(str(v) for v in value)
|
105
105
|
else:
|
106
106
|
return str(value)
|
@@ -121,13 +121,13 @@ def display_for_field(value: Any, field: Any, empty_value_display: str) -> str:
|
|
121
121
|
return empty_value_display
|
122
122
|
elif isinstance(field, models.DateTimeField):
|
123
123
|
return formats.localize(timezone.template_localtime(value))
|
124
|
-
elif isinstance(field,
|
124
|
+
elif isinstance(field, models.DateField | models.TimeField):
|
125
125
|
return formats.localize(value)
|
126
126
|
elif MoneyField is not None and isinstance(field, MoneyField):
|
127
127
|
return str(value)
|
128
128
|
elif isinstance(field, models.DecimalField):
|
129
129
|
return formats.number_format(value, field.decimal_places)
|
130
|
-
elif isinstance(field,
|
130
|
+
elif isinstance(field, models.IntegerField | models.FloatField):
|
131
131
|
return formats.number_format(value)
|
132
132
|
elif isinstance(field, models.FileField) and value:
|
133
133
|
return format_html('<a href="{}">{}</a>', value.url, value)
|
@@ -140,7 +140,7 @@ def display_for_field(value: Any, field: Any, empty_value_display: str) -> str:
|
|
140
140
|
return display_for_value(value, empty_value_display)
|
141
141
|
|
142
142
|
|
143
|
-
def prettify_json(data: Any, encoder: Any) ->
|
143
|
+
def prettify_json(data: Any, encoder: Any) -> str | None:
|
144
144
|
try:
|
145
145
|
from pygments import highlight
|
146
146
|
from pygments.formatters import HtmlFormatter
|
@@ -165,7 +165,7 @@ def prettify_json(data: Any, encoder: Any) -> Optional[str]:
|
|
165
165
|
)
|
166
166
|
|
167
167
|
|
168
|
-
def parse_date_str(value: str) ->
|
168
|
+
def parse_date_str(value: str) -> datetime.date | None:
|
169
169
|
for format in settings.DATE_INPUT_FORMATS:
|
170
170
|
try:
|
171
171
|
return datetime.datetime.strptime(value, format).date()
|
@@ -173,7 +173,7 @@ def parse_date_str(value: str) -> Optional[datetime.date]:
|
|
173
173
|
continue
|
174
174
|
|
175
175
|
|
176
|
-
def parse_datetime_str(value: str) ->
|
176
|
+
def parse_datetime_str(value: str) -> datetime.datetime | None:
|
177
177
|
for format in settings.DATETIME_INPUT_FORMATS:
|
178
178
|
try:
|
179
179
|
return datetime.datetime.strptime(value, format)
|
unfold/views.py
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
from typing import Any
|
2
2
|
|
3
3
|
import django
|
4
|
+
from django.contrib.admin.views import main
|
4
5
|
from django.contrib.admin.views.main import ERROR_FLAG, PAGE_VAR
|
5
6
|
from django.contrib.admin.views.main import ChangeList as BaseChangeList
|
6
7
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
8
|
+
from django.http import HttpRequest
|
7
9
|
|
8
10
|
from unfold.exceptions import UnfoldException
|
11
|
+
from unfold.forms import DatasetChangeListSearchForm
|
9
12
|
|
10
13
|
|
11
14
|
class ChangeList(BaseChangeList):
|
12
|
-
def __init__(self, request, *args, **kwargs):
|
15
|
+
def __init__(self, request: HttpRequest, *args: Any, **kwargs: Any) -> None:
|
13
16
|
super().__init__(request, *args, **kwargs)
|
14
17
|
|
15
18
|
if django.VERSION < (5, 0):
|
@@ -18,6 +21,17 @@ class ChangeList(BaseChangeList):
|
|
18
21
|
self.filter_params.pop(ERROR_FLAG, None)
|
19
22
|
|
20
23
|
|
24
|
+
class DatasetChangeList(ChangeList):
|
25
|
+
is_dataset = True
|
26
|
+
search_form_class = DatasetChangeListSearchForm
|
27
|
+
|
28
|
+
def __init__(self, request: HttpRequest, *args: Any, **kwargs: Any) -> None:
|
29
|
+
# Monkeypatch SEARCH_VAR and PAGE_VAR for custom datasets
|
30
|
+
main.SEARCH_VAR = f"{kwargs.get('model')._meta.model_name}-q"
|
31
|
+
main.PAGE_VAR = f"{kwargs.get('model')._meta.model_name}-p"
|
32
|
+
super().__init__(request, *args, **kwargs)
|
33
|
+
|
34
|
+
|
21
35
|
class UnfoldModelAdminViewMixin(PermissionRequiredMixin):
|
22
36
|
"""
|
23
37
|
Prepares views to be displayed in admin
|
unfold/widgets.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
from
|
1
|
+
from collections.abc import Callable
|
2
|
+
from typing import Any
|
2
3
|
|
3
4
|
from django.contrib.admin.options import VERTICAL
|
4
5
|
from django.contrib.admin.sites import AdminSite
|
@@ -337,7 +338,7 @@ class UnfoldPrefixSuffixMixin:
|
|
337
338
|
class UnfoldAdminTextInputWidget(UnfoldPrefixSuffixMixin, AdminTextInputWidget):
|
338
339
|
template_name = "unfold/widgets/text.html"
|
339
340
|
|
340
|
-
def __init__(self, attrs:
|
341
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
341
342
|
super().__init__(
|
342
343
|
attrs={
|
343
344
|
**(attrs or {}),
|
@@ -351,7 +352,7 @@ class UnfoldAdminTextInputWidget(UnfoldPrefixSuffixMixin, AdminTextInputWidget):
|
|
351
352
|
class UnfoldAdminURLInputWidget(AdminURLFieldWidget):
|
352
353
|
template_name = "unfold/widgets/url.html"
|
353
354
|
|
354
|
-
def __init__(self, attrs:
|
355
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
355
356
|
super().__init__(
|
356
357
|
attrs={
|
357
358
|
**(attrs or {}),
|
@@ -363,7 +364,7 @@ class UnfoldAdminURLInputWidget(AdminURLFieldWidget):
|
|
363
364
|
|
364
365
|
|
365
366
|
class UnfoldAdminColorInputWidget(AdminTextInputWidget):
|
366
|
-
def __init__(self, attrs:
|
367
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
367
368
|
super().__init__(
|
368
369
|
attrs={
|
369
370
|
**(attrs or {}),
|
@@ -376,7 +377,7 @@ class UnfoldAdminColorInputWidget(AdminTextInputWidget):
|
|
376
377
|
|
377
378
|
|
378
379
|
class UnfoldAdminUUIDInputWidget(AdminUUIDInputWidget):
|
379
|
-
def __init__(self, attrs:
|
380
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
380
381
|
super().__init__(
|
381
382
|
attrs={
|
382
383
|
**(attrs or {}),
|
@@ -390,7 +391,7 @@ class UnfoldAdminUUIDInputWidget(AdminUUIDInputWidget):
|
|
390
391
|
class UnfoldAdminIntegerRangeWidget(MultiWidget):
|
391
392
|
template_name = "unfold/widgets/range.html"
|
392
393
|
|
393
|
-
def __init__(self, attrs:
|
394
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
394
395
|
if attrs is None:
|
395
396
|
attrs = {}
|
396
397
|
|
@@ -402,14 +403,14 @@ class UnfoldAdminIntegerRangeWidget(MultiWidget):
|
|
402
403
|
|
403
404
|
super().__init__(_widgets, attrs)
|
404
405
|
|
405
|
-
def decompress(self, value:
|
406
|
+
def decompress(self, value: str | None) -> tuple[Callable | None, ...]:
|
406
407
|
if value:
|
407
408
|
return value.lower, value.upper
|
408
409
|
return None, None
|
409
410
|
|
410
411
|
|
411
412
|
class UnfoldAdminEmailInputWidget(AdminEmailInputWidget):
|
412
|
-
def __init__(self, attrs:
|
413
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
413
414
|
super().__init__(
|
414
415
|
attrs={
|
415
416
|
**(attrs or {}),
|
@@ -459,7 +460,7 @@ class UnfoldAdminDateWidget(AdminDateWidget):
|
|
459
460
|
template_name = "unfold/widgets/date.html"
|
460
461
|
|
461
462
|
def __init__(
|
462
|
-
self, attrs:
|
463
|
+
self, attrs: dict[str, Any] | None = None, format: str | None = None
|
463
464
|
) -> None:
|
464
465
|
attrs = {
|
465
466
|
**(attrs or {}),
|
@@ -486,7 +487,7 @@ class UnfoldAdminSingleDateWidget(AdminDateWidget):
|
|
486
487
|
template_name = "unfold/widgets/date.html"
|
487
488
|
|
488
489
|
def __init__(
|
489
|
-
self, attrs:
|
490
|
+
self, attrs: dict[str, Any] | None = None, format: str | None = None
|
490
491
|
) -> None:
|
491
492
|
attrs = {
|
492
493
|
**(attrs or {}),
|
@@ -506,7 +507,7 @@ class UnfoldAdminTimeWidget(AdminTimeWidget):
|
|
506
507
|
template_name = "unfold/widgets/time.html"
|
507
508
|
|
508
509
|
def __init__(
|
509
|
-
self, attrs:
|
510
|
+
self, attrs: dict[str, Any] | None = None, format: str | None = None
|
510
511
|
) -> None:
|
511
512
|
attrs = {
|
512
513
|
**(attrs or {}),
|
@@ -533,7 +534,7 @@ class UnfoldAdminSingleTimeWidget(AdminTimeWidget):
|
|
533
534
|
template_name = "unfold/widgets/time.html"
|
534
535
|
|
535
536
|
def __init__(
|
536
|
-
self, attrs:
|
537
|
+
self, attrs: dict[str, Any] | None = None, format: str | None = None
|
537
538
|
) -> None:
|
538
539
|
attrs = {
|
539
540
|
**(attrs or {}),
|
@@ -552,7 +553,7 @@ class UnfoldAdminSingleTimeWidget(AdminTimeWidget):
|
|
552
553
|
class UnfoldAdminTextareaWidget(AdminTextareaWidget):
|
553
554
|
template_name = "unfold/widgets/textarea.html"
|
554
555
|
|
555
|
-
def __init__(self, attrs:
|
556
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
556
557
|
attrs = attrs or {}
|
557
558
|
|
558
559
|
super().__init__(
|
@@ -570,7 +571,7 @@ class UnfoldAdminTextareaWidget(AdminTextareaWidget):
|
|
570
571
|
|
571
572
|
|
572
573
|
class UnfoldAdminExpandableTextareaWidget(UnfoldAdminTextareaWidget):
|
573
|
-
def __init__(self, attrs:
|
574
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
574
575
|
attrs = attrs or {}
|
575
576
|
|
576
577
|
attrs.update({"rows": 2})
|
@@ -593,7 +594,7 @@ class UnfoldAdminExpandableTextareaWidget(UnfoldAdminTextareaWidget):
|
|
593
594
|
class UnfoldAdminSplitDateTimeWidget(AdminSplitDateTime):
|
594
595
|
template_name = "unfold/widgets/split_datetime.html"
|
595
596
|
|
596
|
-
def __init__(self, attrs:
|
597
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
597
598
|
widgets = [
|
598
599
|
UnfoldAdminDateWidget(attrs={"placeholder": _("Date")}),
|
599
600
|
UnfoldAdminTimeWidget(attrs={"placeholder": _("Time")}),
|
@@ -613,11 +614,11 @@ class UnfoldAdminSplitDateTimeVerticalWidget(AdminSplitDateTime):
|
|
613
614
|
|
614
615
|
def __init__(
|
615
616
|
self,
|
616
|
-
attrs:
|
617
|
-
date_attrs:
|
618
|
-
time_attrs:
|
619
|
-
date_label:
|
620
|
-
time_label:
|
617
|
+
attrs: dict[str, Any] | None = None,
|
618
|
+
date_attrs: dict[str, Any] | None = None,
|
619
|
+
time_attrs: dict[str, Any] | None = None,
|
620
|
+
date_label: str | None = None,
|
621
|
+
time_label: str | None = None,
|
621
622
|
) -> None:
|
622
623
|
self.date_label = date_label
|
623
624
|
self.time_label = time_label
|
@@ -629,7 +630,7 @@ class UnfoldAdminSplitDateTimeVerticalWidget(AdminSplitDateTime):
|
|
629
630
|
MultiWidget.__init__(self, widgets, attrs)
|
630
631
|
|
631
632
|
def get_context(
|
632
|
-
self, name: str, value: Any, attrs:
|
633
|
+
self, name: str, value: Any, attrs: dict[str, Any] | None
|
633
634
|
) -> dict[str, Any]:
|
634
635
|
context = super().get_context(name, value, attrs)
|
635
636
|
|
@@ -647,7 +648,7 @@ class UnfoldAdminSplitDateTimeVerticalWidget(AdminSplitDateTime):
|
|
647
648
|
|
648
649
|
|
649
650
|
class UnfoldAdminIntegerFieldWidget(AdminIntegerFieldWidget):
|
650
|
-
def __init__(self, attrs:
|
651
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
651
652
|
super().__init__(
|
652
653
|
attrs={
|
653
654
|
**(attrs or {}),
|
@@ -659,7 +660,7 @@ class UnfoldAdminIntegerFieldWidget(AdminIntegerFieldWidget):
|
|
659
660
|
|
660
661
|
|
661
662
|
class UnfoldAdminDecimalFieldWidget(AdminIntegerFieldWidget):
|
662
|
-
def __init__(self, attrs:
|
663
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
663
664
|
super().__init__(
|
664
665
|
attrs={
|
665
666
|
**(attrs or {}),
|
@@ -671,7 +672,7 @@ class UnfoldAdminDecimalFieldWidget(AdminIntegerFieldWidget):
|
|
671
672
|
|
672
673
|
|
673
674
|
class UnfoldAdminBigIntegerFieldWidget(AdminBigIntegerFieldWidget):
|
674
|
-
def __init__(self, attrs:
|
675
|
+
def __init__(self, attrs: dict[str, Any] | None = None) -> None:
|
675
676
|
super().__init__(
|
676
677
|
attrs={
|
677
678
|
**(attrs or {}),
|
@@ -773,7 +774,7 @@ class UnfoldAdminRadioSelectWidget(AdminRadioSelect):
|
|
773
774
|
template_name = "unfold/widgets/radio.html"
|
774
775
|
option_template_name = "unfold/widgets/radio_option.html"
|
775
776
|
|
776
|
-
def __init__(self, radio_style:
|
777
|
+
def __init__(self, radio_style: int | None = None, *args, **kwargs):
|
777
778
|
super().__init__(*args, **kwargs)
|
778
779
|
|
779
780
|
if radio_style is None:
|
@@ -832,7 +833,7 @@ except ImportError:
|
|
832
833
|
|
833
834
|
class UnfoldBooleanWidget(CheckboxInput):
|
834
835
|
def __init__(
|
835
|
-
self, attrs:
|
836
|
+
self, attrs: dict[str, Any] | None = None, check_test: Callable = None
|
836
837
|
) -> None:
|
837
838
|
if attrs is None:
|
838
839
|
attrs = {}
|
@@ -850,7 +851,7 @@ class UnfoldBooleanWidget(CheckboxInput):
|
|
850
851
|
|
851
852
|
class UnfoldBooleanSwitchWidget(CheckboxInput):
|
852
853
|
def __init__(
|
853
|
-
self, attrs:
|
854
|
+
self, attrs: dict[str, Any] | None = None, check_test: Callable = None
|
854
855
|
) -> None:
|
855
856
|
super().__init__(
|
856
857
|
attrs={
|
@@ -874,8 +875,8 @@ class UnfoldForeignKeyRawIdWidget(ForeignKeyRawIdWidget):
|
|
874
875
|
self,
|
875
876
|
rel: ForeignObjectRel,
|
876
877
|
admin_site: AdminSite,
|
877
|
-
attrs:
|
878
|
-
using:
|
878
|
+
attrs: dict | None = None,
|
879
|
+
using: Any | None = None,
|
879
880
|
) -> None:
|
880
881
|
attrs = {
|
881
882
|
**(attrs or {}),
|
File without changes
|
File without changes
|