django-unfold 0.27.0__py3-none-any.whl → 0.28.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.27.0.dist-info → django_unfold-0.28.0.dist-info}/METADATA +44 -4
- {django_unfold-0.27.0.dist-info → django_unfold-0.28.0.dist-info}/RECORD +21 -18
- unfold/admin.py +1 -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/dataclasses.py +2 -0
- unfold/fields.py +9 -1
- 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/fieldset_row.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/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.0.dist-info}/LICENSE.md +0 -0
- {django_unfold-0.27.0.dist-info → django_unfold-0.28.0.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.0
|
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.
|
@@ -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
|
@@ -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
|
@@ -63,10 +64,10 @@ unfold/contrib/simple_history/templates/simple_history/_object_history_list.html
|
|
63
64
|
unfold/contrib/simple_history/templates/simple_history/object_history.html,sha256=AZ6uQRr7wKxV_rys5hGTVGYtVS-Fp5eHIqiXYW8FB1c,847
|
64
65
|
unfold/contrib/simple_history/templates/simple_history/object_history_form.html,sha256=MOL3Tw3Nk3Rnq1koRV7yeCev4CP06_4xqAIOQk1M7FU,2290
|
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
|
@@ -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,6 +134,7 @@ 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
|
137
|
+
unfold/templates/unfold/helpers/attrs.html,sha256=Mwpj72kuwYj8hOT3J2T8qx6f1r_4xwwaS1slHA-82jI,166
|
136
138
|
unfold/templates/unfold/helpers/boolean.html,sha256=p_WOlytoXvDwta76WgcV4JSWKpBgKf4amhqmHF798F8,564
|
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
|
@@ -140,7 +142,7 @@ unfold/templates/unfold/helpers/display_label.html,sha256=LS9DWzYjHkYLV27sZDwyXl
|
|
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
144
|
unfold/templates/unfold/helpers/field_readonly_value.html,sha256=wdzHVKaI96S-S1MaV-odKXDdT_MRkfWMcXdUBhRlTDY,490
|
143
|
-
unfold/templates/unfold/helpers/fieldset_row.html,sha256=
|
145
|
+
unfold/templates/unfold/helpers/fieldset_row.html,sha256=pcVBMudv1QDZp840S9a_8BuFb1DzUWBmsPUZI7lfgDo,2751
|
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
|
@@ -156,7 +158,7 @@ unfold/templates/unfold/helpers/navigation.html,sha256=Nmgk6_690AeHgKE0-YS7tQYq2
|
|
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,10 +167,11 @@ 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
|
@@ -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.0.dist-info/LICENSE.md,sha256=Ltk_quRyyvV3J5v3brtOqmibeZSw2Hrb8bY1W3ya0Ik,1077
|
195
|
+
django_unfold-0.28.0.dist-info/METADATA,sha256=_i3r1OdWajR9BKmzMzYuPv91IyuKVKMvSTu6ufCwl8E,50658
|
196
|
+
django_unfold-0.28.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
197
|
+
django_unfold-0.28.0.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
|
@@ -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" %}
|
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>',
|
@@ -45,6 +45,8 @@
|
|
45
45
|
{% include "unfold/helpers/messages/error.html" with error=message %}
|
46
46
|
{% endif %}
|
47
47
|
|
48
|
+
{% block login_before %}{% endblock %}
|
49
|
+
|
48
50
|
<form action="{{ app_path }}" method="post" id="login-form">
|
49
51
|
{% csrf_token %}
|
50
52
|
|
@@ -70,6 +72,8 @@
|
|
70
72
|
</button>
|
71
73
|
</div>
|
72
74
|
</form>
|
75
|
+
|
76
|
+
{% block login_after %}{% endblock %}
|
73
77
|
</div>
|
74
78
|
|
75
79
|
<div class="absolute flex flex-row items-center justify-between left-0 m-4 right-0 top-0">
|
@@ -12,7 +12,7 @@
|
|
12
12
|
{% endif %}
|
13
13
|
|
14
14
|
{% for action in actions_submit_line %}
|
15
|
-
<button type="submit" name="{{ action.action_name }}" class="border font-medium px-3 py-2 rounded-md text-sm text-gray-500 transition-all
|
15
|
+
<button type="submit" {% if not action.attrs.name %}name="{{ action.action_name }}"{% endif %} class="border font-medium px-3 py-2 rounded-md text-sm text-gray-500 transition-all w-full hover:bg-gray-50 lg:w-auto dark:border-gray-700 dark:text-gray-400 dark:hover:text-gray-200 dark:hover:bg-gray-900" {% include "unfold/helpers/attrs.html" with attrs=action.attrs %}>
|
16
16
|
{{ action.description }}
|
17
17
|
</button>
|
18
18
|
{% endfor %}
|
@@ -0,0 +1 @@
|
|
1
|
+
{% for name, value in attrs.items %}{% if value is not False %} {{ name }}{% if value is not True %}="{{ value|stringformat:'s' }}"{% endif %}{% endif %}{% endfor %}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<div class="form-row
|
2
|
-
{% if adminform.model_admin.compressed_fields %} border-b border-gray-200 -mx-3 px-3 pt-3 first:pt-0 last:border-b-0{% endif %}
|
2
|
+
{% if adminform.model_admin.compressed_fields %} border-b border-gray-200 -mx-3 px-3 pt-3 first:pt-0 dark:border-gray-800 last:border-b-0{% endif %}
|
3
3
|
{% if not line.fields|length == 1 %} flex flex-row flex-wrap gap-x-8{% endif %}
|
4
4
|
{% if not line.has_visible_field %} hidden{% endif %}
|
5
5
|
{% for field in line %}{% if field.field.name %} field-{{ field.field.name }}{% endif %}{% endfor %}">
|
@@ -1,13 +1,13 @@
|
|
1
1
|
{% if results %}
|
2
|
-
<ul class="absolute bg-white border left-0 mt-12 right-0 rounded top-0 shadow-sm text-sm dark:bg-gray-800 dark:border-gray-700">
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
2
|
+
<ul class="absolute bg-white border left-0 mt-12 right-0 rounded top-0 shadow-sm text-sm z-10 dark:bg-gray-800 dark:border-gray-700">
|
3
|
+
{% for app in results %}
|
4
|
+
{% for model in app.models %}
|
5
|
+
<li>
|
6
|
+
<a href="{{ model.admin_url }}" class="block group overflow-hidden px-3 py-2 text-gray-500 text-ellipsis whitespace-nowrap hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200">
|
7
|
+
{{ app.name }} <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> {{ model.name }}
|
8
|
+
</a>
|
9
|
+
</li>
|
10
|
+
{% endfor %}
|
10
11
|
{% endfor %}
|
11
|
-
|
12
|
-
</ul>
|
12
|
+
</ul>
|
13
13
|
{% endif %}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
{% extends "unfold/layouts/base_simple.html" %}
|
2
|
+
|
3
|
+
{% block branding %}
|
4
|
+
<h1 id="site-name">
|
5
|
+
<a href="{% url 'admin:index' %}">
|
6
|
+
{{ site_header|default:_('Django administration') }}
|
7
|
+
</a>
|
8
|
+
</h1>
|
9
|
+
{% endblock %}
|
10
|
+
|
11
|
+
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
|
@@ -15,7 +15,13 @@
|
|
15
15
|
{% include "unfold/helpers/header.html" %}
|
16
16
|
{% endblock %}
|
17
17
|
|
18
|
-
|
18
|
+
{% if not is_popup %}
|
19
|
+
{% spaceless %}
|
20
|
+
{% block breadcrumbs %}{% endblock %}
|
21
|
+
{% endspaceless %}
|
22
|
+
{% endif %}
|
23
|
+
|
24
|
+
<div class="px-4 lg:px-12">
|
19
25
|
<div id="content" class="container mx-auto {% block coltype %}colM{% endblock %}">
|
20
26
|
{% block content %}
|
21
27
|
{% block object-tools %}{% endblock %}
|
@@ -17,7 +17,7 @@
|
|
17
17
|
<input type="text" value="{% if widget.value %}{{ widget.value.url }}{% else %}{% trans 'Choose file to upload' %}{% endif %}" disabled class="bg-white flex-grow font-medium px-3 py-2 text-ellipsis dark:bg-gray-900 {% if widget.value %}text-gray-500 dark:text-gray-400{% else %}text-gray-300 dark:text-gray-400{% endif %}">
|
18
18
|
|
19
19
|
<div class="flex flex-none items-center leading-none self-stretch">
|
20
|
-
<input id="{{ widget.name }}" type="{{ widget.type }}" name="{{ widget.name }}" class="
|
20
|
+
<input id="{{ widget.name }}" type="{{ widget.type }}" name="{{ widget.name }}" class="{{ widget.file_input_class }}" {% include "django/forms/widgets/attrs.html" %} />
|
21
21
|
|
22
22
|
<label for="{{ widget.name }}" class="cursor-pointer text-gray-400 px-3 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-200">
|
23
23
|
<span class="material-symbols-outlined">file_upload</span>
|
unfold/utils.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import datetime
|
2
2
|
import decimal
|
3
3
|
import json
|
4
|
-
from typing import Any, Iterable, List
|
4
|
+
from typing import Any, Iterable, List, Optional
|
5
5
|
|
6
6
|
from django.db import models
|
7
7
|
from django.template.loader import render_to_string
|
@@ -121,3 +121,23 @@ def hex_to_rgb(hex_color: str) -> List[int]:
|
|
121
121
|
b = int(hex_color[4:6], 16)
|
122
122
|
|
123
123
|
return (r, g, b)
|
124
|
+
|
125
|
+
|
126
|
+
def prettify_json(data: Any) -> Optional[str]:
|
127
|
+
try:
|
128
|
+
from pygments import highlight
|
129
|
+
from pygments.formatters import HtmlFormatter
|
130
|
+
from pygments.lexers import JsonLexer
|
131
|
+
except ImportError:
|
132
|
+
return None
|
133
|
+
|
134
|
+
def format_response(response: str, theme: str) -> str:
|
135
|
+
formatter = HtmlFormatter(style=theme, noclasses=True, nobackground=True)
|
136
|
+
return highlight(response, JsonLexer(), formatter)
|
137
|
+
|
138
|
+
response = json.dumps(data, sort_keys=True, indent=4)
|
139
|
+
|
140
|
+
return mark_safe(
|
141
|
+
f'<div class="block dark:hidden">{format_response(response, "colorful")}</div>'
|
142
|
+
f'<div class="hidden dark:block">{format_response(response, "monokai")}</div>'
|
143
|
+
)
|
unfold/views.py
CHANGED
@@ -10,13 +10,25 @@ class UnfoldModelAdminViewMixin(PermissionRequiredMixin):
|
|
10
10
|
Prepares views to be displayed in admin
|
11
11
|
"""
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
model_admin = None
|
14
|
+
|
15
|
+
def __init__(self, model_admin, **kwargs):
|
16
|
+
self.model_admin = model_admin
|
17
|
+
super().__init__(**kwargs)
|
18
|
+
|
19
|
+
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
|
20
|
+
if not hasattr(self, "model_admin"):
|
15
21
|
raise UnfoldException(
|
16
22
|
"UnfoldModelAdminViewMixin was not provided with 'model_admin' argument"
|
17
23
|
)
|
18
|
-
|
19
|
-
|
20
|
-
|
24
|
+
|
25
|
+
if not hasattr(self, "title"):
|
26
|
+
raise UnfoldException(
|
27
|
+
"UnfoldModelAdminViewMixin was not provided with 'title' attribute"
|
28
|
+
)
|
29
|
+
|
30
|
+
return super().get_context_data(
|
31
|
+
**kwargs,
|
32
|
+
**self.model_admin.admin_site.each_context(self.request),
|
33
|
+
**{"title": self.title},
|
21
34
|
)
|
22
|
-
return context_data
|
unfold/widgets.py
CHANGED
@@ -288,7 +288,18 @@ class FileFieldMixin:
|
|
288
288
|
def get_context(self, name, value, attrs):
|
289
289
|
widget = super().get_context(name, value, attrs)
|
290
290
|
widget["widget"].update(
|
291
|
-
{
|
291
|
+
{
|
292
|
+
"class": " ".join([*CHECKBOX_CLASSES, *["form-check-input"]]),
|
293
|
+
"file_input_class": " ".join(
|
294
|
+
[
|
295
|
+
self.attrs.get("class", ""),
|
296
|
+
*[
|
297
|
+
"opacity-0",
|
298
|
+
"pointer-events-none",
|
299
|
+
],
|
300
|
+
]
|
301
|
+
),
|
302
|
+
}
|
292
303
|
)
|
293
304
|
return widget
|
294
305
|
|
File without changes
|
File without changes
|