Hi everyone,
I recently started looking into Ticket #30577 (customizing read-only fields). While diving in, I noticed it has some concerned references to the recent fix for Ticket #35959 (specifically this part of commit d755a98).
It appears that the fix for #35959 had an unintended broader impact. By removing the getattr(widget, "read_only", False) workaround, it inadvertently affected third-party and custom code that relied on this undocumented behavior as a feature, since developers currently have no other way to render custom read-only widgets in the admin (see this comment and this post for more info) - reminds me of Hyrum’s Law.
So it looks like there’s a dilemma:
-
Removing the check entirely (current state): Fixes #35959, but affects widespread community reliance on
read_only=Truewithout providing an alternative. -
Reverting the check as-is: Restores the ecosystem but brings back the crash reported in #35959.
I wonder if we should revisit #35959 and handle this through a standard deprecation cycle:
-
Restore the
getattrcheck, but wrap it in atry...except (NotImplementedError, AttributeError):block. This defensively prevents the #35959 crashes while keeping custom read-only widgets functional for the time being. -
Deprecation Warning: Within that same block, issue a
RemovedInDjango70Warningfor any widget utilizing this behavior. -
Official API: Prioritize the design and implementation of an official, documented solution for read-only fields (Ticket #30577) so the community has a target to migrate toward - I can give it a shot, although I honestly haven’t dug much into #30577 yet - I got distracted figuring out #35959

-
Final Removal: Once the deprecation cycle concludes (and hopefully #30577 is concluded), we can remove the workaround once again.
To help make this second pass on #35959 concrete, I have put together a Draft PR demonstrating a possible mitigation and the warning here: Draft PR #21072
Cheers!