django-unfold 0.27.0__py3-none-any.whl → 0.28.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/METADATA +64 -9
- {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/RECORD +30 -27
- unfold/admin.py +1 -0
- unfold/contrib/forms/widgets.py +2 -0
- unfold/contrib/import_export/forms.py +21 -7
- unfold/contrib/import_export/templates/admin/import_export/change_list_export.html +5 -0
- unfold/contrib/import_export/templates/admin/import_export/export.html +1 -1
- unfold/contrib/simple_history/templates/simple_history/object_history.html +3 -5
- unfold/contrib/simple_history/templates/simple_history/{_object_history_list.html → object_history_list.html} +49 -11
- unfold/dataclasses.py +2 -0
- unfold/fields.py +9 -1
- unfold/static/unfold/css/styles.css +1 -1
- unfold/styles.css +1 -2
- unfold/templates/admin/login.html +4 -0
- unfold/templates/admin/submit_line.html +1 -1
- unfold/templates/unfold/helpers/attrs.html +1 -0
- unfold/templates/unfold/helpers/boolean.html +1 -1
- unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
- unfold/templates/unfold/helpers/fieldset_row.html +2 -2
- unfold/templates/unfold/helpers/navigation.html +1 -1
- unfold/templates/unfold/helpers/search_results.html +10 -10
- unfold/templates/unfold/layouts/base.html +11 -0
- unfold/templates/unfold/layouts/base_simple.html +7 -1
- unfold/templates/unfold/widgets/clearable_file_input_small.html +1 -1
- unfold/templates/unfold/widgets/split_datetime.html +7 -7
- unfold/utils.py +21 -1
- unfold/views.py +18 -6
- unfold/widgets.py +12 -1
- {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/LICENSE.md +0 -0
- {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: django-unfold
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.28.1
|
4
4
|
Summary: Modern Django admin theme for seamless interface development
|
5
5
|
Home-page: https://unfoldadmin.com
|
6
6
|
License: MIT
|
@@ -35,13 +35,13 @@ Description-Content-Type: text/markdown
|
|
35
35
|
|
36
36
|
Unfold is theme for Django admin incorporating most common practises for building full-fledged admin areas. It is designed to work at the top of default administration provided by Django.
|
37
37
|
|
38
|
-
- **Unfold:** demo site is available at [unfoldadmin.com](https://unfoldadmin.com)
|
38
|
+
- **Unfold:** demo site is available at [unfoldadmin.com](https://unfoldadmin.com?utm_medium=github&utm_source=unfold)
|
39
39
|
- **Formula:** repository with demo implementation at [github.com/unfoldadmin/formula](https://github.com/unfoldadmin/formula)
|
40
40
|
- **Turbo:** Django & Next.js boilerplate implementing Unfold at [github.com/unfoldadmin/turbo](https://github.com/unfoldadmin/turbo)
|
41
41
|
|
42
42
|
## Are you using Unfold and need a help?<!-- omit from toc -->
|
43
43
|
|
44
|
-
Did you decide to start using Unfold but you don't have time to make the switch from native Django admin? [Get in touch with us](https://unfoldadmin.com
|
44
|
+
Did you decide to start using Unfold but you don't have time to make the switch from native Django admin? [Get in touch with us](https://unfoldadmin.com/?utm_medium=github&utm_source=unfold) and let's supercharge development by using our know-how.
|
45
45
|
|
46
46
|
## Features <!-- omit from toc -->
|
47
47
|
|
@@ -62,7 +62,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
|
|
62
62
|
- **Third party packages:** default support for multiple popular applications
|
63
63
|
- **Environment label**: distinguish between environments by displaying a label
|
64
64
|
- **Nonrelated inlines**: displays nonrelated model as inline in changeform
|
65
|
-
- **Parallel admin**: support for default admin in parallel with Unfold. [Admin migration guide](https://unfoldadmin.com/blog/migrating-django-admin-unfold
|
65
|
+
- **Parallel admin**: support for default admin in parallel with Unfold. [Admin migration guide](https://unfoldadmin.com/blog/migrating-django-admin-unfold/?utm_medium=github&utm_source=unfold)
|
66
66
|
- **VS Code**: project configuration and development container is included
|
67
67
|
|
68
68
|
## Table of contents <!-- omit from toc -->
|
@@ -81,6 +81,7 @@ Did you decide to start using Unfold but you don't have time to make the switch
|
|
81
81
|
- [Dropdown filters](#dropdown-filters)
|
82
82
|
- [Numeric filters](#numeric-filters)
|
83
83
|
- [Date/time filters](#datetime-filters)
|
84
|
+
- [Custom admin pages](#custom-admin-pages)
|
84
85
|
- [Nonrelated inlines](#nonrelated-inlines)
|
85
86
|
- [Display decorator](#display-decorator)
|
86
87
|
- [Change form tabs](#change-form-tabs)
|
@@ -645,6 +646,45 @@ class YourModelAdmin(ModelAdmin):
|
|
645
646
|
)
|
646
647
|
```
|
647
648
|
|
649
|
+
## Custom admin pages
|
650
|
+
|
651
|
+
By default, Unfold provides a basic view mixin which helps with creation of basic views which are part of Unfold UI. The implementation requires creation of class based view inheriting from `unfold.views.UnfoldModelAdminViewMixin`. It is important to add `title` and `permissions_required` properties.
|
652
|
+
|
653
|
+
```python
|
654
|
+
# admin.py
|
655
|
+
|
656
|
+
from django.views.generic import TemplateView
|
657
|
+
from unfold.admin import ModelAdmin
|
658
|
+
from unfold.views import UnfoldModelAdminViewMixin
|
659
|
+
|
660
|
+
|
661
|
+
class MyClassBasedView(UnfoldModelAdminViewMixin, TemplateView):
|
662
|
+
title = "Custom Title" # required: custom page header title
|
663
|
+
permissions_required = () # required: tuple of permissions
|
664
|
+
template_name = "some/template/path.html"
|
665
|
+
|
666
|
+
|
667
|
+
class CustomAdmin(ModelAdmin):
|
668
|
+
def get_urls(self):
|
669
|
+
return super().get_urls() + [
|
670
|
+
path(
|
671
|
+
"custom-url-path",
|
672
|
+
MyClassBasedView.as_view(model_admin=self), # IMPORTANT: model_admin is required
|
673
|
+
name="custom_name"
|
674
|
+
),
|
675
|
+
]
|
676
|
+
```
|
677
|
+
|
678
|
+
The template is straightforward, extend from `unfold/layouts/base.html` and the UI will display all Unfold components like header or sidebar with all menu items. Then all content needs to be located in `content` block.
|
679
|
+
|
680
|
+
```django-html
|
681
|
+
{% extends "unfold/layouts/base.html" %}
|
682
|
+
|
683
|
+
{% block content %}
|
684
|
+
Content here
|
685
|
+
{% endblock %}
|
686
|
+
```
|
687
|
+
|
648
688
|
## Nonrelated inlines
|
649
689
|
|
650
690
|
To display inlines which are not related (no foreign key pointing at the main model) to the model instance in changeform, you can use nonrelated inlines which are included in `unfold.contrib.inlines` module. Make sure this module is included in `INSTALLED_APPS` in settings.py.
|
@@ -826,7 +866,10 @@ from django_celery_beat.models import (
|
|
826
866
|
PeriodicTask,
|
827
867
|
SolarSchedule,
|
828
868
|
)
|
829
|
-
|
869
|
+
from django_celery_beat.admin import ClockedScheduleAdmin as BaseClockedScheduleAdmin
|
870
|
+
from django_celery_beat.admin import CrontabScheduleAdmin as BaseCrontabScheduleAdmin
|
871
|
+
from django_celery_beat.admin import PeriodicTaskAdmin as BasePeriodicTaskAdmin
|
872
|
+
from django_celery_beat.admin import PeriodicTaskForm, TaskSelectWidget
|
830
873
|
|
831
874
|
admin.site.unregister(PeriodicTask)
|
832
875
|
admin.site.unregister(IntervalSchedule)
|
@@ -834,18 +877,30 @@ admin.site.unregister(CrontabSchedule)
|
|
834
877
|
admin.site.unregister(SolarSchedule)
|
835
878
|
admin.site.unregister(ClockedSchedule)
|
836
879
|
|
837
|
-
|
838
|
-
class
|
880
|
+
|
881
|
+
class UnfoldTaskSelectWidget(UnfoldAdminSelectWidget, TaskSelectWidget):
|
839
882
|
pass
|
840
883
|
|
841
884
|
|
885
|
+
class UnfoldPeriodicTaskForm(PeriodicTaskForm):
|
886
|
+
def __init__(self, *args, **kwargs):
|
887
|
+
super().__init__(*args, **kwargs)
|
888
|
+
self.fields["task"].widget = UnfoldAdminTextInputWidget()
|
889
|
+
self.fields["regtask"].widget = UnfoldTaskSelectWidget()
|
890
|
+
|
891
|
+
|
892
|
+
@admin.register(PeriodicTask)
|
893
|
+
class PeriodicTaskAdmin(BasePeriodicTaskAdmin, ModelAdmin):
|
894
|
+
form = UnfoldPeriodicTaskForm
|
895
|
+
|
896
|
+
|
842
897
|
@admin.register(IntervalSchedule)
|
843
898
|
class IntervalScheduleAdmin(ModelAdmin):
|
844
899
|
pass
|
845
900
|
|
846
901
|
|
847
902
|
@admin.register(CrontabSchedule)
|
848
|
-
class CrontabScheduleAdmin(ModelAdmin):
|
903
|
+
class CrontabScheduleAdmin(BaseCrontabScheduleAdmin, ModelAdmin):
|
849
904
|
pass
|
850
905
|
|
851
906
|
|
@@ -854,7 +909,7 @@ class SolarScheduleAdmin(ModelAdmin):
|
|
854
909
|
pass
|
855
910
|
|
856
911
|
@admin.register(ClockedSchedule)
|
857
|
-
class ClockedScheduleAdmin(ModelAdmin):
|
912
|
+
class ClockedScheduleAdmin(BaseClockedScheduleAdmin, ModelAdmin):
|
858
913
|
pass
|
859
914
|
```
|
860
915
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
unfold/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
unfold/admin.py,sha256=
|
2
|
+
unfold/admin.py,sha256=Q8my6Ui10yDW_KqTwfPK8p51u9SAj2n5f8DFF8lxYuk,18991
|
3
3
|
unfold/apps.py,sha256=SlBXPYrUd2uXn67qFbRvbXSUk3XFWrF4-5WELgDCvho,381
|
4
4
|
unfold/checks.py,sha256=Smgji9w19hnYjJElJ_FJnnyTEAE-E-OUB6otHu7lasY,1670
|
5
5
|
unfold/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -26,7 +26,7 @@ unfold/contrib/forms/static/unfold/forms/js/trix.js,sha256=Pao0XiVeDiRawfTkGDg_n
|
|
26
26
|
unfold/contrib/forms/templates/unfold/forms/array.html,sha256=11silyHbsJA0U_ksS8MvfFOJKC_qKTAwXxoMIB78APk,1507
|
27
27
|
unfold/contrib/forms/templates/unfold/forms/helpers/toolbar.html,sha256=yS8Zy-UrzvZ5RUYwdprQzREffnYq0NlIbXBfZM2UB04,9700
|
28
28
|
unfold/contrib/forms/templates/unfold/forms/wysiwyg.html,sha256=4ZefV6XrjJlUczcuSw8BhvMJUFSZPSXo1IkgkBivh5g,351
|
29
|
-
unfold/contrib/forms/widgets.py,sha256=
|
29
|
+
unfold/contrib/forms/widgets.py,sha256=D8utpEv-t_VDkppICA_0jtHvke7uElzAgaGMqd7NBHw,2875
|
30
30
|
unfold/contrib/guardian/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
31
31
|
unfold/contrib/guardian/apps.py,sha256=ObJqwh4vHxkD4XfduP5IQAiYiWZxsXUOUqF1_R1GsRI,136
|
32
32
|
unfold/contrib/guardian/templates/admin/guardian/model/change_form.html,sha256=FSJc4MYYWyzZAy8Ay0b7Ov-cUo-oELHOM5fQehM54Lg,403
|
@@ -38,13 +38,14 @@ unfold/contrib/guardian/templates/unfold/guardian/group_form.html,sha256=P8WMC5E
|
|
38
38
|
unfold/contrib/guardian/templates/unfold/guardian/user_form.html,sha256=ci7FRrhTEKbFKKxsJ-07_dWXBYz4mqXPoqu5HfqYLaM,4132
|
39
39
|
unfold/contrib/import_export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
40
40
|
unfold/contrib/import_export/apps.py,sha256=SdJu6Qh90VqGWY19FSDhhpUqhTbaIYsJKny3zX5baHI,149
|
41
|
-
unfold/contrib/import_export/forms.py,sha256=
|
41
|
+
unfold/contrib/import_export/forms.py,sha256=O8BBKJIdqLg3-uUFQyDV9-L6EoJ7EVSX3LJBP1zegGw,2037
|
42
42
|
unfold/contrib/import_export/templates/admin/import_export/base.html,sha256=loL2qcV-f8aAzkHss_I4IkwfgemVW2CjOu_aiBxdwX0,357
|
43
43
|
unfold/contrib/import_export/templates/admin/import_export/change_form.html,sha256=_YorgltKO0CRSaLBAp67XnGMUBWEP_XewsUff0hlrE4,446
|
44
|
+
unfold/contrib/import_export/templates/admin/import_export/change_list_export.html,sha256=vZb2XVoJrDSjM1msiZqkQPMLQGjuqRHuLNdt11hmbQs,164
|
44
45
|
unfold/contrib/import_export/templates/admin/import_export/change_list_export_item.html,sha256=pTDeqPKOlCPKH2dxMIfPnWuc2wVDzB7AzL73WbxSnRY,257
|
45
46
|
unfold/contrib/import_export/templates/admin/import_export/change_list_import_export.html,sha256=JdKd6P2Ot9Ou4yg4CywTauuE1UiTz_mRvDwlx3vj3LI,229
|
46
47
|
unfold/contrib/import_export/templates/admin/import_export/change_list_import_item.html,sha256=XUuRxnsx9YQbKvW-E_JGl_ha7kpTSGSoRefOTTizuX0,233
|
47
|
-
unfold/contrib/import_export/templates/admin/import_export/export.html,sha256=
|
48
|
+
unfold/contrib/import_export/templates/admin/import_export/export.html,sha256=NZ2bZ0yvskp_twIjX9LSROMmicXAU8dDXemxdII9_K0,3447
|
48
49
|
unfold/contrib/import_export/templates/admin/import_export/import.html,sha256=P54_f3s96PV87Bo-FCZfmsn9DkRXLOB36r7HYF6y7GM,2075
|
49
50
|
unfold/contrib/import_export/templates/admin/import_export/import_confirm.html,sha256=M-acK4XSLHuPFD_NJashGYvPPeJrJsC-3LMvHs3lRis,867
|
50
51
|
unfold/contrib/import_export/templates/admin/import_export/import_errors.html,sha256=0DmJvZs31u-E2Y53yySci86cTnG9aUnOzvfYrOo0lYA,1422
|
@@ -59,19 +60,19 @@ unfold/contrib/inlines/checks.py,sha256=8sdyBcxw0erqQvp9sHlpGgy0rXfum-cd2eQE0rXF
|
|
59
60
|
unfold/contrib/inlines/forms.py,sha256=R9OJvrbqNLlKvTxw97JjElCY4CQ3IyRIkjIJUN0gJ9k,1323
|
60
61
|
unfold/contrib/simple_history/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
61
62
|
unfold/contrib/simple_history/apps.py,sha256=eF_KVYb60CAnGgWk2Z1YKYGfgA3TJBMr229qI7e2pgU,153
|
62
|
-
unfold/contrib/simple_history/templates/simple_history/
|
63
|
-
unfold/contrib/simple_history/templates/simple_history/object_history.html,sha256=AZ6uQRr7wKxV_rys5hGTVGYtVS-Fp5eHIqiXYW8FB1c,847
|
63
|
+
unfold/contrib/simple_history/templates/simple_history/object_history.html,sha256=ioBkepWc9-PQe4Kfy32RKOt_zf4fntz5XUfFeV3yQVw,771
|
64
64
|
unfold/contrib/simple_history/templates/simple_history/object_history_form.html,sha256=MOL3Tw3Nk3Rnq1koRV7yeCev4CP06_4xqAIOQk1M7FU,2290
|
65
|
+
unfold/contrib/simple_history/templates/simple_history/object_history_list.html,sha256=-QAWguUzGtD08_LBBk00_5ZYUjnso-q6dLXSeALc0n4,7449
|
65
66
|
unfold/contrib/simple_history/templates/simple_history/submit_line.html,sha256=ns9CEkU4HwKHhhj8qj_9UXvzp0viGtD1tp93GV2WRCs,1703
|
66
|
-
unfold/dataclasses.py,sha256=
|
67
|
+
unfold/dataclasses.py,sha256=XssBT3nfeFO-oekKDWrX6abIyrIW1P8CPzzCv1TRYFM,266
|
67
68
|
unfold/decorators.py,sha256=6E4vPVwK0IQDAiDPg9pgyypRqciX_gR0jwITDcrSc8U,3367
|
68
69
|
unfold/exceptions.py,sha256=gcCj1ox61E137bk_0Cqy4YC3SttdPgB-fiJUqpmyHSE,43
|
69
|
-
unfold/fields.py,sha256=
|
70
|
+
unfold/fields.py,sha256=Zegz_og7aHpdvUdFlUcIYVPB9TjPGjybhR2QNuq1b7A,7422
|
70
71
|
unfold/forms.py,sha256=GXEm3CFwglyuEbGdVyEMJTB45Gs-_RvGGlXJEkPy2kw,3688
|
71
72
|
unfold/settings.py,sha256=--TdTSWdOA8TQGW4-vjJkjy_zEyd_kZwBr3BIuQ8hzI,1208
|
72
73
|
unfold/sites.py,sha256=Gy_i43j2nizW2g8-mas5icvtk-beKism_CznATW6Ia8,12586
|
73
74
|
unfold/static/unfold/css/simplebar.css,sha256=5LLaEM11pKi6JFCOLt4XKuZxTpT9rpdq_tNlaQytFlU,4647
|
74
|
-
unfold/static/unfold/css/styles.css,sha256=
|
75
|
+
unfold/static/unfold/css/styles.css,sha256=bj69qsSGIkN5MXx2_5uFa5DdrU8_9a1ZBY_ICVQtBCI,92189
|
75
76
|
unfold/static/unfold/fonts/inter/Inter-Bold.woff2,sha256=O88EyjAeRPE_QEyKBKpK5wf2epUOEu8wwjj5bnhCZqE,46552
|
76
77
|
unfold/static/unfold/fonts/inter/Inter-Medium.woff2,sha256=O88EyjAeRPE_QEyKBKpK5wf2epUOEu8wwjj5bnhCZqE,46552
|
77
78
|
unfold/static/unfold/fonts/inter/Inter-Regular.woff2,sha256=O88EyjAeRPE_QEyKBKpK5wf2epUOEu8wwjj5bnhCZqE,46552
|
@@ -85,7 +86,7 @@ unfold/static/unfold/js/app.js,sha256=CIitJoFqpeZYPw8icGVXYX9tVRUgqFxcPZ2WjWS8Yl
|
|
85
86
|
unfold/static/unfold/js/chart.js,sha256=22W6cFERR-CElMOKRgMMicueMVP0Vf7FBEBYH8Z8tCk,200633
|
86
87
|
unfold/static/unfold/js/htmx.js,sha256=XOLqvnZiyEx46EW9vaJTBUaaWg8CGVVfXJkVsUmJbpI,42820
|
87
88
|
unfold/static/unfold/js/simplebar.js,sha256=t-uG1FAD6ZoiMeN--wac0XRS7SxoDVG6zvRnGuEp7X8,27176
|
88
|
-
unfold/styles.css,sha256=
|
89
|
+
unfold/styles.css,sha256=RbIWn2OR51DzBgHobHuJKGOUCoKYI6WZsYFjtGjECoE,17835
|
89
90
|
unfold/templates/admin/actions.html,sha256=1tVlUpLoM72K2Ew4vQGcRwPjHuAtO5Jm4QdDsDLOq0I,2625
|
90
91
|
unfold/templates/admin/app_index.html,sha256=lVjMIFsspHQ09LGHKfdfg7TlqlL39AX5LbwoeoZjFhk,1335
|
91
92
|
unfold/templates/admin/app_list.html,sha256=krDzw2EXqqvIi8bJtPhJsNran9H7hwdhM6ZW_IRlDwQ,3038
|
@@ -107,12 +108,12 @@ unfold/templates/admin/filter.html,sha256=dkrFkei-EAlldIU8DrgvSChzWQuUOu6-LS_qlZ
|
|
107
108
|
unfold/templates/admin/includes/fieldset.html,sha256=lMVwBifFWKvLvHqZ6yjP6Xf6BJFzi-EOf5JHIxEHmRI,888
|
108
109
|
unfold/templates/admin/includes/object_delete_summary.html,sha256=Nv69SCzyJHFX14iJFfodxKM0IIpQegKZH0fvKB15QJI,468
|
109
110
|
unfold/templates/admin/index.html,sha256=pkGdKWdD3zzOvkRdELvdb15sleSpfl4eHPA14PAh7z0,684
|
110
|
-
unfold/templates/admin/login.html,sha256=
|
111
|
+
unfold/templates/admin/login.html,sha256=ePmGmS9MrqvR6_6hnRSYdW57XKmMIuVGTL9I6jCw9BM,3792
|
111
112
|
unfold/templates/admin/nav_sidebar.html,sha256=63lUhsHfrjZowplnOEq4BkGD9jlX0bVQw5VrAMJqf5M,1178
|
112
113
|
unfold/templates/admin/object_history.html,sha256=PsbhXFd_3SCB9YkSJeHESp2VqjNlHtUW26mRtaZ-MD0,5069
|
113
114
|
unfold/templates/admin/pagination.html,sha256=KWTPV7_hVSZ1374a-pqHXhnOueNQKu1UnSUYirrWtCk,1173
|
114
115
|
unfold/templates/admin/search_form.html,sha256=8fJlPYHQDCm4Je05wwdNJuJQR6ChLgghWmo-yHSybMs,1099
|
115
|
-
unfold/templates/admin/submit_line.html,sha256=
|
116
|
+
unfold/templates/admin/submit_line.html,sha256=X7xg5vgWfHFWJOuXOLshma_LWWI0H9GHDmMYD1JqfI4,4353
|
116
117
|
unfold/templates/auth/widgets/read_only_password_hash.html,sha256=Li9efo-3cFC5zj9im0SPfc62R4ZNVPQhs24H1U7xmD8,785
|
117
118
|
unfold/templates/registration/logged_out.html,sha256=E7RHtB6AGQwgUIiV7dwJ1DbdfNvEhzJARONnB6jRLhQ,1028
|
118
119
|
unfold/templates/registration/password_change_done.html,sha256=i1ZzfTwZHWNWoN9_xHZDdcgLdTOVbTFFD1HUSuG0LkY,1062
|
@@ -133,14 +134,15 @@ unfold/templates/unfold/helpers/actions_row.html,sha256=1xd39zx38NOoKuDuxAG7PHeu
|
|
133
134
|
unfold/templates/unfold/helpers/add_link.html,sha256=mIgpKrwqBO1oJ4cwPQWSX1oUHBwHJmy5-2TxUHf-1bo,808
|
134
135
|
unfold/templates/unfold/helpers/app_list.html,sha256=lFnW8p9DcZbI9t3_ee9JX9ERHA0NRL2V88zpzuG4jq8,4720
|
135
136
|
unfold/templates/unfold/helpers/app_list_default.html,sha256=vZkw1F7oHOKReNkdHRYjhuNdA1nNdvSD4wbDmf0bnsM,4102
|
136
|
-
unfold/templates/unfold/helpers/
|
137
|
+
unfold/templates/unfold/helpers/attrs.html,sha256=Mwpj72kuwYj8hOT3J2T8qx6f1r_4xwwaS1slHA-82jI,166
|
138
|
+
unfold/templates/unfold/helpers/boolean.html,sha256=6gXAMEJcNVB14je9uN32dxImXP3KMCiWPeKU5EAnawA,569
|
137
139
|
unfold/templates/unfold/helpers/breadcrumb_item.html,sha256=k_1j57UV0WtzFFlMKaewj4NLbR_DhXI6RzCHThblZLw,234
|
138
140
|
unfold/templates/unfold/helpers/display_header.html,sha256=HiuaIJ6Y8DSM99OFypLO_2uQadZIw7tSg1aJJpFEXkM,1161
|
139
141
|
unfold/templates/unfold/helpers/display_label.html,sha256=LS9DWzYjHkYLV27sZDwyXlg2sLJ0AlId9FbjnXpsbfg,317
|
140
142
|
unfold/templates/unfold/helpers/field.html,sha256=Ds-zUHkdyxamfUCVNhxvtM0XoJg9OCA0QcsLbLWv4oo,882
|
141
143
|
unfold/templates/unfold/helpers/field_readonly.html,sha256=O0gHEW46OWt1oUUk0lZiyR-mztWv_7IH6GpKRm2wUw4,235
|
142
|
-
unfold/templates/unfold/helpers/field_readonly_value.html,sha256=
|
143
|
-
unfold/templates/unfold/helpers/fieldset_row.html,sha256=
|
144
|
+
unfold/templates/unfold/helpers/field_readonly_value.html,sha256=8dhZAyIT1VrBLvGz9aP_7eqHFqmqMJdcQ-aIYgalpDI,437
|
145
|
+
unfold/templates/unfold/helpers/fieldset_row.html,sha256=XRaouqP-Z1nA_9Y9uSxIMjsJq_JIHj1SkpDFz1_xFM4,2820
|
144
146
|
unfold/templates/unfold/helpers/fieldsets_tabs.html,sha256=V3bgW75eozaBDty-xfciGafhCWq_Ba5HfQkk92yRc9A,1445
|
145
147
|
unfold/templates/unfold/helpers/form_errors.html,sha256=EwerIJptSCWXvtAJ1IZKfEn98qlShBIGavsTThbklAs,266
|
146
148
|
unfold/templates/unfold/helpers/form_label.html,sha256=SR4U6iK9w4oels6iGY_Da-yN4BbXQVN9zCDlBGGXcw8,310
|
@@ -152,11 +154,11 @@ unfold/templates/unfold/helpers/messages/error.html,sha256=mlHVdfpG2ycsKIDBJB9CZ
|
|
152
154
|
unfold/templates/unfold/helpers/messages/errornote.html,sha256=5ChxoVYkF4jI-cw72gVHh0CRxDnG9ME_U6UQOArax2k,404
|
153
155
|
unfold/templates/unfold/helpers/messages/info.html,sha256=js95Hm3CzqpP6_XJpnA2vG7qt8eyHmJJJcDF0e5PLtQ,143
|
154
156
|
unfold/templates/unfold/helpers/messages.html,sha256=axUkgdYQySOTKEuRBDkohXFf8dM1ioQt5m6iAR7Ls18,701
|
155
|
-
unfold/templates/unfold/helpers/navigation.html,sha256=
|
157
|
+
unfold/templates/unfold/helpers/navigation.html,sha256=NkyTYH4_NIAMMHmZFdIVCjTl3m3sy6xrBLIi0F_YZpw,1070
|
156
158
|
unfold/templates/unfold/helpers/pagination_current_item.html,sha256=4cZ2KLVcP0Y7xuGyXgexDQ07r94cgM5Gnmtv11dkRPQ,69
|
157
159
|
unfold/templates/unfold/helpers/pagination_ellipsis.html,sha256=Ar9Ntf2I_79mIVW5Hadwkn1Kx1Lj3d8eIXNXI1IIBfg,56
|
158
160
|
unfold/templates/unfold/helpers/search.html,sha256=T3JLlzEeHTEpX6qfjNQ0cQPW2rtVIOyE9quEyVHVXsA,1382
|
159
|
-
unfold/templates/unfold/helpers/search_results.html,sha256=
|
161
|
+
unfold/templates/unfold/helpers/search_results.html,sha256=N5CNMJSF91jbJS6OQP0nANlnwVeS9UmnuOJ8QLitl2c,774
|
160
162
|
unfold/templates/unfold/helpers/site_icon.html,sha256=RO-R5yRt6yOx41Z8dpDP4lzwMXFdz8Dp5j8vGUtHzh0,789
|
161
163
|
unfold/templates/unfold/helpers/site_logo.html,sha256=05tqXzHy--pluceRQ2jDUZCFX9DjPHdBqGaieUv9sXk,424
|
162
164
|
unfold/templates/unfold/helpers/submit.html,sha256=oSzq85LRLhdOlbFtFZFhYm6ucT95u6LunTeSTDClszQ,206
|
@@ -165,17 +167,18 @@ unfold/templates/unfold/helpers/tab_list.html,sha256=WMFSx0HEvylI_AOIPtFuWff1ePJ
|
|
165
167
|
unfold/templates/unfold/helpers/theme_switch.html,sha256=skkl6fYUnYLM7fAPivHxWjnOnuQSKa-7aDxh7I8dGIg,2266
|
166
168
|
unfold/templates/unfold/helpers/userlinks.html,sha256=qWjtBt9Q_tU8a874ii0Qqg8t_d-SSYBTB_3QZfNlx9g,634
|
167
169
|
unfold/templates/unfold/helpers/welcomemsg.html,sha256=noRysgSENef4_53pXaTiBCy2or6lQm1ZtmCQVODAB1c,1120
|
168
|
-
unfold/templates/unfold/layouts/
|
170
|
+
unfold/templates/unfold/layouts/base.html,sha256=bAXZDbyiyxNiE-49mqr7pHUFhC2mHZQzIDUY-js_yZ0,379
|
171
|
+
unfold/templates/unfold/layouts/base_simple.html,sha256=T37-ncKZBLNnOlsUQq90rGl3sLdRjFaxWCPG399pkbE,1179
|
169
172
|
unfold/templates/unfold/layouts/skeleton.html,sha256=iXrUiggVp36vmBIia5p32c-9Ruy0PxkFFQogDpvENbk,3419
|
170
173
|
unfold/templates/unfold/widgets/clearable_file_input.html,sha256=gAJsfyCnanOyeN4ypp1y7r76znvITV7FYTyWvPsmlDs,1882
|
171
|
-
unfold/templates/unfold/widgets/clearable_file_input_small.html,sha256=
|
174
|
+
unfold/templates/unfold/widgets/clearable_file_input_small.html,sha256=LPgiKuMAYPiEupFxdlwc1TozNRV1w9ekdRuv-5P4fgw,2531
|
172
175
|
unfold/templates/unfold/widgets/date.html,sha256=WXo2LG1v_gBZBSg-zocj7oujMKI0MWLYCIFfB04HMLQ,122
|
173
176
|
unfold/templates/unfold/widgets/foreign_key_raw_id.html,sha256=BgXi4ziywtkWmZuUye5bbJ6yeEoHDJB_2lkwXX8hc6c,1026
|
174
177
|
unfold/templates/unfold/widgets/radio.html,sha256=3WcmclQNg7R_pRjEHL1dHkGjAzWlWNYnhHkAirC4nuA,646
|
175
178
|
unfold/templates/unfold/widgets/radio_option.html,sha256=IZgPx-aWKJuxrSalJ3K50RFd1vwSpb9Qk0yZwfV78_A,368
|
176
179
|
unfold/templates/unfold/widgets/range.html,sha256=28FBtSUgUcG82vpk_I27Lbs5oWZOV_oMzVhx4wj3-Ik,262
|
177
180
|
unfold/templates/unfold/widgets/related_widget_wrapper.html,sha256=0I6wSu8z_sJPqmX6uZev4mQGIIM336d6kvHdHj36ny4,3831
|
178
|
-
unfold/templates/unfold/widgets/split_datetime.html,sha256=
|
181
|
+
unfold/templates/unfold/widgets/split_datetime.html,sha256=OCH0tSSHnQfdJaV0_D3qVB6UN4baGBALtxA3Hlh8a6U,1244
|
179
182
|
unfold/templates/unfold/widgets/split_datetime_vertical.html,sha256=xinCH4kkQ-yKUqcSI7-m-_UEzOEKWqvLTjUa3i-e8EM,881
|
180
183
|
unfold/templates/unfold/widgets/split_money.html,sha256=AFLUBmzGbY-RXgsfz7gaDxVRhplaIPhXjg_hWYo9xcY,352
|
181
184
|
unfold/templates/unfold/widgets/textarea.html,sha256=-ZLDGrtASero7L-J3VvTNq_KjPAZh_kLVw0Ow3awqXM,144
|
@@ -185,10 +188,10 @@ unfold/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSu
|
|
185
188
|
unfold/templatetags/unfold.py,sha256=HFe0GrTD4va0lLzsZhxqjEOONmehqOWdf5vulkxgfGU,6302
|
186
189
|
unfold/templatetags/unfold_list.py,sha256=5xAjQX0_JnVwDaj-wGkGqbjOAtp-a18koWIKj5VfBz0,13867
|
187
190
|
unfold/typing.py,sha256=1P8PWM2oeaceUJtA5j071RbKEBpHYaux441u7Hd6wv4,643
|
188
|
-
unfold/utils.py,sha256=
|
189
|
-
unfold/views.py,sha256=
|
190
|
-
unfold/widgets.py,sha256=
|
191
|
-
django_unfold-0.
|
192
|
-
django_unfold-0.
|
193
|
-
django_unfold-0.
|
194
|
-
django_unfold-0.
|
191
|
+
unfold/utils.py,sha256=zZdJE4FmwRd7p5a7sJiAoZjBOJitXJduOq7BulyppWM,4803
|
192
|
+
unfold/views.py,sha256=hQCyeeMa9kcJV1IZeeYqj8PGW7J4QWME8n-5n0UGmiU,1003
|
193
|
+
unfold/widgets.py,sha256=w9BnJ6LYaFJJG7eJGJ-NKwqSHh6iUExN4P94WRvZO_c,15575
|
194
|
+
django_unfold-0.28.1.dist-info/LICENSE.md,sha256=Ltk_quRyyvV3J5v3brtOqmibeZSw2Hrb8bY1W3ya0Ik,1077
|
195
|
+
django_unfold-0.28.1.dist-info/METADATA,sha256=twP1ylIumQTVb9QAlPFA-Rn-mgahDJbspHQifMo7zJ0,51430
|
196
|
+
django_unfold-0.28.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
197
|
+
django_unfold-0.28.1.dist-info/RECORD,,
|
unfold/admin.py
CHANGED
@@ -464,6 +464,7 @@ class ModelAdmin(ModelAdminMixin, BaseModelAdmin):
|
|
464
464
|
method=method,
|
465
465
|
description=self._get_action_description(method, action),
|
466
466
|
path=self._get_action_url(method, action),
|
467
|
+
attrs=method.attrs if hasattr(method, "attrs") else None,
|
467
468
|
)
|
468
469
|
|
469
470
|
@staticmethod
|
unfold/contrib/forms/widgets.py
CHANGED
@@ -15,23 +15,37 @@ class ImportForm(BaseImportForm):
|
|
15
15
|
def __init__(self, *args, **kwargs):
|
16
16
|
super().__init__(*args, **kwargs)
|
17
17
|
|
18
|
-
self.fields["resource"].widget.attrs["class"] = " ".join(
|
19
|
-
|
20
|
-
|
18
|
+
self.fields["resource"].widget.attrs["class"] = " ".join(
|
19
|
+
[self.fields["resource"].widget.attrs.get("class", ""), *SELECT_CLASSES]
|
20
|
+
)
|
21
|
+
self.fields["import_file"].widget = UnfoldAdminFileFieldWidget(
|
22
|
+
attrs=self.fields["import_file"].widget.attrs
|
23
|
+
)
|
24
|
+
self.fields["format"].widget.attrs["class"] = " ".join(
|
25
|
+
[self.fields["format"].widget.attrs.get("class", ""), *SELECT_CLASSES]
|
26
|
+
)
|
21
27
|
|
22
28
|
|
23
29
|
class ExportForm(BaseExportForm):
|
24
30
|
def __init__(self, *args, **kwargs):
|
25
31
|
super().__init__(*args, **kwargs)
|
26
|
-
self.fields["resource"].widget.attrs["class"] = " ".join(
|
27
|
-
|
32
|
+
self.fields["resource"].widget.attrs["class"] = " ".join(
|
33
|
+
[self.fields["resource"].widget.attrs.get("class", ""), *SELECT_CLASSES]
|
34
|
+
)
|
35
|
+
self.fields["format"].widget.attrs["class"] = " ".join(
|
36
|
+
[self.fields["format"].widget.attrs.get("class", ""), *SELECT_CLASSES]
|
37
|
+
)
|
28
38
|
|
29
39
|
|
30
40
|
class SelectableFieldsExportForm(BaseSelectableFieldsExportForm):
|
31
41
|
def __init__(self, formats, resources, **kwargs):
|
32
42
|
super().__init__(formats, resources, **kwargs)
|
33
|
-
self.fields["resource"].widget.attrs["class"] = " ".join(
|
34
|
-
|
43
|
+
self.fields["resource"].widget.attrs["class"] = " ".join(
|
44
|
+
[self.fields["resource"].widget.attrs.get("class", ""), *SELECT_CLASSES]
|
45
|
+
)
|
46
|
+
self.fields["format"].widget.attrs["class"] = " ".join(
|
47
|
+
[self.fields["format"].widget.attrs.get("class", ""), *SELECT_CLASSES]
|
48
|
+
)
|
35
49
|
|
36
50
|
for _key, field in self.fields.items():
|
37
51
|
if isinstance(field, BooleanField):
|
@@ -54,7 +54,7 @@
|
|
54
54
|
|
55
55
|
<fieldset class="border border-gray-200 mb-4 rounded-md pt-3 px-3 shadow-sm dark:border-gray-800">
|
56
56
|
{% for field in form.visible_fields %}
|
57
|
-
<div {% if field.field.is_selectable_field %}class="selectable-field-export-row" resource-index="{{ field.field.resource_index }}"{%
|
57
|
+
<div {% if field.field.is_selectable_field %}class="selectable-field-export-row" resource-index="{{ field.field.resource_index }}"{% endif %}>
|
58
58
|
{% if field.field.initial_field %}
|
59
59
|
<p class="block font-medium mb-2 text-gray-900 text-sm dark:text-gray-200">
|
60
60
|
{% trans "This exporter will export the following fields" %}
|
@@ -1,8 +1,6 @@
|
|
1
1
|
{% extends "admin/object_history.html" %}
|
2
2
|
|
3
|
-
{% load
|
4
|
-
{% load url from simple_history_compat %}
|
5
|
-
{% load display_list from simple_history_admin_list %}
|
3
|
+
{% load i18n %}
|
6
4
|
|
7
5
|
{% block content %}
|
8
6
|
{% if not revert_disabled %}
|
@@ -11,8 +9,8 @@
|
|
11
9
|
</p>
|
12
10
|
{% endif %}
|
13
11
|
|
14
|
-
{% if
|
15
|
-
{%
|
12
|
+
{% if historical_records %}
|
13
|
+
{% include object_history_list_template %}
|
16
14
|
{% else %}
|
17
15
|
<p class="mb-3 px-3 py-3 rounded-md text-sm last:mb-8 bg-amber-100 text-amber-600 dark:bg-amber-600/20 dark:border-amber-600/10">
|
18
16
|
{% trans "This object doesn't have a change history." %}
|
@@ -31,40 +31,44 @@
|
|
31
31
|
<th class="align-middle font-medium px-3 py-2 text-left text-gray-400 text-sm">
|
32
32
|
{% trans 'Change reason' %}
|
33
33
|
</th>
|
34
|
+
|
35
|
+
<th class="align-middle font-medium px-3 py-2 text-left text-gray-400 text-sm">
|
36
|
+
{% trans 'Changes' %}
|
37
|
+
</th>
|
34
38
|
</tr>
|
35
39
|
</thead>
|
36
40
|
|
37
41
|
<tbody>
|
38
|
-
{% for
|
42
|
+
{% for record in historical_records %}
|
39
43
|
<tr class="block border mb-3 rounded-md shadow-sm lg:table-row lg:border-none lg:mb-0 lg:shadow-none dark:border-gray-800">
|
40
44
|
<td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Object' %}">
|
41
|
-
<a href="{% url opts|admin_urlname:'simple_history' object.pk
|
42
|
-
{{
|
45
|
+
<a href="{% url opts|admin_urlname:'simple_history' object.pk record.pk %}">
|
46
|
+
{{ record.history_object }}
|
43
47
|
</a>
|
44
48
|
</td>
|
45
49
|
|
46
50
|
{% for column in history_list_display %}
|
47
51
|
<td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans column %}">
|
48
|
-
{{
|
52
|
+
{{ record|getattribute:column }}
|
49
53
|
</th>
|
50
54
|
{% endfor %}
|
51
55
|
|
52
56
|
<td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Date/time' %}">
|
53
|
-
{{
|
57
|
+
{{ record.history_date }}
|
54
58
|
</td>
|
55
59
|
|
56
60
|
<td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Comment' %}">
|
57
|
-
{{
|
61
|
+
{{ record.get_history_type_display }}
|
58
62
|
</td>
|
59
63
|
|
60
64
|
<td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Changed by' %}">
|
61
|
-
{% if
|
62
|
-
{% url admin_user_view
|
65
|
+
{% if record.history_user %}
|
66
|
+
{% url admin_user_view record.history_user_id as admin_user_url %}
|
63
67
|
|
64
68
|
{% if admin_user_url %}
|
65
|
-
<a href="{{ admin_user_url }}">{{
|
69
|
+
<a href="{{ admin_user_url }}">{{ record.history_user }}</a>
|
66
70
|
{% else %}
|
67
|
-
{{
|
71
|
+
{{ record.history_user }}
|
68
72
|
{% endif %}
|
69
73
|
{% else %}
|
70
74
|
{% trans "None" %}
|
@@ -72,7 +76,41 @@
|
|
72
76
|
</td>
|
73
77
|
|
74
78
|
<td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Change reason' %}">
|
75
|
-
{{
|
79
|
+
{{ record.history_change_reason }}
|
80
|
+
</td>
|
81
|
+
|
82
|
+
<td class="align-middle flex border-t border-gray-200 font-normal px-3 py-2 text-left text-sm before:flex before:capitalize before:content-[attr(data-label)] before:items-center before:mr-auto before:text-gray-500 first:border-t-0 dark:before:text-gray-400 lg:before:hidden lg:first:border-t lg:py-3 lg:table-cell dark:border-gray-800" data-label="{% trans 'Changes' %}">
|
83
|
+
{% block history_delta_changes %}
|
84
|
+
{% if record.history_delta_changes %}
|
85
|
+
<ul>
|
86
|
+
{% for change in record.history_delta_changes %}
|
87
|
+
<li class="flex flex-row gap-2">
|
88
|
+
<strong class="font-medium text-gray-700 dark:text-gray-200">
|
89
|
+
{{ change.field }}:
|
90
|
+
</strong>
|
91
|
+
|
92
|
+
<div class="flex flex-row items-center gap-2">
|
93
|
+
{% if change.old %}
|
94
|
+
<span>
|
95
|
+
{{ change.old }}
|
96
|
+
</span>
|
97
|
+
{% endif %}
|
98
|
+
|
99
|
+
{% if change.old and change.new %}
|
100
|
+
<span class="align-text-top material-symbols-outlined md-18 text-gray-300 group-hover:text-gray-400 dark:text-gray-600">arrow_right_alt</span>
|
101
|
+
{% endif %}
|
102
|
+
|
103
|
+
{% if change.new %}
|
104
|
+
<span>
|
105
|
+
{{ change.new }}
|
106
|
+
</span>
|
107
|
+
{% endif %}
|
108
|
+
</div>
|
109
|
+
</li>
|
110
|
+
{% endfor %}
|
111
|
+
</ul>
|
112
|
+
{% endif %}
|
113
|
+
{% endblock %}
|
76
114
|
</td>
|
77
115
|
</tr>
|
78
116
|
{% endfor %}
|
unfold/dataclasses.py
CHANGED
unfold/fields.py
CHANGED
@@ -18,7 +18,7 @@ from django.utils.safestring import SafeText, mark_safe
|
|
18
18
|
from django.utils.text import capfirst
|
19
19
|
|
20
20
|
from .settings import get_config
|
21
|
-
from .utils import display_for_field
|
21
|
+
from .utils import display_for_field, prettify_json
|
22
22
|
from .widgets import CHECKBOX_LABEL_CLASSES, LABEL_CLASSES
|
23
23
|
|
24
24
|
|
@@ -138,6 +138,14 @@ class UnfoldAdminReadonlyField(helpers.AdminReadonlyField):
|
|
138
138
|
and value is not None
|
139
139
|
):
|
140
140
|
result_repr = self.get_admin_url(f.remote_field, value)
|
141
|
+
elif isinstance(f, models.JSONField):
|
142
|
+
formatted_output = prettify_json(value)
|
143
|
+
|
144
|
+
if formatted_output:
|
145
|
+
return formatted_output
|
146
|
+
|
147
|
+
result_repr = display_for_field(value, f, self.empty_value_display)
|
148
|
+
return conditional_escape(result_repr)
|
141
149
|
elif isinstance(f, models.URLField):
|
142
150
|
return format_html(
|
143
151
|
'<a href="{}" class="text-primary-600 underline whitespace-nowrap">{}</a>',
|