| 258 | class SplitHiddenInput(HiddenInput): |
| 259 | """ |
| 260 | A widget that handles <input type="hidden"> for fields that are split into |
| 261 | multiple values. Meant to be a hidden replacement for MultiWidget. |
| 262 | """ |
| 263 | def __init__(self, widgets, attrs=None): |
| 264 | self.widgets = [isinstance(w, type) and w() or w for w in widgets] |
| 265 | super(SplitHiddenInput, self).__init__(attrs) |
| 266 | |
| 267 | def render(self, name, value, attrs=None): |
| 268 | # value is a list of values, each corresponding to a widget |
| 269 | # in self.widgets. |
| 270 | if not isinstance(value, list): |
| 271 | value = self.decompress(value) |
| 272 | output = [] |
| 273 | final_attrs = self.build_attrs(attrs, type=self.input_type) |
| 274 | id_ = final_attrs.get('id', None) |
| 275 | for i, widget in enumerate(self.widgets): |
| 276 | try: |
| 277 | widget_value = value[i] |
| 278 | except IndexError: |
| 279 | widget_value = None |
| 280 | if id_: |
| 281 | final_attrs = dict(final_attrs, id='%s_%s' % (id_, i)) |
| 282 | output.append(widget.render(name + '_%s' % i, widget_value, final_attrs)) |
| 283 | return mark_safe(self.format_output(output)) |
| 284 | |
| 285 | def id_for_label(self, id_): |
| 286 | # See the comment for RadioSelect.id_for_label() |
| 287 | if id_: |
| 288 | id_ += '_0' |
| 289 | return id_ |
| 290 | id_for_label = classmethod(id_for_label) |
| 291 | |
| 292 | def value_from_datadict(self, data, files, name): |
| 293 | return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)] |
| 294 | |
| 295 | def format_output(self, rendered_widgets): |
| 296 | """ |
| 297 | Given a list of rendered widgets (as strings), returns a Unicode string |
| 298 | representing the HTML for the whole lot. |
| 299 | |
| 300 | This hook allows you to format the HTML design of the widgets, if |
| 301 | needed. |
| 302 | """ |
| 303 | return u''.join(rendered_widgets) |
| 304 | |
| 305 | def decompress(self, value): |
| 306 | """ |
| 307 | Returns a list of decompressed values for the given compressed value. |
| 308 | The given value can be assumed to be valid, but not necessarily |
| 309 | non-empty. |
| 310 | """ |
| 311 | raise NotImplementedError('Subclasses must implement this method.') |
| 312 | |
| 720 | class HiddenSplitDateTimeWidget(SplitHiddenInput): |
| 721 | """ |
| 722 | A Widget that splits datetime input into two <input type="text"> boxes. |
| 723 | """ |
| 724 | def __init__(self, attrs=None): |
| 725 | widgets = (HiddenInput(attrs=attrs), HiddenInput(attrs=attrs)) |
| 726 | super(HiddenSplitDateTimeWidget, self).__init__(widgets, attrs) |
| 727 | |
| 728 | def decompress(self, value): |
| 729 | if value: |
| 730 | return [value.date(), value.time().replace(microsecond=0)] |
| 731 | return [None, None] |