class MultiWidget(widgets, attrs=None)
[source]
A widget that is composed of multiple widgets. MultiWidget
works hand in hand with the MultiValueField
.
MultiWidget
has one required argument:
-
widgets
-
An iterable containing the widgets needed.
And one required method:
-
decompress(value)
[source] -
This method takes a single “compressed” value from the field and returns a list of “decompressed” values. The input value can be assumed valid, but not necessarily non-empty.
This method must be implemented by the subclass, and since the value may be empty, the implementation must be defensive.
The rationale behind “decompression” is that it is necessary to “split” the combined value of the form field into the values for each widget.
An example of this is how
SplitDateTimeWidget
turns adatetime
value into a list with date and time split into two separate values:from django.forms import MultiWidget class SplitDateTimeWidget(MultiWidget): # ... def decompress(self, value): if value: return [value.date(), value.time().replace(microsecond=0)] return [None, None]
Tip
Note that
MultiValueField
has a complementary methodcompress()
with the opposite responsibility - to combine cleaned values of all member fields into one.
Other methods that may be useful to override include:
-
render(name, value, attrs=None)
[source] -
Argument
value
is handled differently in this method from the subclasses ofWidget
because it has to figure out how to split a single value for display in multiple widgets.The
value
argument used when rendering can be one of two things:- A
list
. - A single value (e.g., a string) that is the “compressed” representation of a
list
of values.
If
value
is a list, the output ofrender()
will be a concatenation of rendered child widgets. Ifvalue
is not a list, it will first be processed by the methoddecompress()
to create the list and then rendered.When
render()
executes its HTML rendering, each value in the list is rendered with the corresponding widget – the first value is rendered in the first widget, the second value is rendered in the second widget, etc.Unlike in the single value widgets, method
render()
need not be implemented in the subclasses. - A
-
format_output(rendered_widgets)
[source] -
Given a list of rendered widgets (as strings), returns a Unicode string representing the HTML for the whole lot.
This hook allows you to format the HTML design of the widgets any way you’d like.
Here’s an example widget which subclasses MultiWidget
to display a date with the day, month, and year in different select boxes. This widget is intended to be used with a DateField
rather than a MultiValueField
, thus we have implemented value_from_datadict()
:
from datetime import date from django.forms import widgets class DateSelectorWidget(widgets.MultiWidget): def __init__(self, attrs=None): # create choices for days, months, years # example below, the rest snipped for brevity. years = [(year, year) for year in (2011, 2012, 2013)] _widgets = ( widgets.Select(attrs=attrs, choices=days), widgets.Select(attrs=attrs, choices=months), widgets.Select(attrs=attrs, choices=years), ) super(DateSelectorWidget, self).__init__(_widgets, attrs) def decompress(self, value): if value: return [value.day, value.month, value.year] return [None, None, None] def format_output(self, rendered_widgets): return ''.join(rendered_widgets) def value_from_datadict(self, data, files, name): datelist = [ widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)] try: D = date( day=int(datelist[0]), month=int(datelist[1]), year=int(datelist[2]), ) except ValueError: return '' else: return str(D)
The constructor creates several Select
widgets in a tuple. The super
class uses this tuple to setup the widget.
The format_output()
method is fairly vanilla here (in fact, it’s the same as what’s been implemented as the default for MultiWidget
), but the idea is that you could add custom HTML between the widgets should you wish.
The required method decompress()
breaks up a datetime.date
value into the day, month, and year values corresponding to each widget. Note how the method handles the case where value
is None
.
The default implementation of value_from_datadict()
returns a list of values corresponding to each Widget
. This is appropriate when using a MultiWidget
with a MultiValueField
, but since we want to use this widget with a DateField
which takes a single value, we have overridden this method to combine the data of all the subwidgets into a datetime.date
. The method extracts data from the POST
dictionary and constructs and validates the date. If it is valid, we return the string, otherwise, we return an empty string which will cause form.is_valid
to return False
.
Please login to continue.