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.
Files changed (30) hide show
  1. {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/METADATA +64 -9
  2. {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/RECORD +30 -27
  3. unfold/admin.py +1 -0
  4. unfold/contrib/forms/widgets.py +2 -0
  5. unfold/contrib/import_export/forms.py +21 -7
  6. unfold/contrib/import_export/templates/admin/import_export/change_list_export.html +5 -0
  7. unfold/contrib/import_export/templates/admin/import_export/export.html +1 -1
  8. unfold/contrib/simple_history/templates/simple_history/object_history.html +3 -5
  9. unfold/contrib/simple_history/templates/simple_history/{_object_history_list.html → object_history_list.html} +49 -11
  10. unfold/dataclasses.py +2 -0
  11. unfold/fields.py +9 -1
  12. unfold/static/unfold/css/styles.css +1 -1
  13. unfold/styles.css +1 -2
  14. unfold/templates/admin/login.html +4 -0
  15. unfold/templates/admin/submit_line.html +1 -1
  16. unfold/templates/unfold/helpers/attrs.html +1 -0
  17. unfold/templates/unfold/helpers/boolean.html +1 -1
  18. unfold/templates/unfold/helpers/field_readonly_value.html +1 -1
  19. unfold/templates/unfold/helpers/fieldset_row.html +2 -2
  20. unfold/templates/unfold/helpers/navigation.html +1 -1
  21. unfold/templates/unfold/helpers/search_results.html +10 -10
  22. unfold/templates/unfold/layouts/base.html +11 -0
  23. unfold/templates/unfold/layouts/base_simple.html +7 -1
  24. unfold/templates/unfold/widgets/clearable_file_input_small.html +1 -1
  25. unfold/templates/unfold/widgets/split_datetime.html +7 -7
  26. unfold/utils.py +21 -1
  27. unfold/views.py +18 -6
  28. unfold/widgets.py +12 -1
  29. {django_unfold-0.27.0.dist-info → django_unfold-0.28.1.dist-info}/LICENSE.md +0 -0
  30. {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.27.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/) and let's supercharge development by using our know-how.
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
- @admin.register(PeriodicTask)
838
- class PeriodicTaskAdmin(ModelAdmin):
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=T14cMt5yn-uQQWDS5_Ebb2Jjhsc0pStaKtsutNoJeWg,18921
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=yWug9YQ6FWI7hqvNZqhCwJhlfC_gMh9GELVGTE2Tw9k,2813
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=cmUUiULJo771rbxf-uCarrbRNwvzCIketbP_7eFnvGc,1496
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=a0gL1YvlFTYQEpJuab-Ue_YL86UO5VkfREqy5CepZUg,3481
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/_object_history_list.html,sha256=aXOQ1zwsRBlFmzODsZApvMtb8t1IPXim6i4plXUR5XE,5112
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=JJdGYzQ8MpeOe2FQPJqrMn_UJcxUz1VJgHCuCtkZCA8,199
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=01CRr526Fautw58ik5RAGAihwAeLB5mxO6PR-oFto1o,7055
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=CU9SCfH3nREI3C6yP9DFAvvr_23lSg9H6rAwM0_w958,91898
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=JA2ybI-pzRM4ZOKshI187oJ5Z3gMNWHQAuEfwq5Xb_E,17854
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=WdOfFLofwBWj9VKCq1U22uLY19J2YQY6vRaE4OOSKfQ,3681
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=Oi7lUe2oh8O4--ZM0eQzVtZQnRKVeVXylc1ECGA7zKI,4247
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/boolean.html,sha256=p_WOlytoXvDwta76WgcV4JSWKpBgKf4amhqmHF798F8,564
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=wdzHVKaI96S-S1MaV-odKXDdT_MRkfWMcXdUBhRlTDY,490
143
- unfold/templates/unfold/helpers/fieldset_row.html,sha256=HHGzZ09Irtj4PUGXZkbAAvJcBFGcvJqjR7k-TZzpVyU,2730
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=Nmgk6_690AeHgKE0-YS7tQYq2sOnn3jUZnBhcluR-QE,1067
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=nv2HDqGvP9aAmQ35Fdq0oiZcDFTXgkLic1AVMLumyU8,725
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/base_simple.html,sha256=rki7n7QagHFAaCEn488pTOj9dpNL9AwwzKps8Ipiubk,993
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=rqUnHF4jwL8_RySUuq2aXgj-0P_usgo1HeVT_IcfyFY,2531
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=eXLFZyCv84LCTFWAUhNO3xAIzWvGBvI1ZpYbB38_HOI,862
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=5OIgDcwvIJQbwbnnqHx61cHh-2T1h184mTAuNq5WXLI,4088
189
- unfold/views.py,sha256=Ml3XlEoHLcbEWof59Dw8ihKBMcmp-gBAibThtBFj55A,708
190
- unfold/widgets.py,sha256=iiI73XznYH34LgXBHu1oVtYb76lLO3HiOD9blmm89rY,15236
191
- django_unfold-0.27.0.dist-info/LICENSE.md,sha256=Ltk_quRyyvV3J5v3brtOqmibeZSw2Hrb8bY1W3ya0Ik,1077
192
- django_unfold-0.27.0.dist-info/METADATA,sha256=llKdxPkbhzG4E-UJji8aTaQkjm5YTf9DBP4OSC9pa6c,49139
193
- django_unfold-0.27.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
194
- django_unfold-0.27.0.dist-info/RECORD,,
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
@@ -60,6 +60,8 @@ class ArrayWidget(MultiWidget):
60
60
 
61
61
  def decompress(self, value: Union[str, List]) -> List:
62
62
  if isinstance(value, List):
63
+ return value
64
+ elif isinstance(value, str):
63
65
  return value.split(",")
64
66
 
65
67
  return []
@@ -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(SELECT_CLASSES)
19
- self.fields["import_file"].widget = UnfoldAdminFileFieldWidget()
20
- self.fields["format"].widget.attrs["class"] = " ".join(SELECT_CLASSES)
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(SELECT_CLASSES)
27
- self.fields["format"].widget.attrs["class"] = " ".join(SELECT_CLASSES)
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(SELECT_CLASSES)
34
- self.fields["format"].widget.attrs["class"] = " ".join(SELECT_CLASSES)
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):
@@ -0,0 +1,5 @@
1
+ {% extends "admin/import_export/change_list.html" %}
2
+
3
+ {% block actions-items %}
4
+ {% include "admin/import_export/change_list_export_item.html" %}
5
+ {% endblock %}
@@ -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 }}"{% else %}class="form-row aligned"{% endif %}>
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 admin_urls i18n %}
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 action_list %}
15
- {% display_list %}
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 action in action_list %}
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 action.pk %}">
42
- {{ action.history_object }}
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
- {{ action|getattribute:column }}
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
- {{ action.history_date }}
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
- {{ action.get_history_type_display }}
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 action.history_user %}
62
- {% url admin_user_view action.history_user_id as admin_user_url %}
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 }}">{{ action.history_user }}</a>
69
+ <a href="{{ admin_user_url }}">{{ record.history_user }}</a>
66
70
  {% else %}
67
- {{ action.history_user }}
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
- {{ action.history_change_reason }}
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
@@ -1,4 +1,5 @@
1
1
  from dataclasses import dataclass
2
+ from typing import Dict, Optional
2
3
 
3
4
  from .typing import ActionFunction
4
5
 
@@ -9,3 +10,4 @@ class UnfoldAction:
9
10
  method: ActionFunction
10
11
  description: str
11
12
  path: str
13
+ attrs: Optional[Dict] = None
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>',