Opened 3 months ago

Closed 3 months ago

Last modified 3 months ago

#35192 closed Cleanup/optimization (needsinfo)

Support injecting custom context into widget templates

Reported by: Oxan van Leeuwen Owned by: nobody
Component: Forms Version: 5.0
Severity: Normal Keywords:
Cc: David Smith, Oxan van Leeuwen Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

The context available to widget templates is currently very rigid and does not allow any customization. For example, it's currently almost impossible to add an invalid CSS class to widgets that have errors.

I think my preferred solution would be to insert a call to a form renderer method in the callchain between BoundField.as_widget() and Widget.render(), which can be overridden by a custom renderer. It should receive the BoundField itself as an argument so that it has access to the current state. Something like the following sketch:

class BoundField:
    def as_widget(self, widget=None, attrs=None, only_initial=False):
        ... # leave current code as-is, except for last call to widget.render()
        return self.form.renderer.render_widget(
            field=self,
            widget=widget,
            name=self.html_initial_name if only_initial else self.html_name,
            value=value,
            attrs=attrs,
        )

class BaseRenderer:
    def render_widget(self, field, widget, name, value, attrs=None):
        # this can be overridden to add/change/remove `attrs`, or to render the widget in an entirely different way
        return widget.render(name, value, attrs)

Change History (3)

comment:1 by Mariusz Felisiak, 3 months ago

Cc: David Smith added

comment:2 by David Smith, 3 months ago

Resolution: needsinfo
Status: newclosed

it's currently almost impossible to add an invalid CSS class to widgets that have errors.

I agree that it is currently tricky to add invalid CSS to widgets (<inputs>) and would like to see this eased with Django itself. That was one of my conclusions when I attempted to write a tailwind styled form using just Django itself. See blog post.

I think there's a few different design options here, in addition to your suggestion above I see a couple of additional options.

  • A template filter/tag. This is the approach used by both django-widget-tweaks and django-crispy-forms.
  • Easing use of a custom BoundField. Currently you need to override each field's get_bound_field() to achieve this. Maybe this could also be set on the form renderer? This would also allow folk to make other customisations such as #35191 without adding a long list of options to the renderer.

It's probably worth starting a discussion on the django forum to gain wider views from the community. I'm happy to help with this discussion. As I think we need a wider discussion on the design I'll mark as 'needsinfo' for now.

comment:3 by Oxan van Leeuwen, 3 months ago

I think a custom BoundField could also work indeed. I'm by no means married to my proposal, it was just the most sensible thing I could come up with :)

I agree that it could be valuable to have a wider discussion about the design here, but unfortunately I don't have the bandwidth at the moment to drive such a discussion.

Note: See TracTickets for help on using tickets.
Back to Top