[Django] #35987: ErrorList.copy() reverts to default renderer

13 views
Skip to first unread message

Django

unread,
Dec 9, 2024, 5:36:06 AM12/9/24
to django-...@googlegroups.com
#35987: ErrorList.copy() reverts to default renderer
----------------------------------------+------------------------------
Reporter: Adam Johnson | Owner: Adam Johnson
Type: Bug | Status: assigned
Component: Forms | Version: dev
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
----------------------------------------+------------------------------
When an `ErrorList` is copied, it loses track of any custom renderer,
reverting to the default one. Practically, this means custom styles are
not applied to non-field errors when rendering a whole form.

For example, I wrote a custom renderer that swaps some templates like so:

{{{#!python
from django import forms
from django.forms.renderers import TemplatesSetting

from django.template.exceptions import TemplateDoesNotExist


class CustomRenderer(TemplatesSetting):
def get_template(self, template_name):
if template_name.startswith("django/forms/"):
# Load our custom version from "custom/forms/" if it exists
our_template =
f"custom/{template_name.removeprefix('django/')}"
try:
return super().get_template(our_template)
except TemplateDoesNotExist:
pass
return super().get_template(template_name)


class MyForm(forms.Form):
default_renderer = CustomRenderer()
}}}

The custom error list template uses some CSS utility classes from
Tailwind, like `text-red-600`:

{{{#!htmldjango
{% if errors %}<ul class="text-red-600">{% for error in errors %}<li>{{
error }}</li>{% endfor %}</ul>{% endif %}
}}}

Creating a form with a non-field error and rendering those errors uses the
custom template:

{{{#!pycon
In [1]: from example.forms import MyForm
...:
...: form = MyForm({})
...: form.full_clean()
...: form.add_error(None, "Test error")

In [2]: form.non_field_errors().render()
Out[2]: '<ul class="text-red-600"><li>Test error</li></ul>'
}}}

But rendering the whole form reverts to the default template, from the
default renderer:

{{{#!pycon
In [3]: form.render()
Out[3]: '<ul class="errorlist nonfield"><li>Test error</li></ul>\n\n
<div></div>'
}}}

This occurs because the `ErrorList` is copied in `Form.get_context()`:

https://github.com/django/django/blob/1860a1afc9ac20750f932e8e0a94b32d096f2848/django/forms/forms.py#L225

The fix would be to also copy over `renderer` in `ErrorList.copy()`:

https://github.com/django/django/blob/1860a1afc9ac20750f932e8e0a94b32d096f2848/django/forms/utils.py#L165

I think this has probably been an issue ever since a custom renderer
became possible in #31026.
--
Ticket URL: <https://code.djangoproject.com/ticket/35987>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Dec 9, 2024, 5:55:34 AM12/9/24
to django-...@googlegroups.com
#35987: ErrorList.copy() reverts to default renderer
------------------------------+----------------------------------------
Reporter: Adam Johnson | Owner: Adam Johnson
Type: Bug | Status: assigned
Component: Forms | Version: dev
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+----------------------------------------
Changes (by Adam Johnson):

* has_patch: 0 => 1

--
Ticket URL: <https://code.djangoproject.com/ticket/35987#comment:1>

Django

unread,
Dec 9, 2024, 6:51:08 AM12/9/24
to django-...@googlegroups.com
#35987: ErrorList.copy() reverts to default renderer
------------------------------+----------------------------------------
Reporter: Adam Johnson | Owner: Adam Johnson
Type: Bug | Status: assigned
Component: Forms | Version: dev
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
------------------------------+----------------------------------------
Changes (by Sarah Boyce):

* stage: Unreviewed => Accepted

Comment:

Thank you!
--
Ticket URL: <https://code.djangoproject.com/ticket/35987#comment:2>

Django

unread,
Dec 9, 2024, 11:59:55 AM12/9/24
to django-...@googlegroups.com
#35987: ErrorList.copy() reverts to default renderer
-------------------------------------+-------------------------------------
Reporter: Adam Johnson | Owner: Adam
| Johnson
Type: Bug | Status: assigned
Component: Forms | Version: dev
Severity: Normal | Resolution:
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* stage: Accepted => Ready for checkin

--
Ticket URL: <https://code.djangoproject.com/ticket/35987#comment:3>

Django

unread,
Dec 10, 2024, 6:15:02 AM12/10/24
to django-...@googlegroups.com
#35987: ErrorList.copy() reverts to default renderer
-------------------------------------+-------------------------------------
Reporter: Adam Johnson | Owner: Adam
| Johnson
Type: Bug | Status: closed
Component: Forms | Version: dev
Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce <42296566+sarahboyce@…>):

* resolution: => fixed
* status: assigned => closed

Comment:

In [changeset:"4806c42efac790dd65bc890b85904df7bdeb1309" 4806c42]:
{{{#!CommitTicketReference repository=""
revision="4806c42efac790dd65bc890b85904df7bdeb1309"
Fixed #35987 -- Made ErrorList.copy() copy the renderer attribute.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35987#comment:4>

Django

unread,
Dec 10, 2024, 6:15:02 AM12/10/24
to django-...@googlegroups.com
#35987: ErrorList.copy() reverts to default renderer
-------------------------------------+-------------------------------------
Reporter: Adam Johnson | Owner: Adam
| Johnson
Type: Bug | Status: closed
Component: Forms | Version: dev
Severity: Normal | Resolution: fixed
Keywords: | Triage Stage: Ready for
| checkin
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Sarah Boyce <42296566+sarahboyce@…>):

In [changeset:"5e998d717f7b4220a1728bd49b66ca0162e2a6cb" 5e998d71]:
{{{#!CommitTicketReference repository=""
revision="5e998d717f7b4220a1728bd49b66ca0162e2a6cb"
Refs #35987 -- Added extra tests for ErrorList and ErrorDict copy methods.
}}}
--
Ticket URL: <https://code.djangoproject.com/ticket/35987#comment:5>
Reply all
Reply to author
Forward
0 new messages