Reputation: 1207
I am new at django.
I want to create a custom widget.
forms.py:
from project.widgets import MultiChoiceFilterWidget
class CustomSearchForm(FacetedSearchForm):
TEST_COLORS = [
u"Blau", u"Rot", u"Gelb"
]
color = forms.MultipleChoiceField(
label=_("Color"), choices=[(x, x) for x in TEST_COLORS],
widget=MultiChoiceFilterWidget, required=False)
widget.py:
class MultiChoiceFilterWidget(forms.widgets.CheckboxSelectMultiple):
template_name = 'project/widgets/filter.html'
option_template_name = 'ptoject/widgets/filter_option.html'
project/widgets/filter.html:
<h1>TEST</h1>
But it doesn't render the new template, instead it still renders the old way.
Can you give me some tips?
Upvotes: 21
Views: 22281
Reputation: 161
My approach, override render method and place your template in your regular templates dir:
class Records2RelatedFieldWidgetWrapper(RelatedFieldWidgetWrapper):
from django.template import Context, Template
from django.template.loader import get_template
template_name = 'records2/related_widget_wrapper_r2.html'
def render(self, name, value, attrs=None, renderer=None):
"""Render the widget as an HTML string."""
template = Template(get_template(self.template_name).template.source)
return template.render(Context(self.get_context(name, value, attrs)))
Upvotes: 0
Reputation: 51
If you only need to change the templates, redefining a complete widget is tedious for nothing. Since the widget is passed to the field as an instance, you can instanciate the base widget you want to use and change the templates afterward.
class CustomSearchForm(FacetedSearchForm):
TEST_COLORS = [
u"Blau", u"Rot", u"Gelb"
]
color = forms.MultipleChoiceField(
label=_("Color"), choices=[(x, x) for x in TEST_COLORS],
widget=forms.widgets.CheckboxSelectMultiple, required=False)
color.widget.template_name = 'project/widgets/filter.html'
color.widget.option_template_name = 'project/widgets/filter_option.html'
If you need to pass custom data to your templates, then you will have to create a custom widget.
Upvotes: 4
Reputation: 494
You will have to do the below steps to render your new widget template:
1) Add 'django.forms' to your INSTALLED_APPS;
2) Add FORM_RENDERER = 'django.forms.renderers.TemplatesSetting' to your settings.py.
More details : https://docs.djangoproject.com/en/2.0/ref/forms/renderers/#django.forms.renderers.TemplatesSetting
Upvotes: 43
Reputation: 23134
Django version < 1.11:
The widget must implement the render
method in order to render a different template:
from django.utils.safestring import mark_safe
from django.template.loader import render_to_string
class MultiChoiceFilterWidget(forms.widgets.CheckboxSelectMultiple):
template_name = 'project/widgets/filter.html'
def render(self, data):
...
Do stuff with data
...
return mark_safe(render_to_string(self.template_name))
In the renderer's documentation, we can find the following:
New in Django 1.11:
In older versions, widgets are rendered using Python. All APIs described in this document are new.
And by having a look at the widget source code and specifically on how the Input
widget extends the Widget
class, we can see that you would only need to customize your widget as follows:
class MultiChoiceFilterWidget(forms.widgets.CheckboxSelectMultiple):
template_name = 'project/widgets/filter.html'
Which is what you have already.
Upvotes: 19