build_widget_attrs calls self.errors

I’m playing with the django 5.0 upgrade, and I’m finding that I have some forms failing to render. Looking closer, I notice that build_widget_attrs in boundfield.py refers to self.errors.

Line 290:

    if not widget.is_hidden and self.errors:
        attrs["aria-invalid"] = "true"

self.errors is a property that can force a form clean(), which may not be what you want, when GETting a form.

Are we to assume that our custom form clean() functions can be called during a GET request as well as after POST?

Hi @steve-bradshaw-c, welcome :wave:

full_clean() is a no-op for unbound forms:

        if not self.is_bound:  # Stop further processing.
            return

(forms.py:317)

… so there’s no harm in it being called, I think :thinking:

But also, the .errors property is not new there, and is called during form rendering in Django 4.2 as well. (in BaseForm.get_context()).

Maybe there’s some issue though… if you could reduce to a minimal example showing a difference that would be useful (and make it easier to say more)

Thanks.

//cc @smithdc1

Also note that it is possible to bind a form with data supplied during a GET request - or even completely outside the context of an HTTP request (think Celery tasks or management commands that pull data from external sources).

So yes, not all forms are bound with data as the result of a POST, and so the clean function should run regardless of the request being made (or not made) to supply data to the form.

I believe the call to .errors is new in build_widget_attrs - I checked it against 4.2.8 before posting. In my test case is_bound is true, triggering my model’s clean() function

It breaks when rendering a ModelForm on a template. The ModelForm is not the Model where the clean() function is, but the Model for the ModelForm is a child of the clean()-broke-Model. If I remove this call, it works. Bizarrely, if I don’t remove it and put a breakpoint on the call to build_widget_attrs and inspect the boundfield object (possibly calculating some lazy values) and continue, the page renders fine as well.

It’s difficult to provide an example because I don’t know exactly what’s happening. It seems a clean function on an related model is being run during rendering of a ModelField. I can fix it by shoring up the validation on that clean function, but it still feels a little strange.

Hey @steve-bradshaw-c, yes, as described it sounds a little strange…

I imagine it’s difficult to reproduce, but if you could provide even a sample project showing a regression here (and open a ticket :wink:) we’d be able to investigate.

(Without that it’s hard to say anything much… :grimacing:)