Skip to content

Allow Widgets templates to be specified in a FormRenderer class #172

Description

@nanorepublica

Code of Conduct

  • I agree to follow Django's Code of Conduct

Feature Description

Optionally allow Widget templates to be specified on a custom FormRenderer class. For example:

class MyFormRenderer(TemplatesSetting):
    form_template_name = "forms/my_form.html"
    field_template_name = "forms/my_field.html"
    # This is new - specific widget template
    select_template_name = "forms/my_widget.html#select"

Problem

We currently have the FormRenderer API which allows customisation of form rendering a variety of levels of specificity (settings, form class, form instance) via the following templates:

form_template_name = "django/forms/div.html"
formset_template_name = "django/forms/formsets/div.html"
field_template_name = "django/forms/field.html"

Currently to override Widgets at a global level, requires monkey-patching the template_name class attribute which then means there are possible clashes and bugs between the user facing styles and admin styles.

Request or proposal

proposal

Additional Details

No response

Implementation Suggestions

Looking at the base Widget class it has two methods that deal with rendering. render and _render

I would propose adding a get_template_name method instead of calling self.template_name directly in this method, which would take a renderer argument. Off the top of my head something like this:

class Widget:
    
    def get_template_name(self, renderer, template_name):
          renderer_widget_attr_name = f"{self.__class__.__name__}_template_name"
          renderer_template_name = getattr(renderer, renderer_widget_attr_name, None)
          if renderer_template_name:
               return renderer_template_name
          return template_name
   
    def _render(self, template_name, context, renderer=None):
        if renderer is None:
            renderer = get_default_renderer()
        template_name = self.get_template_name(renderer, template_name)
        return mark_safe(renderer.render(template_name, context))

Perhaps there is a bit of a refactor of render and _render, but that is not necessary.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    Idea

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions