django / django/new-features

Allow Widgets templates to be specified in a FormRenderer class

Open
#172 7 comments 5 reactions 0 assignees View on GitHub
Dominant language
No language data
Stars
188
Forks
7
PR merge metrics
No merged PRs in 30d

Description

### Code of Conduct

- [x] 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:

```py
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:

```py
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.

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.