diff options
Diffstat (limited to 'lib/python2.7/site-packages/django/forms/widgets.py')
-rw-r--r-- | lib/python2.7/site-packages/django/forms/widgets.py | 869 |
1 files changed, 0 insertions, 869 deletions
diff --git a/lib/python2.7/site-packages/django/forms/widgets.py b/lib/python2.7/site-packages/django/forms/widgets.py deleted file mode 100644 index cf68bac..0000000 --- a/lib/python2.7/site-packages/django/forms/widgets.py +++ /dev/null @@ -1,869 +0,0 @@ -""" -HTML Widget classes -""" - -from __future__ import absolute_import, unicode_literals - -import copy -from itertools import chain -import warnings - -from django.conf import settings -from django.forms.util import flatatt, to_current_timezone -from django.utils.datastructures import MultiValueDict, MergeDict -from django.utils.html import conditional_escape, format_html -from django.utils.translation import ugettext_lazy -from django.utils.encoding import force_text, python_2_unicode_compatible -from django.utils.safestring import mark_safe -from django.utils import datetime_safe, formats, six -from django.utils.six.moves.urllib.parse import urljoin - -__all__ = ( - 'Media', 'MediaDefiningClass', 'Widget', 'TextInput', - 'EmailInput', 'URLInput', 'NumberInput', 'PasswordInput', - 'HiddenInput', 'MultipleHiddenInput', 'ClearableFileInput', - 'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput', - 'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', - 'CheckboxSelectMultiple', 'MultiWidget', - 'SplitDateTimeWidget', -) - -MEDIA_TYPES = ('css','js') - -@python_2_unicode_compatible -class Media(object): - def __init__(self, media=None, **kwargs): - if media: - media_attrs = media.__dict__ - else: - media_attrs = kwargs - - self._css = {} - self._js = [] - - for name in MEDIA_TYPES: - getattr(self, 'add_' + name)(media_attrs.get(name, None)) - - # Any leftover attributes must be invalid. - # if media_attrs != {}: - # raise TypeError("'class Media' has invalid attribute(s): %s" % ','.join(media_attrs.keys())) - - def __str__(self): - return self.render() - - def render(self): - return mark_safe('\n'.join(chain(*[getattr(self, 'render_' + name)() for name in MEDIA_TYPES]))) - - def render_js(self): - return [format_html('<script type="text/javascript" src="{0}"></script>', self.absolute_path(path)) for path in self._js] - - def render_css(self): - # To keep rendering order consistent, we can't just iterate over items(). - # We need to sort the keys, and iterate over the sorted list. - media = sorted(self._css.keys()) - return chain(*[ - [format_html('<link href="{0}" type="text/css" media="{1}" rel="stylesheet" />', self.absolute_path(path), medium) - for path in self._css[medium]] - for medium in media]) - - def absolute_path(self, path, prefix=None): - if path.startswith(('http://', 'https://', '/')): - return path - if prefix is None: - if settings.STATIC_URL is None: - # backwards compatibility - prefix = settings.MEDIA_URL - else: - prefix = settings.STATIC_URL - return urljoin(prefix, path) - - def __getitem__(self, name): - "Returns a Media object that only contains media of the given type" - if name in MEDIA_TYPES: - return Media(**{str(name): getattr(self, '_' + name)}) - raise KeyError('Unknown media type "%s"' % name) - - def add_js(self, data): - if data: - for path in data: - if path not in self._js: - self._js.append(path) - - def add_css(self, data): - if data: - for medium, paths in data.items(): - for path in paths: - if not self._css.get(medium) or path not in self._css[medium]: - self._css.setdefault(medium, []).append(path) - - def __add__(self, other): - combined = Media() - for name in MEDIA_TYPES: - getattr(combined, 'add_' + name)(getattr(self, '_' + name, None)) - getattr(combined, 'add_' + name)(getattr(other, '_' + name, None)) - return combined - -def media_property(cls): - def _media(self): - # Get the media property of the superclass, if it exists - sup_cls = super(cls, self) - try: - base = sup_cls.media - except AttributeError: - base = Media() - - # Get the media definition for this class - definition = getattr(cls, 'Media', None) - if definition: - extend = getattr(definition, 'extend', True) - if extend: - if extend == True: - m = base - else: - m = Media() - for medium in extend: - m = m + base[medium] - return m + Media(definition) - else: - return Media(definition) - else: - return base - return property(_media) - -class MediaDefiningClass(type): - "Metaclass for classes that can have media definitions" - def __new__(cls, name, bases, attrs): - new_class = super(MediaDefiningClass, cls).__new__(cls, name, bases, - attrs) - if 'media' not in attrs: - new_class.media = media_property(new_class) - return new_class - -@python_2_unicode_compatible -class SubWidget(object): - """ - Some widgets are made of multiple HTML elements -- namely, RadioSelect. - This is a class that represents the "inner" HTML element of a widget. - """ - def __init__(self, parent_widget, name, value, attrs, choices): - self.parent_widget = parent_widget - self.name, self.value = name, value - self.attrs, self.choices = attrs, choices - - def __str__(self): - args = [self.name, self.value, self.attrs] - if self.choices: - args.append(self.choices) - return self.parent_widget.render(*args) - -class Widget(six.with_metaclass(MediaDefiningClass)): - is_hidden = False # Determines whether this corresponds to an <input type="hidden">. - needs_multipart_form = False # Determines does this widget need multipart form - is_localized = False - is_required = False - - def __init__(self, attrs=None): - if attrs is not None: - self.attrs = attrs.copy() - else: - self.attrs = {} - - def __deepcopy__(self, memo): - obj = copy.copy(self) - obj.attrs = self.attrs.copy() - memo[id(self)] = obj - return obj - - def subwidgets(self, name, value, attrs=None, choices=()): - """ - Yields all "subwidgets" of this widget. Used only by RadioSelect to - allow template access to individual <input type="radio"> buttons. - - Arguments are the same as for render(). - """ - yield SubWidget(self, name, value, attrs, choices) - - def render(self, name, value, attrs=None): - """ - Returns this Widget rendered as HTML, as a Unicode string. - - The 'value' given is not guaranteed to be valid input, so subclass - implementations should program defensively. - """ - raise NotImplementedError - - def build_attrs(self, extra_attrs=None, **kwargs): - "Helper function for building an attribute dictionary." - attrs = dict(self.attrs, **kwargs) - if extra_attrs: - attrs.update(extra_attrs) - return attrs - - def value_from_datadict(self, data, files, name): - """ - Given a dictionary of data and this widget's name, returns the value - of this widget. Returns None if it's not provided. - """ - return data.get(name, None) - - def id_for_label(self, id_): - """ - Returns the HTML ID attribute of this Widget for use by a <label>, - given the ID of the field. Returns None if no ID is available. - - This hook is necessary because some widgets have multiple HTML - elements and, thus, multiple IDs. In that case, this method should - return an ID value that corresponds to the first ID in the widget's - tags. - """ - return id_ - -class Input(Widget): - """ - Base class for all <input> widgets (except type='checkbox' and - type='radio', which are special). - """ - input_type = None # Subclasses must define this. - - def _format_value(self, value): - if self.is_localized: - return formats.localize_input(value) - return value - - def render(self, name, value, attrs=None): - if value is None: - value = '' - final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) - if value != '': - # Only add the 'value' attribute if a value is non-empty. - final_attrs['value'] = force_text(self._format_value(value)) - return format_html('<input{0} />', flatatt(final_attrs)) - - -class TextInput(Input): - input_type = 'text' - - def __init__(self, attrs=None): - if attrs is not None: - self.input_type = attrs.pop('type', self.input_type) - super(TextInput, self).__init__(attrs) - - -class NumberInput(TextInput): - input_type = 'number' - - -class EmailInput(TextInput): - input_type = 'email' - - -class URLInput(TextInput): - input_type = 'url' - - -class PasswordInput(TextInput): - input_type = 'password' - - def __init__(self, attrs=None, render_value=False): - super(PasswordInput, self).__init__(attrs) - self.render_value = render_value - - def render(self, name, value, attrs=None): - if not self.render_value: value=None - return super(PasswordInput, self).render(name, value, attrs) - -class HiddenInput(Input): - input_type = 'hidden' - is_hidden = True - -class MultipleHiddenInput(HiddenInput): - """ - A widget that handles <input type="hidden"> for fields that have a list - of values. - """ - def __init__(self, attrs=None, choices=()): - super(MultipleHiddenInput, self).__init__(attrs) - # choices can be any iterable - self.choices = choices - - def render(self, name, value, attrs=None, choices=()): - if value is None: value = [] - final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) - id_ = final_attrs.get('id', None) - inputs = [] - for i, v in enumerate(value): - input_attrs = dict(value=force_text(v), **final_attrs) - if id_: - # An ID attribute was given. Add a numeric index as a suffix - # so that the inputs don't all have the same ID attribute. - input_attrs['id'] = '%s_%s' % (id_, i) - inputs.append(format_html('<input{0} />', flatatt(input_attrs))) - return mark_safe('\n'.join(inputs)) - - def value_from_datadict(self, data, files, name): - if isinstance(data, (MultiValueDict, MergeDict)): - return data.getlist(name) - return data.get(name, None) - -class FileInput(Input): - input_type = 'file' - needs_multipart_form = True - - def render(self, name, value, attrs=None): - return super(FileInput, self).render(name, None, attrs=attrs) - - def value_from_datadict(self, data, files, name): - "File widgets take data from FILES, not POST" - return files.get(name, None) - - -FILE_INPUT_CONTRADICTION = object() - -class ClearableFileInput(FileInput): - initial_text = ugettext_lazy('Currently') - input_text = ugettext_lazy('Change') - clear_checkbox_label = ugettext_lazy('Clear') - - template_with_initial = '%(initial_text)s: %(initial)s %(clear_template)s<br />%(input_text)s: %(input)s' - - template_with_clear = '%(clear)s <label for="%(clear_checkbox_id)s">%(clear_checkbox_label)s</label>' - - url_markup_template = '<a href="{0}">{1}</a>' - - def clear_checkbox_name(self, name): - """ - Given the name of the file input, return the name of the clear checkbox - input. - """ - return name + '-clear' - - def clear_checkbox_id(self, name): - """ - Given the name of the clear checkbox input, return the HTML id for it. - """ - return name + '_id' - - def render(self, name, value, attrs=None): - substitutions = { - 'initial_text': self.initial_text, - 'input_text': self.input_text, - 'clear_template': '', - 'clear_checkbox_label': self.clear_checkbox_label, - } - template = '%(input)s' - substitutions['input'] = super(ClearableFileInput, self).render(name, value, attrs) - - if value and hasattr(value, "url"): - template = self.template_with_initial - substitutions['initial'] = format_html(self.url_markup_template, - value.url, - force_text(value)) - if not self.is_required: - checkbox_name = self.clear_checkbox_name(name) - checkbox_id = self.clear_checkbox_id(checkbox_name) - substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name) - substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id) - substitutions['clear'] = CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id}) - substitutions['clear_template'] = self.template_with_clear % substitutions - - return mark_safe(template % substitutions) - - def value_from_datadict(self, data, files, name): - upload = super(ClearableFileInput, self).value_from_datadict(data, files, name) - if not self.is_required and CheckboxInput().value_from_datadict( - data, files, self.clear_checkbox_name(name)): - if upload: - # If the user contradicts themselves (uploads a new file AND - # checks the "clear" checkbox), we return a unique marker - # object that FileField will turn into a ValidationError. - return FILE_INPUT_CONTRADICTION - # False signals to clear any existing value, as opposed to just None - return False - return upload - -class Textarea(Widget): - def __init__(self, attrs=None): - # The 'rows' and 'cols' attributes are required for HTML correctness. - default_attrs = {'cols': '40', 'rows': '10'} - if attrs: - default_attrs.update(attrs) - super(Textarea, self).__init__(default_attrs) - - def render(self, name, value, attrs=None): - if value is None: value = '' - final_attrs = self.build_attrs(attrs, name=name) - return format_html('<textarea{0}>\r\n{1}</textarea>', - flatatt(final_attrs), - force_text(value)) - - -class DateInput(TextInput): - def __init__(self, attrs=None, format=None): - super(DateInput, self).__init__(attrs) - if format: - self.format = format - self.manual_format = True - else: - self.format = formats.get_format('DATE_INPUT_FORMATS')[0] - self.manual_format = False - - def _format_value(self, value): - if self.is_localized and not self.manual_format: - return formats.localize_input(value) - elif hasattr(value, 'strftime'): - value = datetime_safe.new_date(value) - return value.strftime(self.format) - return value - - -class DateTimeInput(TextInput): - def __init__(self, attrs=None, format=None): - super(DateTimeInput, self).__init__(attrs) - if format: - self.format = format - self.manual_format = True - else: - self.format = formats.get_format('DATETIME_INPUT_FORMATS')[0] - self.manual_format = False - - def _format_value(self, value): - if self.is_localized and not self.manual_format: - return formats.localize_input(value) - elif hasattr(value, 'strftime'): - value = datetime_safe.new_datetime(value) - return value.strftime(self.format) - return value - - -class TimeInput(TextInput): - def __init__(self, attrs=None, format=None): - super(TimeInput, self).__init__(attrs) - if format: - self.format = format - self.manual_format = True - else: - self.format = formats.get_format('TIME_INPUT_FORMATS')[0] - self.manual_format = False - - def _format_value(self, value): - if self.is_localized and not self.manual_format: - return formats.localize_input(value) - elif hasattr(value, 'strftime'): - return value.strftime(self.format) - return value - - -# Defined at module level so that CheckboxInput is picklable (#17976) -def boolean_check(v): - return not (v is False or v is None or v == '') - - -class CheckboxInput(Widget): - def __init__(self, attrs=None, check_test=None): - super(CheckboxInput, self).__init__(attrs) - # check_test is a callable that takes a value and returns True - # if the checkbox should be checked for that value. - self.check_test = boolean_check if check_test is None else check_test - - def render(self, name, value, attrs=None): - final_attrs = self.build_attrs(attrs, type='checkbox', name=name) - if self.check_test(value): - final_attrs['checked'] = 'checked' - if not (value is True or value is False or value is None or value == ''): - # Only add the 'value' attribute if a value is non-empty. - final_attrs['value'] = force_text(value) - return format_html('<input{0} />', flatatt(final_attrs)) - - def value_from_datadict(self, data, files, name): - if name not in data: - # A missing value means False because HTML form submission does not - # send results for unselected checkboxes. - return False - value = data.get(name) - # Translate true and false strings to boolean values. - values = {'true': True, 'false': False} - if isinstance(value, six.string_types): - value = values.get(value.lower(), value) - return bool(value) - - -class Select(Widget): - allow_multiple_selected = False - - def __init__(self, attrs=None, choices=()): - super(Select, self).__init__(attrs) - # choices can be any iterable, but we may need to render this widget - # multiple times. Thus, collapse it into a list so it can be consumed - # more than once. - self.choices = list(choices) - - def render(self, name, value, attrs=None, choices=()): - if value is None: value = '' - final_attrs = self.build_attrs(attrs, name=name) - output = [format_html('<select{0}>', flatatt(final_attrs))] - options = self.render_options(choices, [value]) - if options: - output.append(options) - output.append('</select>') - return mark_safe('\n'.join(output)) - - def render_option(self, selected_choices, option_value, option_label): - option_value = force_text(option_value) - if option_value in selected_choices: - selected_html = mark_safe(' selected="selected"') - if not self.allow_multiple_selected: - # Only allow for a single selection. - selected_choices.remove(option_value) - else: - selected_html = '' - return format_html('<option value="{0}"{1}>{2}</option>', - option_value, - selected_html, - force_text(option_label)) - - def render_options(self, choices, selected_choices): - # Normalize to strings. - selected_choices = set(force_text(v) for v in selected_choices) - output = [] - for option_value, option_label in chain(self.choices, choices): - if isinstance(option_label, (list, tuple)): - output.append(format_html('<optgroup label="{0}">', force_text(option_value))) - for option in option_label: - output.append(self.render_option(selected_choices, *option)) - output.append('</optgroup>') - else: - output.append(self.render_option(selected_choices, option_value, option_label)) - return '\n'.join(output) - -class NullBooleanSelect(Select): - """ - A Select Widget intended to be used with NullBooleanField. - """ - def __init__(self, attrs=None): - choices = (('1', ugettext_lazy('Unknown')), - ('2', ugettext_lazy('Yes')), - ('3', ugettext_lazy('No'))) - super(NullBooleanSelect, self).__init__(attrs, choices) - - def render(self, name, value, attrs=None, choices=()): - try: - value = {True: '2', False: '3', '2': '2', '3': '3'}[value] - except KeyError: - value = '1' - return super(NullBooleanSelect, self).render(name, value, attrs, choices) - - def value_from_datadict(self, data, files, name): - value = data.get(name, None) - return {'2': True, - True: True, - 'True': True, - '3': False, - 'False': False, - False: False}.get(value, None) - - -class SelectMultiple(Select): - allow_multiple_selected = True - - def render(self, name, value, attrs=None, choices=()): - if value is None: value = [] - final_attrs = self.build_attrs(attrs, name=name) - output = [format_html('<select multiple="multiple"{0}>', flatatt(final_attrs))] - options = self.render_options(choices, value) - if options: - output.append(options) - output.append('</select>') - return mark_safe('\n'.join(output)) - - def value_from_datadict(self, data, files, name): - if isinstance(data, (MultiValueDict, MergeDict)): - return data.getlist(name) - return data.get(name, None) - - -@python_2_unicode_compatible -class ChoiceInput(SubWidget): - """ - An object used by ChoiceFieldRenderer that represents a single - <input type='$input_type'>. - """ - input_type = None # Subclasses must define this - - def __init__(self, name, value, attrs, choice, index): - self.name = name - self.value = value - self.attrs = attrs - self.choice_value = force_text(choice[0]) - self.choice_label = force_text(choice[1]) - self.index = index - - def __str__(self): - return self.render() - - def render(self, name=None, value=None, attrs=None, choices=()): - name = name or self.name - value = value or self.value - attrs = attrs or self.attrs - if 'id' in self.attrs: - label_for = format_html(' for="{0}_{1}"', self.attrs['id'], self.index) - else: - label_for = '' - return format_html('<label{0}>{1} {2}</label>', label_for, self.tag(), self.choice_label) - - def is_checked(self): - return self.value == self.choice_value - - def tag(self): - if 'id' in self.attrs: - self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index) - final_attrs = dict(self.attrs, type=self.input_type, name=self.name, value=self.choice_value) - if self.is_checked(): - final_attrs['checked'] = 'checked' - return format_html('<input{0} />', flatatt(final_attrs)) - - -class RadioChoiceInput(ChoiceInput): - input_type = 'radio' - - def __init__(self, *args, **kwargs): - super(RadioChoiceInput, self).__init__(*args, **kwargs) - self.value = force_text(self.value) - - -class RadioInput(RadioChoiceInput): - def __init__(self, *args, **kwargs): - msg = "RadioInput has been deprecated. Use RadioChoiceInput instead." - warnings.warn(msg, PendingDeprecationWarning, stacklevel=2) - super(RadioInput, self).__init__(*args, **kwargs) - - -class CheckboxChoiceInput(ChoiceInput): - input_type = 'checkbox' - - def __init__(self, *args, **kwargs): - super(CheckboxChoiceInput, self).__init__(*args, **kwargs) - self.value = set(force_text(v) for v in self.value) - - def is_checked(self): - return self.choice_value in self.value - - -@python_2_unicode_compatible -class ChoiceFieldRenderer(object): - """ - An object used by RadioSelect to enable customization of radio widgets. - """ - - choice_input_class = None - - def __init__(self, name, value, attrs, choices): - self.name = name - self.value = value - self.attrs = attrs - self.choices = choices - - def __iter__(self): - for i, choice in enumerate(self.choices): - yield self.choice_input_class(self.name, self.value, self.attrs.copy(), choice, i) - - def __getitem__(self, idx): - choice = self.choices[idx] # Let the IndexError propogate - return self.choice_input_class(self.name, self.value, self.attrs.copy(), choice, idx) - - def __str__(self): - return self.render() - - def render(self): - """ - Outputs a <ul> for this set of choice fields. - If an id was given to the field, it is applied to the <ul> (each - item in the list will get an id of `$id_$i`). - """ - id_ = self.attrs.get('id', None) - start_tag = format_html('<ul id="{0}">', id_) if id_ else '<ul>' - output = [start_tag] - for widget in self: - output.append(format_html('<li>{0}</li>', force_text(widget))) - output.append('</ul>') - return mark_safe('\n'.join(output)) - - -class RadioFieldRenderer(ChoiceFieldRenderer): - choice_input_class = RadioChoiceInput - - -class CheckboxFieldRenderer(ChoiceFieldRenderer): - choice_input_class = CheckboxChoiceInput - - -class RendererMixin(object): - renderer = None # subclasses must define this - _empty_value = None - - def __init__(self, *args, **kwargs): - # Override the default renderer if we were passed one. - renderer = kwargs.pop('renderer', None) - if renderer: - self.renderer = renderer - super(RendererMixin, self).__init__(*args, **kwargs) - - def subwidgets(self, name, value, attrs=None, choices=()): - for widget in self.get_renderer(name, value, attrs, choices): - yield widget - - def get_renderer(self, name, value, attrs=None, choices=()): - """Returns an instance of the renderer.""" - if value is None: - value = self._empty_value - final_attrs = self.build_attrs(attrs) - choices = list(chain(self.choices, choices)) - return self.renderer(name, value, final_attrs, choices) - - def render(self, name, value, attrs=None, choices=()): - return self.get_renderer(name, value, attrs, choices).render() - - def id_for_label(self, id_): - # Widgets using this RendererMixin are made of a collection of - # subwidgets, each with their own <label>, and distinct ID. - # The IDs are made distinct by y "_X" suffix, where X is the zero-based - # index of the choice field. Thus, the label for the main widget should - # reference the first subwidget, hence the "_0" suffix. - if id_: - id_ += '_0' - return id_ - - -class RadioSelect(RendererMixin, Select): - renderer = RadioFieldRenderer - _empty_value = '' - - -class CheckboxSelectMultiple(RendererMixin, SelectMultiple): - renderer = CheckboxFieldRenderer - _empty_value = [] - - -class MultiWidget(Widget): - """ - A widget that is composed of multiple widgets. - - Its render() method is different than other widgets', because it has to - figure out how to split a single value for display in multiple widgets. - The ``value`` argument can be one of two things: - - * A list. - * A normal value (e.g., a string) that has been "compressed" from - a list of values. - - In the second case -- i.e., if the value is NOT a list -- render() will - first "decompress" the value into a list before rendering it. It does so by - calling the decompress() method, which MultiWidget subclasses must - implement. This method takes a single "compressed" value and returns a - list. - - When render() does 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. - - Subclasses may implement format_output(), which takes the list of rendered - widgets and returns a string of HTML that formats them any way you'd like. - - You'll probably want to use this class with MultiValueField. - """ - def __init__(self, widgets, attrs=None): - self.widgets = [w() if isinstance(w, type) else w for w in widgets] - super(MultiWidget, self).__init__(attrs) - - def render(self, name, value, attrs=None): - if self.is_localized: - for widget in self.widgets: - widget.is_localized = self.is_localized - # value is a list of values, each corresponding to a widget - # in self.widgets. - if not isinstance(value, list): - value = self.decompress(value) - output = [] - final_attrs = self.build_attrs(attrs) - id_ = final_attrs.get('id', None) - for i, widget in enumerate(self.widgets): - try: - widget_value = value[i] - except IndexError: - widget_value = None - if id_: - final_attrs = dict(final_attrs, id='%s_%s' % (id_, i)) - output.append(widget.render(name + '_%s' % i, widget_value, final_attrs)) - return mark_safe(self.format_output(output)) - - def id_for_label(self, id_): - # See the comment for RadioSelect.id_for_label() - if id_: - id_ += '_0' - return id_ - - def value_from_datadict(self, data, files, name): - return [widget.value_from_datadict(data, files, name + '_%s' % i) for i, widget in enumerate(self.widgets)] - - def format_output(self, rendered_widgets): - """ - 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, if - needed. - """ - return ''.join(rendered_widgets) - - def decompress(self, value): - """ - Returns a list of decompressed values for the given compressed value. - The given value can be assumed to be valid, but not necessarily - non-empty. - """ - raise NotImplementedError('Subclasses must implement this method.') - - def _get_media(self): - "Media for a multiwidget is the combination of all media of the subwidgets" - media = Media() - for w in self.widgets: - media = media + w.media - return media - media = property(_get_media) - - def __deepcopy__(self, memo): - obj = super(MultiWidget, self).__deepcopy__(memo) - obj.widgets = copy.deepcopy(self.widgets) - return obj - - @property - def needs_multipart_form(self): - return any(w.needs_multipart_form for w in self.widgets) - - -class SplitDateTimeWidget(MultiWidget): - """ - A Widget that splits datetime input into two <input type="text"> boxes. - """ - - def __init__(self, attrs=None, date_format=None, time_format=None): - widgets = (DateInput(attrs=attrs, format=date_format), - TimeInput(attrs=attrs, format=time_format)) - super(SplitDateTimeWidget, self).__init__(widgets, attrs) - - def decompress(self, value): - if value: - value = to_current_timezone(value) - return [value.date(), value.time().replace(microsecond=0)] - return [None, None] - -class SplitHiddenDateTimeWidget(SplitDateTimeWidget): - """ - A Widget that splits datetime input into two <input type="hidden"> inputs. - """ - is_hidden = True - - def __init__(self, attrs=None, date_format=None, time_format=None): - super(SplitHiddenDateTimeWidget, self).__init__(attrs, date_format, time_format) - for widget in self.widgets: - widget.input_type = 'hidden' - widget.is_hidden = True |