Ticket #8655: splithidden_8714.diff

File splithidden_8714.diff, 4.2 KB (added by bthomas, 7 years ago)

A new widget for rendering a split input field as multiple hidden fields

  • django/forms/fields.py

     
    2727from django.utils.encoding import smart_unicode, smart_str
    2828
    2929from util import ErrorList, ValidationError
    30 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput, TimeInput
     30from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateTimeInput, TimeInput, HiddenSplitDateTimeWidget
    3131from django.core.files.uploadedfile import SimpleUploadedFile as UploadedFile
    3232
    3333__all__ = (
     
    811811        self.widget.choices = self.choices
    812812
    813813class SplitDateTimeField(MultiValueField):
     814    hidden_widget = HiddenSplitDateTimeWidget
    814815    default_error_messages = {
    815816        'invalid_date': _(u'Enter a valid date.'),
    816817        'invalid_time': _(u'Enter a valid time.'),
  • django/forms/widgets.py

     
    255255            return data.getlist(name)
    256256        return data.get(name, None)
    257257
     258class 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
    258313class FileInput(Input):
    259314    input_type = 'file'
    260315    needs_multipart_form = True
     
    662717            return [value.date(), value.time().replace(microsecond=0)]
    663718        return [None, None]
    664719
     720class 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]
Back to Top