| 268 | Other methods that may be useful to override include: |
| 269 | |
| 270 | .. method:: render(name, value, attrs=None) |
| 271 | |
| 272 | Argument ``value`` is handled differently in this method from the |
| 273 | subclasses of :class:`~Widget` because it has to figure out how to |
| 274 | split a single value for display in multiple widgets. |
| 275 | |
| 276 | The ``value`` argument used when rendering can be one of two things: |
| 277 | |
| 278 | * A ``list``. |
| 279 | * A single value (e.g., a string) that is the "compressed" representation |
| 280 | of a ``list`` of values. |
| 281 | |
| 282 | If `value` is a list, output of :meth:`~MultiWidget.render` will be a |
| 283 | concatenation of rendered child widgets. If `value` is not a list, it |
| 284 | will be first processed by the method :meth:`~MultiWidget.decompress()` |
| 285 | to create the list and then processed as above. |
| 286 | |
| 287 | In the second case -- i.e., if the value is *not* a list -- |
| 288 | ``render()`` will first decompress the value into a ``list`` before |
| 289 | rendering it. It does so by calling the ``decompress()`` method, which |
| 290 | :class:`MultiWidget`'s subclasses must implement (see above). |
| 291 | |
| 292 | When ``render()`` executes its HTML rendering, each value in the list |
| 293 | is rendered with the corresponding widget -- the first value is |
| 294 | rendered in the first widget, the second value is rendered in the |
| 295 | second widget, etc. |
| 296 | |
| 297 | Unlike in the single value widgets, method :meth:`~MultiWidget.render` |
| 298 | need not be implemented in the subclasses. |
| 299 | |
| 300 | .. method:: format_output(rendered_widgets) |
| 301 | |
| 302 | Given a list of rendered widgets (as strings), returns a Unicode string |
| 303 | representing the HTML for the whole lot. |
| 304 | |
| 305 | This hook allows you to format the HTML design of the widgets any way |
| 306 | you'd like. |
| 307 | |
| 308 | Here's an example widget which subclasses :class:`MultiWidget` to display |
| 309 | a date with the day, month, and year in different select boxes. This widget |
| 310 | is intended to be used with a :class:`~django.forms.DateField` rather than |
| 311 | a :class:`~django.forms.MultiValueField`, thus we have implemented |
| 312 | :meth:`~Widget.value_from_datadict`:: |
| 313 | |
| 314 | from datetime import date |
| 315 | from django.forms import widgets |
| 316 | |
| 317 | class DateSelectorWidget(widgets.MultiWidget): |
| 318 | def __init__(self, attrs=None): |
| 319 | # create choices for days, months, years |
| 320 | # example below, the rest snipped for brevity. |
| 321 | years = [(year, year) for year in (2011, 2012, 2013)] |
| 322 | _widgets = ( |
| 323 | widgets.Select(attrs=attrs, choices=days), |
| 324 | widgets.Select(attrs=attrs, choices=months), |
| 325 | widgets.Select(attrs=attrs, choices=years), |
| 326 | ) |
| 327 | super(DateSelectorWidget, self).__init__(_widgets, attrs) |
| 328 | |
| 329 | def decompress(self, value): |
| 330 | if value: |
| 331 | return [value.day, value.month, value.year] |
| 332 | return [None, None, None] |
| 333 | |
| 334 | def format_output(self, rendered_widgets): |
| 335 | return u''.join(rendered_widgets) |
| 336 | |
| 337 | def value_from_datadict(self, data, files, name): |
| 338 | datelist = [ |
| 339 | widget.value_from_datadict(data, files, name + '_%s' % i) |
| 340 | for i, widget in enumerate(self.widgets)] |
| 341 | try: |
| 342 | D = date(day=int(datelist[0]), month=int(datelist[1]), |
| 343 | year=int(datelist[2])) |
| 344 | except ValueError: |
| 345 | return '' |
| 346 | else: |
| 347 | return str(D) |
| 348 | |
| 349 | The constructor creates several :class:`Select` widgets in a tuple. The |
| 350 | ``super`` class uses this tuple to setup the widget. |
| 351 | |
| 352 | The :meth:`~MultiWidget.format_output` method is fairly vanilla here (in |
| 353 | fact, it's the same as what's been implemented as the default for |
| 354 | ``MultiWidget``), but the idea is that you could add custom HTML between |
| 355 | the widgets should you wish. |
| 356 | |
| 357 | The required method :meth:`~MultiWidget.decompress` breaks up a |
| 358 | ``datetime.date`` value into the day, month, and year values corresponding |
| 359 | to each widget. Note how the method handles the case where ``value`` is |
| 360 | ``None``. |
| 361 | |
| 362 | The default implementation of :meth:`~Widget.value_from_datadict` returns |
| 363 | a list of values corresponding to each ``Widget``. This is appropriate |
| 364 | when using a ``MultiWidget`` with a :class:`~django.forms.MultiValueField`, |
| 365 | but since we want to use this widget with a :class:`~django.forms.DateField` |
| 366 | which takes a single value, we have overridden this method to combine the |
| 367 | data of all the subwidgets into a ``datetimem.date``. The method extracts |
| 368 | data from the ``POST`` dictionary and constructs and validates the date. |
| 369 | If it is valid, we return the string, otherwise, we return an empty string |
| 370 | which will cause ``form.is_valid`` to return ``False``. |
555 | | ``MultiWidget`` |
556 | | ~~~~~~~~~~~~~~~ |
557 | | |
558 | | .. class:: MultiWidget |
559 | | |
560 | | Wrapper around multiple other widgets. You'll probably want to use this |
561 | | class with :class:`MultiValueField`. |
562 | | |
563 | | Its ``render()`` method is different than other widgets', because it has to |
564 | | figure out how to split a single value for display in multiple widgets. |
565 | | |
566 | | Subclasses may implement ``format_output``, which takes the list of |
567 | | rendered widgets and returns a string of HTML that formats them any way |
568 | | you'd like. |
569 | | |
570 | | The ``value`` argument used when rendering can be one of two things: |
571 | | |
572 | | * A ``list``. |
573 | | * A single value (e.g., a string) that is the "compressed" representation |
574 | | of a ``list`` of values. |
575 | | |
576 | | In the second case -- i.e., if the value is *not* a list -- ``render()`` |
577 | | will first decompress the value into a ``list`` before rendering it. It |
578 | | does so by calling the ``decompress()`` method, which |
579 | | :class:`MultiWidget`'s subclasses must implement. This method takes a |
580 | | single "compressed" value and returns a ``list``. An example of this is how |
581 | | :class:`SplitDateTimeWidget` turns a :class:`datetime` value into a list |
582 | | with date and time split into two seperate values:: |
583 | | |
584 | | class SplitDateTimeWidget(MultiWidget): |
585 | | |
586 | | # ... |
587 | | |
588 | | def decompress(self, value): |
589 | | if value: |
590 | | return [value.date(), value.time().replace(microsecond=0)] |
591 | | return [None, None] |
592 | | |
593 | | When ``render()`` executes its HTML rendering, each value in the list is |
594 | | rendered with the corresponding widget -- the first value is rendered in |
595 | | the first widget, the second value is rendered in the second widget, etc. |
596 | | |
597 | | :class:`MultiWidget` has one required argument: |
598 | | |
599 | | .. attribute:: MultiWidget.widgets |
600 | | |
601 | | An iterable containing the widgets needed. |
602 | | |