#30577 closed New feature (needsinfo)
feature request: custom rendering for readonly fields in admin
Reported by: | David | Owned by: | nobody |
---|---|---|---|
Component: | contrib.admin | Version: | 5.1 |
Severity: | Normal | Keywords: | |
Cc: | Florian Demmer, Carlos Palol, ldeluigi, Mariusz Felisiak | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
The new view permission is extremely useful, and encourages more use of the Django Admin tool. It has highlighted a limitation in the rendering of readonly_fields
that can be easily addressed. At the moment, readonly_fields
(or all fields when the user has only can_view
) can only have custom rendering or formatting if they are custom properties or new fields (created in the ModelAdmin), existing fields can't be changed. In my use-case I have a number of rich text enhanced TextField
s, which when rendered as read-only show up as HTML and can't be marked safe. In this case creating a custom field in the ModelAdmin
where the Field can be output with mark_safe()
doesn't work as the original field needs to exist for users with change permissions, the only other way is to include the field twice which creates UX issues.
If, in ModelAdmin, you could override the formatting/output of a read-only field it would address this issue. Alternatively, as mentioned in the comments of #14802, the idea of Fields having a method that is called by admin to handle the read-only HTML rendering would also do the trick as is related.
Change History (12)
comment:2 by , 6 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
comment:3 by , 4 years ago
Cc: | added |
---|
comment:4 by , 3 years ago
Just ended up here while looking for a way to have a custom widget on a read-only JSONField and bumping into ReadOnlyPasswordHashWidget
hackery on my own...
Wouldn't it be cleaner (and easy) to simple update ​https://github.com/django/django/blob/main/django/contrib/admin/templates/admin/includes/fieldset.html#L16-L18 to check for an existing field.readonly_widget
all the time?
comment:5 by , 3 years ago
Cc: | added |
---|
follow-ups: 7 9 comment:6 by , 7 months ago
Cc: | added |
---|---|
Resolution: | needsinfo |
Status: | closed → new |
Version: | 2.2 → 5.1 |
I'd like to reopen this ticket in favor of another use case scenario:
I have plenty of models that each have many DateTimeFields that are read only, namely 'updated' and 'created' timestamps.
I want to customize how datetimes are displayed as HTML when they are read_only, but unfortunately Django admin invokes the hardcoded display functions to display read_only fields that don't have a widget set with read_only=True. I don't want to customize it once for each of these fields, I'd like to make a common abstract class that inherits from ModelAdmin once for all my forms and have it change the generated HTML for datetimefields for every subclass.
Using formfield_overrides with a widget with read_only=True isn't enough because the AdminReadonlyField contents method wants the field to be explicitly listed in the form fields before checking if read_only is True on the widget.
I'd like to be able to provide a read only representation of field classes from a ModelAdmin superclass.
comment:7 by , 6 months ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Replying to ldeluigi:
I'd like to reopen this ticket in favor of another use case scenario:
I have plenty of models that each have many DateTimeFields that are read only, namely 'updated' and 'created' timestamps.
I want to customize how datetimes are displayed as HTML when they are read_only, but unfortunately Django admin invokes the hardcoded display functions to display read_only fields that don't have a widget set with read_only=True. I don't want to customize it once for each of these fields, I'd like to make a common abstract class that inherits from ModelAdmin once for all my forms and have it change the generated HTML for datetimefields for every subclass.
Using formfield_overrides with a widget with read_only=True isn't enough because the AdminReadonlyField contents method wants the field to be explicitly listed in the form fields before checking if read_only is True on the widget.
I'd like to be able to provide a read only representation of field classes from a ModelAdmin superclass.
Thanks for reopening this ticket, however you didn't answer any of Carlton's requests/questions or provide PoC. Please don't reopen old ticket without providing required details.
comment:8 by , 6 months ago
Cc: | added |
---|
comment:9 by , 6 months ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
Here is the PoC where I've defined an AbstractAdmin that basically monkeypatches the feature for all subclasses that expose readonly DateTimeField(s) values:
​https://github.com/ldeluigi/django-poc-20240610
The interesting part is in the example
app admin.py file: ​https://github.com/ldeluigi/django-poc-20240610/blob/master/example/admin.py
I'd like to be able to do the same without having to write that ugly and cumbersome code which as a side effect has to alter the field names inside the model admin field
and fieldsets
lists disruptively, breaking the rest of the code not aware of the renaming of those from something
to something_local
.
In my PoC I can't take advantage of the read_only field on widgets because I can't define an abstract admin form class that works for every subclass, because its subclass define DateTimeFields with different names and not every one of them is read only potentially.
What I need is something that allows me to customize the display of readonly field based on their type that is only used if they are read only for whatever reason, including because of missing permissions.
Example of possible API to solve the problem:
class AbstractAdmin(admin.ModelAdmin): readonly_formfield_overrides = { DateTimeField: {'widget': MyCustomReadonlyWidget}, }
if widgets are not the best choice for readonly representation better work with functions:
def datetime_to_html(datetime: datetime | None) -> SafeText: if datetime is None: return mark_safe('never') return ... class AbstractAdmin(admin.ModelAdmin): readonly_formfield_overrides = { DateTimeField: datetime_to_html, }
Where readonly_formfield_overrides
would only be used for non-editable fields whose type one of the specified for customization
comment:10 by , 6 months ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Thank you for providing your insights here Ideluigi, this helps illustrate a potential approach if we want to take this forward.
From reading the ticket through, I believe before we try to develop a feature, we want to see a sample project/example of this issue in action. This will need to be clear what we see and what we want to see instead. This would be useful in testing but also in investigating workarounds and whether we have to make customizations in Django.
Based off that we can make an assessment on different approaches to achieve this and conclude if Django should make this easier.
Then we can start looking at updates to Django 🙂
If you want to discuss your approach, I recommend moving to the ​Django forum as there is a wider audience who might be able to give you feedback there.
comment:11 by , 6 months ago
Follow up in the forum: ​https://forum.djangoproject.com/t/feature-request-discussion-custom-rendering-for-readonly-fields-in-admin/32009
(for those who come by this thread)
Hi David.
This is interesting. I think I see where you're coming from but, could I ask you to put together an minimal project that demonstrates exactly the issue you're seeing — perhaps with some screenshots etc — so we can make sure we're 100% clear?
I'm not sure about an adjustment here. I think it would depend on exactly what's being proposed. Do you have a specific implementation idea?
It may be that there's a work-around.
bf39978a53f117ca02e9a0c78b76664a41a54745 introduced a check on the widget for a
read_only
attribute, when renderingAdminReadonlyField
If you were to override,
ModelAdmin.get_form()
to set a custom widget (withread_only=True
) on the required field, when the user did not have thechange
permission, you should 🤔 be able to leverage this to get the behaviour you need. (If you could put together that test project it would be easy enough to have a play with this...)Given these questions, and that #14802 was closed as
wontfix
, I'm going to close this asneedsinfo
right now. A sample project plus a proposal is probably needed to progress. With just a sample project, asking on the DevelopersMailingList might provide some help. Exploring the work-around would be the shortest route forward.