diff options
author | coderick14 | 2017-05-17 15:40:18 +0530 |
---|---|---|
committer | coderick14 | 2017-05-17 15:41:00 +0530 |
commit | a1e0a5502f04da68b6a9ca8508dda3f9d7e1d055 (patch) | |
tree | 20181e6b1936f50ad48d8e35720d64a37566f558 /lib/python2.7/site-packages/django/forms | |
parent | 6f4a84c1e58ff4d54aab94cbee26e995328b05b8 (diff) | |
download | SBHS-2018-Rpi-a1e0a5502f04da68b6a9ca8508dda3f9d7e1d055.tar.gz SBHS-2018-Rpi-a1e0a5502f04da68b6a9ca8508dda3f9d7e1d055.tar.bz2 SBHS-2018-Rpi-a1e0a5502f04da68b6a9ca8508dda3f9d7e1d055.zip |
Upgrade to Django 1.11
- Database integration yet to be tested
Diffstat (limited to 'lib/python2.7/site-packages/django/forms')
-rw-r--r-- | lib/python2.7/site-packages/django/forms/__init__.py | 11 | ||||
-rw-r--r-- | lib/python2.7/site-packages/django/forms/extras/__init__.py | 3 | ||||
-rw-r--r-- | lib/python2.7/site-packages/django/forms/extras/widgets.py | 138 | ||||
-rw-r--r-- | lib/python2.7/site-packages/django/forms/fields.py | 1146 | ||||
-rw-r--r-- | lib/python2.7/site-packages/django/forms/forms.py | 584 | ||||
-rw-r--r-- | lib/python2.7/site-packages/django/forms/formsets.py | 417 | ||||
-rw-r--r-- | lib/python2.7/site-packages/django/forms/models.py | 1231 | ||||
-rw-r--r-- | lib/python2.7/site-packages/django/forms/util.py | 103 | ||||
-rw-r--r-- | lib/python2.7/site-packages/django/forms/widgets.py | 869 |
9 files changed, 0 insertions, 4502 deletions
diff --git a/lib/python2.7/site-packages/django/forms/__init__.py b/lib/python2.7/site-packages/django/forms/__init__.py deleted file mode 100644 index 2588098..0000000 --- a/lib/python2.7/site-packages/django/forms/__init__.py +++ /dev/null @@ -1,11 +0,0 @@ -""" -Django validation and HTML form handling. -""" - -from __future__ import absolute_import - -from django.core.exceptions import ValidationError -from django.forms.fields import * -from django.forms.forms import * -from django.forms.models import * -from django.forms.widgets import * diff --git a/lib/python2.7/site-packages/django/forms/extras/__init__.py b/lib/python2.7/site-packages/django/forms/extras/__init__.py deleted file mode 100644 index d801e4f..0000000 --- a/lib/python2.7/site-packages/django/forms/extras/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import absolute_import - -from django.forms.extras.widgets import * diff --git a/lib/python2.7/site-packages/django/forms/extras/widgets.py b/lib/python2.7/site-packages/django/forms/extras/widgets.py deleted file mode 100644 index 0b96dc4..0000000 --- a/lib/python2.7/site-packages/django/forms/extras/widgets.py +++ /dev/null @@ -1,138 +0,0 @@ -""" -Extra HTML Widget classes -""" -from __future__ import unicode_literals - -import datetime -import re - -from django.forms.widgets import Widget, Select -from django.utils import datetime_safe -from django.utils.dates import MONTHS -from django.utils.encoding import force_str -from django.utils.safestring import mark_safe -from django.utils.formats import get_format -from django.utils import six -from django.conf import settings - -__all__ = ('SelectDateWidget',) - -RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$') - -def _parse_date_fmt(): - fmt = get_format('DATE_FORMAT') - escaped = False - output = [] - for char in fmt: - if escaped: - escaped = False - elif char == '\\': - escaped = True - elif char in 'Yy': - output.append('year') - #if not self.first_select: self.first_select = 'year' - elif char in 'bEFMmNn': - output.append('month') - #if not self.first_select: self.first_select = 'month' - elif char in 'dj': - output.append('day') - #if not self.first_select: self.first_select = 'day' - return output - -class SelectDateWidget(Widget): - """ - A Widget that splits date input into three <select> boxes. - - This also serves as an example of a Widget that has more than one HTML - element and hence implements value_from_datadict. - """ - none_value = (0, '---') - month_field = '%s_month' - day_field = '%s_day' - year_field = '%s_year' - - def __init__(self, attrs=None, years=None, required=True): - # years is an optional list/tuple of years to use in the "year" select box. - self.attrs = attrs or {} - self.required = required - if years: - self.years = years - else: - this_year = datetime.date.today().year - self.years = range(this_year, this_year+10) - - def render(self, name, value, attrs=None): - try: - year_val, month_val, day_val = value.year, value.month, value.day - except AttributeError: - year_val = month_val = day_val = None - if isinstance(value, six.string_types): - if settings.USE_L10N: - try: - input_format = get_format('DATE_INPUT_FORMATS')[0] - v = datetime.datetime.strptime(force_str(value), input_format) - year_val, month_val, day_val = v.year, v.month, v.day - except ValueError: - pass - else: - match = RE_DATE.match(value) - if match: - year_val, month_val, day_val = [int(v) for v in match.groups()] - choices = [(i, i) for i in self.years] - year_html = self.create_select(name, self.year_field, value, year_val, choices) - choices = list(six.iteritems(MONTHS)) - month_html = self.create_select(name, self.month_field, value, month_val, choices) - choices = [(i, i) for i in range(1, 32)] - day_html = self.create_select(name, self.day_field, value, day_val, choices) - - output = [] - for field in _parse_date_fmt(): - if field == 'year': - output.append(year_html) - elif field == 'month': - output.append(month_html) - elif field == 'day': - output.append(day_html) - return mark_safe('\n'.join(output)) - - def id_for_label(self, id_): - first_select = None - field_list = _parse_date_fmt() - if field_list: - first_select = field_list[0] - if first_select is not None: - return '%s_%s' % (id_, first_select) - else: - return '%s_month' % id_ - - def value_from_datadict(self, data, files, name): - y = data.get(self.year_field % name) - m = data.get(self.month_field % name) - d = data.get(self.day_field % name) - if y == m == d == "0": - return None - if y and m and d: - if settings.USE_L10N: - input_format = get_format('DATE_INPUT_FORMATS')[0] - try: - date_value = datetime.date(int(y), int(m), int(d)) - except ValueError: - return '%s-%s-%s' % (y, m, d) - else: - date_value = datetime_safe.new_date(date_value) - return date_value.strftime(input_format) - else: - return '%s-%s-%s' % (y, m, d) - return data.get(name, None) - - def create_select(self, name, field, value, val, choices): - if 'id' in self.attrs: - id_ = self.attrs['id'] - else: - id_ = 'id_%s' % name - if not (self.required and val): - choices.insert(0, self.none_value) - local_attrs = self.build_attrs(id=field % id_) - s = Select(choices=choices) - select_html = s.render(field % name, val, local_attrs) - return select_html diff --git a/lib/python2.7/site-packages/django/forms/fields.py b/lib/python2.7/site-packages/django/forms/fields.py deleted file mode 100644 index 966b303..0000000 --- a/lib/python2.7/site-packages/django/forms/fields.py +++ /dev/null @@ -1,1146 +0,0 @@ -""" -Field classes. -""" - -from __future__ import absolute_import, unicode_literals - -import copy -import datetime -import os -import re -import sys -from decimal import Decimal, DecimalException -from io import BytesIO - -from django.core import validators -from django.core.exceptions import ValidationError -from django.forms.util import ErrorList, from_current_timezone, to_current_timezone -from django.forms.widgets import ( - TextInput, NumberInput, EmailInput, URLInput, HiddenInput, - MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, - NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, - SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION -) -from django.utils import formats -from django.utils.encoding import smart_text, force_str, force_text -from django.utils.ipv6 import clean_ipv6_address -from django.utils import six -from django.utils.six.moves.urllib.parse import urlsplit, urlunsplit -from django.utils.translation import ugettext_lazy as _, ungettext_lazy - -# Provide this import for backwards compatibility. -from django.core.validators import EMPTY_VALUES - - -__all__ = ( - 'Field', 'CharField', 'IntegerField', - 'DateField', 'TimeField', 'DateTimeField', 'TimeField', - 'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField', - 'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', - 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', - 'SplitDateTimeField', 'IPAddressField', 'GenericIPAddressField', 'FilePathField', - 'SlugField', 'TypedChoiceField', 'TypedMultipleChoiceField' -) - - -class Field(object): - widget = TextInput # Default widget to use when rendering this type of Field. - hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden". - default_validators = [] # Default set of validators - # Add an 'invalid' entry to default_error_message if you want a specific - # field error message not raised by the field validators. - default_error_messages = { - 'required': _('This field is required.'), - } - empty_values = list(validators.EMPTY_VALUES) - - # Tracks each time a Field instance is created. Used to retain order. - creation_counter = 0 - - def __init__(self, required=True, widget=None, label=None, initial=None, - help_text='', error_messages=None, show_hidden_initial=False, - validators=[], localize=False): - # required -- Boolean that specifies whether the field is required. - # True by default. - # widget -- A Widget class, or instance of a Widget class, that should - # be used for this Field when displaying it. Each Field has a - # default Widget that it'll use if you don't specify this. In - # most cases, the default widget is TextInput. - # label -- A verbose name for this field, for use in displaying this - # field in a form. By default, Django will use a "pretty" - # version of the form field name, if the Field is part of a - # Form. - # initial -- A value to use in this Field's initial display. This value - # is *not* used as a fallback if data isn't given. - # help_text -- An optional string to use as "help text" for this Field. - # error_messages -- An optional dictionary to override the default - # messages that the field will raise. - # show_hidden_initial -- Boolean that specifies if it is needed to render a - # hidden widget with initial value after widget. - # validators -- List of addtional validators to use - # localize -- Boolean that specifies if the field should be localized. - self.required, self.label, self.initial = required, label, initial - self.show_hidden_initial = show_hidden_initial - self.help_text = help_text - widget = widget or self.widget - if isinstance(widget, type): - widget = widget() - - # Trigger the localization machinery if needed. - self.localize = localize - if self.localize: - widget.is_localized = True - - # Let the widget know whether it should display as required. - widget.is_required = self.required - - # Hook into self.widget_attrs() for any Field-specific HTML attributes. - extra_attrs = self.widget_attrs(widget) - if extra_attrs: - widget.attrs.update(extra_attrs) - - self.widget = widget - - # Increase the creation counter, and save our local copy. - self.creation_counter = Field.creation_counter - Field.creation_counter += 1 - - messages = {} - for c in reversed(self.__class__.__mro__): - messages.update(getattr(c, 'default_error_messages', {})) - messages.update(error_messages or {}) - self.error_messages = messages - - self.validators = self.default_validators + validators - super(Field, self).__init__() - - def prepare_value(self, value): - return value - - def to_python(self, value): - return value - - def validate(self, value): - if value in self.empty_values and self.required: - raise ValidationError(self.error_messages['required'], code='required') - - def run_validators(self, value): - if value in self.empty_values: - return - errors = [] - for v in self.validators: - try: - v(value) - except ValidationError as e: - if hasattr(e, 'code') and e.code in self.error_messages: - e.message = self.error_messages[e.code] - errors.extend(e.error_list) - if errors: - raise ValidationError(errors) - - def clean(self, value): - """ - Validates the given value and returns its "cleaned" value as an - appropriate Python object. - - Raises ValidationError for any errors. - """ - value = self.to_python(value) - self.validate(value) - self.run_validators(value) - return value - - def bound_data(self, data, initial): - """ - Return the value that should be shown for this field on render of a - bound form, given the submitted POST data for the field and the initial - data, if any. - - For most fields, this will simply be data; FileFields need to handle it - a bit differently. - """ - return data - - def widget_attrs(self, widget): - """ - Given a Widget instance (*not* a Widget class), returns a dictionary of - any HTML attributes that should be added to the Widget, based on this - Field. - """ - return {} - - def _has_changed(self, initial, data): - """ - Return True if data differs from initial. - """ - # For purposes of seeing whether something has changed, None is - # the same as an empty string, if the data or inital value we get - # is None, replace it w/ ''. - initial_value = initial if initial is not None else '' - try: - data = self.to_python(data) - except ValidationError: - return True - data_value = data if data is not None else '' - return initial_value != data_value - - def __deepcopy__(self, memo): - result = copy.copy(self) - memo[id(self)] = result - result.widget = copy.deepcopy(self.widget, memo) - result.validators = self.validators[:] - return result - - -class CharField(Field): - def __init__(self, max_length=None, min_length=None, *args, **kwargs): - self.max_length, self.min_length = max_length, min_length - super(CharField, self).__init__(*args, **kwargs) - if min_length is not None: - self.validators.append(validators.MinLengthValidator(int(min_length))) - if max_length is not None: - self.validators.append(validators.MaxLengthValidator(int(max_length))) - - def to_python(self, value): - "Returns a Unicode object." - if value in self.empty_values: - return '' - return smart_text(value) - - def widget_attrs(self, widget): - attrs = super(CharField, self).widget_attrs(widget) - if self.max_length is not None and isinstance(widget, TextInput): - # The HTML attribute is maxlength, not max_length. - attrs.update({'maxlength': str(self.max_length)}) - return attrs - - -class IntegerField(Field): - widget = NumberInput - default_error_messages = { - 'invalid': _('Enter a whole number.'), - } - - def __init__(self, max_value=None, min_value=None, *args, **kwargs): - self.max_value, self.min_value = max_value, min_value - if kwargs.get('localize') and self.widget == NumberInput: - # Localized number input is not well supported on most browsers - kwargs.setdefault('widget', super(IntegerField, self).widget) - super(IntegerField, self).__init__(*args, **kwargs) - - if max_value is not None: - self.validators.append(validators.MaxValueValidator(max_value)) - if min_value is not None: - self.validators.append(validators.MinValueValidator(min_value)) - - def to_python(self, value): - """ - Validates that int() can be called on the input. Returns the result - of int(). Returns None for empty values. - """ - value = super(IntegerField, self).to_python(value) - if value in self.empty_values: - return None - if self.localize: - value = formats.sanitize_separators(value) - try: - value = int(str(value)) - except (ValueError, TypeError): - raise ValidationError(self.error_messages['invalid'], code='invalid') - return value - - def widget_attrs(self, widget): - attrs = super(IntegerField, self).widget_attrs(widget) - if isinstance(widget, NumberInput): - if self.min_value is not None: - attrs['min'] = self.min_value - if self.max_value is not None: - attrs['max'] = self.max_value - return attrs - - -class FloatField(IntegerField): - default_error_messages = { - 'invalid': _('Enter a number.'), - } - - def to_python(self, value): - """ - Validates that float() can be called on the input. Returns the result - of float(). Returns None for empty values. - """ - value = super(IntegerField, self).to_python(value) - if value in self.empty_values: - return None - if self.localize: - value = formats.sanitize_separators(value) - try: - value = float(value) - except (ValueError, TypeError): - raise ValidationError(self.error_messages['invalid'], code='invalid') - return value - - def widget_attrs(self, widget): - attrs = super(FloatField, self).widget_attrs(widget) - if isinstance(widget, NumberInput): - attrs.setdefault('step', 'any') - return attrs - - -class DecimalField(IntegerField): - default_error_messages = { - 'invalid': _('Enter a number.'), - 'max_digits': ungettext_lazy( - 'Ensure that there are no more than %(max)s digit in total.', - 'Ensure that there are no more than %(max)s digits in total.', - 'max'), - 'max_decimal_places': ungettext_lazy( - 'Ensure that there are no more than %(max)s decimal place.', - 'Ensure that there are no more than %(max)s decimal places.', - 'max'), - 'max_whole_digits': ungettext_lazy( - 'Ensure that there are no more than %(max)s digit before the decimal point.', - 'Ensure that there are no more than %(max)s digits before the decimal point.', - 'max'), - } - - def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs): - self.max_digits, self.decimal_places = max_digits, decimal_places - super(DecimalField, self).__init__(max_value, min_value, *args, **kwargs) - - def to_python(self, value): - """ - Validates that the input is a decimal number. Returns a Decimal - instance. Returns None for empty values. Ensures that there are no more - than max_digits in the number, and no more than decimal_places digits - after the decimal point. - """ - if value in self.empty_values: - return None - if self.localize: - value = formats.sanitize_separators(value) - value = smart_text(value).strip() - try: - value = Decimal(value) - except DecimalException: - raise ValidationError(self.error_messages['invalid'], code='invalid') - return value - - def validate(self, value): - super(DecimalField, self).validate(value) - if value in self.empty_values: - return - # Check for NaN, Inf and -Inf values. We can't compare directly for NaN, - # since it is never equal to itself. However, NaN is the only value that - # isn't equal to itself, so we can use this to identify NaN - if value != value or value == Decimal("Inf") or value == Decimal("-Inf"): - raise ValidationError(self.error_messages['invalid'], code='invalid') - sign, digittuple, exponent = value.as_tuple() - decimals = abs(exponent) - # digittuple doesn't include any leading zeros. - digits = len(digittuple) - if decimals > digits: - # We have leading zeros up to or past the decimal point. Count - # everything past the decimal point as a digit. We do not count - # 0 before the decimal point as a digit since that would mean - # we would not allow max_digits = decimal_places. - digits = decimals - whole_digits = digits - decimals - - if self.max_digits is not None and digits > self.max_digits: - raise ValidationError( - self.error_messages['max_digits'], - code='max_digits', - params={'max': self.max_digits}, - ) - if self.decimal_places is not None and decimals > self.decimal_places: - raise ValidationError( - self.error_messages['max_decimal_places'], - code='max_decimal_places', - params={'max': self.decimal_places}, - ) - if (self.max_digits is not None and self.decimal_places is not None - and whole_digits > (self.max_digits - self.decimal_places)): - raise ValidationError( - self.error_messages['max_whole_digits'], - code='max_whole_digits', - params={'max': (self.max_digits - self.decimal_places)}, - ) - return value - - def widget_attrs(self, widget): - attrs = super(DecimalField, self).widget_attrs(widget) - if isinstance(widget, NumberInput): - if self.decimal_places is not None: - # Use exponential notation for small values since they might - # be parsed as 0 otherwise. ref #20765 - step = str(Decimal('1') / 10 ** self.decimal_places).lower() - else: - step = 'any' - attrs.setdefault('step', step) - return attrs - - -class BaseTemporalField(Field): - - def __init__(self, input_formats=None, *args, **kwargs): - super(BaseTemporalField, self).__init__(*args, **kwargs) - if input_formats is not None: - self.input_formats = input_formats - - def to_python(self, value): - # Try to coerce the value to unicode. - unicode_value = force_text(value, strings_only=True) - if isinstance(unicode_value, six.text_type): - value = unicode_value.strip() - # If unicode, try to strptime against each input format. - if isinstance(value, six.text_type): - for format in self.input_formats: - try: - return self.strptime(value, format) - except (ValueError, TypeError): - continue - raise ValidationError(self.error_messages['invalid'], code='invalid') - - def strptime(self, value, format): - raise NotImplementedError('Subclasses must define this method.') - - -class DateField(BaseTemporalField): - widget = DateInput - input_formats = formats.get_format_lazy('DATE_INPUT_FORMATS') - default_error_messages = { - 'invalid': _('Enter a valid date.'), - } - - def to_python(self, value): - """ - Validates that the input can be converted to a date. Returns a Python - datetime.date object. - """ - if value in self.empty_values: - return None - if isinstance(value, datetime.datetime): - return value.date() - if isinstance(value, datetime.date): - return value - return super(DateField, self).to_python(value) - - def strptime(self, value, format): - return datetime.datetime.strptime(force_str(value), format).date() - - -class TimeField(BaseTemporalField): - widget = TimeInput - input_formats = formats.get_format_lazy('TIME_INPUT_FORMATS') - default_error_messages = { - 'invalid': _('Enter a valid time.') - } - - def to_python(self, value): - """ - Validates that the input can be converted to a time. Returns a Python - datetime.time object. - """ - if value in self.empty_values: - return None - if isinstance(value, datetime.time): - return value - return super(TimeField, self).to_python(value) - - def strptime(self, value, format): - return datetime.datetime.strptime(force_str(value), format).time() - - -class DateTimeField(BaseTemporalField): - widget = DateTimeInput - input_formats = formats.get_format_lazy('DATETIME_INPUT_FORMATS') - default_error_messages = { - 'invalid': _('Enter a valid date/time.'), - } - - def prepare_value(self, value): - if isinstance(value, datetime.datetime): - value = to_current_timezone(value) - return value - - def to_python(self, value): - """ - Validates that the input can be converted to a datetime. Returns a - Python datetime.datetime object. - """ - if value in self.empty_values: - return None - if isinstance(value, datetime.datetime): - return from_current_timezone(value) - if isinstance(value, datetime.date): - result = datetime.datetime(value.year, value.month, value.day) - return from_current_timezone(result) - if isinstance(value, list): - # Input comes from a SplitDateTimeWidget, for example. So, it's two - # components: date and time. - if len(value) != 2: - raise ValidationError(self.error_messages['invalid'], code='invalid') - if value[0] in self.empty_values and value[1] in self.empty_values: - return None - value = '%s %s' % tuple(value) - result = super(DateTimeField, self).to_python(value) - return from_current_timezone(result) - - def strptime(self, value, format): - return datetime.datetime.strptime(force_str(value), format) - - -class RegexField(CharField): - def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs): - """ - regex can be either a string or a compiled regular expression object. - error_message is an optional error message to use, if - 'Enter a valid value' is too generic for you. - """ - # error_message is just kept for backwards compatibility: - if error_message: - error_messages = kwargs.get('error_messages') or {} - error_messages['invalid'] = error_message - kwargs['error_messages'] = error_messages - super(RegexField, self).__init__(max_length, min_length, *args, **kwargs) - self._set_regex(regex) - - def _get_regex(self): - return self._regex - - def _set_regex(self, regex): - if isinstance(regex, six.string_types): - regex = re.compile(regex, re.UNICODE) - self._regex = regex - if hasattr(self, '_regex_validator') and self._regex_validator in self.validators: - self.validators.remove(self._regex_validator) - self._regex_validator = validators.RegexValidator(regex=regex) - self.validators.append(self._regex_validator) - - regex = property(_get_regex, _set_regex) - - -class EmailField(CharField): - widget = EmailInput - default_validators = [validators.validate_email] - - def clean(self, value): - value = self.to_python(value).strip() - return super(EmailField, self).clean(value) - - -class FileField(Field): - widget = ClearableFileInput - default_error_messages = { - 'invalid': _("No file was submitted. Check the encoding type on the form."), - 'missing': _("No file was submitted."), - 'empty': _("The submitted file is empty."), - 'max_length': ungettext_lazy( - 'Ensure this filename has at most %(max)d character (it has %(length)d).', - 'Ensure this filename has at most %(max)d characters (it has %(length)d).', - 'max'), - 'contradiction': _('Please either submit a file or check the clear checkbox, not both.') - } - - def __init__(self, *args, **kwargs): - self.max_length = kwargs.pop('max_length', None) - self.allow_empty_file = kwargs.pop('allow_empty_file', False) - super(FileField, self).__init__(*args, **kwargs) - - def to_python(self, data): - if data in self.empty_values: - return None - - # UploadedFile objects should have name and size attributes. - try: - file_name = data.name - file_size = data.size - except AttributeError: - raise ValidationError(self.error_messages['invalid'], code='invalid') - - if self.max_length is not None and len(file_name) > self.max_length: - params = {'max': self.max_length, 'length': len(file_name)} - raise ValidationError(self.error_messages['max_length'], code='max_length', params=params) - if not file_name: - raise ValidationError(self.error_messages['invalid'], code='invalid') - if not self.allow_empty_file and not file_size: - raise ValidationError(self.error_messages['empty'], code='empty') - - return data - - def clean(self, data, initial=None): - # If the widget got contradictory inputs, we raise a validation error - if data is FILE_INPUT_CONTRADICTION: - raise ValidationError(self.error_messages['contradiction'], code='contradiction') - # False means the field value should be cleared; further validation is - # not needed. - if data is False: - if not self.required: - return False - # If the field is required, clearing is not possible (the widget - # shouldn't return False data in that case anyway). False is not - # in self.empty_value; if a False value makes it this far - # it should be validated from here on out as None (so it will be - # caught by the required check). - data = None - if not data and initial: - return initial - return super(FileField, self).clean(data) - - def bound_data(self, data, initial): - if data in (None, FILE_INPUT_CONTRADICTION): - return initial - return data - - def _has_changed(self, initial, data): - if data is None: - return False - return True - - -class ImageField(FileField): - default_error_messages = { - 'invalid_image': _("Upload a valid image. The file you uploaded was either not an image or a corrupted image."), - } - - def to_python(self, data): - """ - Checks that the file-upload field data contains a valid image (GIF, JPG, - PNG, possibly others -- whatever the Python Imaging Library supports). - """ - f = super(ImageField, self).to_python(data) - if f is None: - return None - - from django.utils.image import Image - - # We need to get a file object for Pillow. We might have a path or we might - # have to read the data into memory. - if hasattr(data, 'temporary_file_path'): - file = data.temporary_file_path() - else: - if hasattr(data, 'read'): - file = BytesIO(data.read()) - else: - file = BytesIO(data['content']) - - try: - # load() could spot a truncated JPEG, but it loads the entire - # image in memory, which is a DoS vector. See #3848 and #18520. - # verify() must be called immediately after the constructor. - Image.open(file).verify() - except Exception: - # Pillow (or PIL) doesn't recognize it as an image. - six.reraise(ValidationError, ValidationError( - self.error_messages['invalid_image'], - code='invalid_image', - ), sys.exc_info()[2]) - if hasattr(f, 'seek') and callable(f.seek): - f.seek(0) - return f - - -class URLField(CharField): - widget = URLInput - default_error_messages = { - 'invalid': _('Enter a valid URL.'), - } - default_validators = [validators.URLValidator()] - - def to_python(self, value): - - def split_url(url): - """ - Returns a list of url parts via ``urlparse.urlsplit`` (or raises a - ``ValidationError`` exception for certain). - """ - try: - return list(urlsplit(url)) - except ValueError: - # urlparse.urlsplit can raise a ValueError with some - # misformatted URLs. - raise ValidationError(self.error_messages['invalid'], code='invalid') - - value = super(URLField, self).to_python(value) - if value: - url_fields = split_url(value) - if not url_fields[0]: - # If no URL scheme given, assume http:// - url_fields[0] = 'http' - if not url_fields[1]: - # Assume that if no domain is provided, that the path segment - # contains the domain. - url_fields[1] = url_fields[2] - url_fields[2] = '' - # Rebuild the url_fields list, since the domain segment may now - # contain the path too. - url_fields = split_url(urlunsplit(url_fields)) - if not url_fields[2]: - # the path portion may need to be added before query params - url_fields[2] = '/' - value = urlunsplit(url_fields) - return value - - def clean(self, value): - value = self.to_python(value).strip() - return super(URLField, self).clean(value) - - -class BooleanField(Field): - widget = CheckboxInput - - def to_python(self, value): - """Returns a Python boolean object.""" - # Explicitly check for the string 'False', which is what a hidden field - # will submit for False. Also check for '0', since this is what - # RadioSelect will provide. Because bool("True") == bool('1') == True, - # we don't need to handle that explicitly. - if isinstance(value, six.string_types) and value.lower() in ('false', '0'): - value = False - else: - value = bool(value) - return super(BooleanField, self).to_python(value) - - def validate(self, value): - if not value and self.required: - raise ValidationError(self.error_messages['required'], code='required') - - def _has_changed(self, initial, data): - # Sometimes data or initial could be None or '' which should be the - # same thing as False. - if initial == 'False': - # show_hidden_initial may have transformed False to 'False' - initial = False - return bool(initial) != bool(data) - - -class NullBooleanField(BooleanField): - """ - A field whose valid values are None, True and False. Invalid values are - cleaned to None. - """ - widget = NullBooleanSelect - - def to_python(self, value): - """ - Explicitly checks for the string 'True' and 'False', which is what a - hidden field will submit for True and False, and for '1' and '0', which - is what a RadioField will submit. Unlike the Booleanfield we need to - explicitly check for True, because we are not using the bool() function - """ - if value in (True, 'True', '1'): - return True - elif value in (False, 'False', '0'): - return False - else: - return None - - def validate(self, value): - pass - - def _has_changed(self, initial, data): - # None (unknown) and False (No) are not the same - if initial is not None: - initial = bool(initial) - if data is not None: - data = bool(data) - return initial != data - - -class ChoiceField(Field): - widget = Select - default_error_messages = { - 'invalid_choice': _('Select a valid choice. %(value)s is not one of the available choices.'), - } - - def __init__(self, choices=(), required=True, widget=None, label=None, - initial=None, help_text='', *args, **kwargs): - super(ChoiceField, self).__init__(required=required, widget=widget, label=label, - initial=initial, help_text=help_text, *args, **kwargs) - self.choices = choices - - def __deepcopy__(self, memo): - result = super(ChoiceField, self).__deepcopy__(memo) - result._choices = copy.deepcopy(self._choices, memo) - return result - - def _get_choices(self): - return self._choices - - def _set_choices(self, value): - # Setting choices also sets the choices on the widget. - # choices can be any iterable, but we call list() on it because - # it will be consumed more than once. - self._choices = self.widget.choices = list(value) - - choices = property(_get_choices, _set_choices) - - def to_python(self, value): - "Returns a Unicode object." - if value in self.empty_values: - return '' - return smart_text(value) - - def validate(self, value): - """ - Validates that the input is in self.choices. - """ - super(ChoiceField, self).validate(value) - if value and not self.valid_value(value): - raise ValidationError( - self.error_messages['invalid_choice'], - code='invalid_choice', - params={'value': value}, - ) - - def valid_value(self, value): - "Check to see if the provided value is a valid choice" - text_value = force_text(value) - for k, v in self.choices: - if isinstance(v, (list, tuple)): - # This is an optgroup, so look inside the group for options - for k2, v2 in v: - if value == k2 or text_value == force_text(k2): - return True - else: - if value == k or text_value == force_text(k): - return True - return False - - -class TypedChoiceField(ChoiceField): - def __init__(self, *args, **kwargs): - self.coerce = kwargs.pop('coerce', lambda val: val) - self.empty_value = kwargs.pop('empty_value', '') - super(TypedChoiceField, self).__init__(*args, **kwargs) - - def to_python(self, value): - """ - Validates that the value is in self.choices and can be coerced to the - right type. - """ - value = super(TypedChoiceField, self).to_python(value) - if value == self.empty_value or value in self.empty_values: - return self.empty_value - try: - value = self.coerce(value) - except (ValueError, TypeError, ValidationError): - raise ValidationError( - self.error_messages['invalid_choice'], - code='invalid_choice', - params={'value': value}, - ) - return value - - -class MultipleChoiceField(ChoiceField): - hidden_widget = MultipleHiddenInput - widget = SelectMultiple - default_error_messages = { - 'invalid_choice': _('Select a valid choice. %(value)s is not one of the available choices.'), - 'invalid_list': _('Enter a list of values.'), - } - - def to_python(self, value): - if not value: - return [] - elif not isinstance(value, (list, tuple)): - raise ValidationError(self.error_messages['invalid_list'], code='invalid_list') - return [smart_text(val) for val in value] - - def validate(self, value): - """ - Validates that the input is a list or tuple. - """ - if self.required and not value: - raise ValidationError(self.error_messages['required'], code='required') - # Validate that each value in the value list is in self.choices. - for val in value: - if not self.valid_value(val): - raise ValidationError( - self.error_messages['invalid_choice'], - code='invalid_choice', - params={'value': val}, - ) - - def _has_changed(self, initial, data): - if initial is None: - initial = [] - if data is None: - data = [] - if len(initial) != len(data): - return True - initial_set = set([force_text(value) for value in initial]) - data_set = set([force_text(value) for value in data]) - return data_set != initial_set - - -class TypedMultipleChoiceField(MultipleChoiceField): - def __init__(self, *args, **kwargs): - self.coerce = kwargs.pop('coerce', lambda val: val) - self.empty_value = kwargs.pop('empty_value', []) - super(TypedMultipleChoiceField, self).__init__(*args, **kwargs) - - def to_python(self, value): - """ - Validates that the values are in self.choices and can be coerced to the - right type. - """ - value = super(TypedMultipleChoiceField, self).to_python(value) - if value == self.empty_value or value in self.empty_values: - return self.empty_value - new_value = [] - for choice in value: - try: - new_value.append(self.coerce(choice)) - except (ValueError, TypeError, ValidationError): - raise ValidationError( - self.error_messages['invalid_choice'], - code='invalid_choice', - params={'value': choice}, - ) - return new_value - - def validate(self, value): - if value != self.empty_value: - super(TypedMultipleChoiceField, self).validate(value) - elif self.required: - raise ValidationError(self.error_messages['required'], code='required') - - -class ComboField(Field): - """ - A Field whose clean() method calls multiple Field clean() methods. - """ - def __init__(self, fields=(), *args, **kwargs): - super(ComboField, self).__init__(*args, **kwargs) - # Set 'required' to False on the individual fields, because the - # required validation will be handled by ComboField, not by those - # individual fields. - for f in fields: - f.required = False - self.fields = fields - - def clean(self, value): - """ - Validates the given value against all of self.fields, which is a - list of Field instances. - """ - super(ComboField, self).clean(value) - for field in self.fields: - value = field.clean(value) - return value - - -class MultiValueField(Field): - """ - A Field that aggregates the logic of multiple Fields. - - Its clean() method takes a "decompressed" list of values, which are then - cleaned into a single value according to self.fields. Each value in - this list is cleaned by the corresponding field -- the first value is - cleaned by the first field, the second value is cleaned by the second - field, etc. Once all fields are cleaned, the list of clean values is - "compressed" into a single value. - - Subclasses should not have to implement clean(). Instead, they must - implement compress(), which takes a list of valid values and returns a - "compressed" version of those values -- a single value. - - You'll probably want to use this with MultiWidget. - """ - default_error_messages = { - 'invalid': _('Enter a list of values.'), - } - - def __init__(self, fields=(), *args, **kwargs): - super(MultiValueField, self).__init__(*args, **kwargs) - # Set 'required' to False on the individual fields, because the - # required validation will be handled by MultiValueField, not by those - # individual fields. - for f in fields: - f.required = False - self.fields = fields - - def validate(self, value): - pass - - def clean(self, value): - """ - Validates every value in the given list. A value is validated against - the corresponding Field in self.fields. - - For example, if this MultiValueField was instantiated with - fields=(DateField(), TimeField()), clean() would call - DateField.clean(value[0]) and TimeField.clean(value[1]). - """ - clean_data = [] - errors = ErrorList() - if not value or isinstance(value, (list, tuple)): - if not value or not [v for v in value if v not in self.empty_values]: - if self.required: - raise ValidationError(self.error_messages['required'], code='required') - else: - return self.compress([]) - else: - raise ValidationError(self.error_messages['invalid'], code='invalid') - for i, field in enumerate(self.fields): - try: - field_value = value[i] - except IndexError: - field_value = None - if self.required and field_value in self.empty_values: - raise ValidationError(self.error_messages['required'], code='required') - try: - clean_data.append(field.clean(field_value)) - except ValidationError as e: - # Collect all validation errors in a single list, which we'll - # raise at the end of clean(), rather than raising a single - # exception for the first error we encounter. - errors.extend(e.error_list) - if errors: - raise ValidationError(errors) - - out = self.compress(clean_data) - self.validate(out) - self.run_validators(out) - return out - - def compress(self, data_list): - """ - Returns a single value for the given list of values. The values can be - assumed to be valid. - - For example, if this MultiValueField was instantiated with - fields=(DateField(), TimeField()), this might return a datetime - object created by combining the date and time in data_list. - """ - raise NotImplementedError('Subclasses must implement this method.') - - def _has_changed(self, initial, data): - if initial is None: - initial = ['' for x in range(0, len(data))] - else: - if not isinstance(initial, list): - initial = self.widget.decompress(initial) - for field, initial, data in zip(self.fields, initial, data): - if field._has_changed(field.to_python(initial), data): - return True - return False - - -class FilePathField(ChoiceField): - def __init__(self, path, match=None, recursive=False, allow_files=True, - allow_folders=False, required=True, widget=None, label=None, - initial=None, help_text='', *args, **kwargs): - self.path, self.match, self.recursive = path, match, recursive - self.allow_files, self.allow_folders = allow_files, allow_folders - super(FilePathField, self).__init__(choices=(), required=required, - widget=widget, label=label, initial=initial, help_text=help_text, - *args, **kwargs) - - if self.required: - self.choices = [] - else: - self.choices = [("", "---------")] - - if self.match is not None: - self.match_re = re.compile(self.match) - - if recursive: - for root, dirs, files in sorted(os.walk(self.path)): - if self.allow_files: - for f in files: - if self.match is None or self.match_re.search(f): - f = os.path.join(root, f) - self.choices.append((f, f.replace(path, "", 1))) - if self.allow_folders: - for f in dirs: - if f == '__pycache__': - continue - if self.match is None or self.match_re.search(f): - f = os.path.join(root, f) - self.choices.append((f, f.replace(path, "", 1))) - else: - try: - for f in sorted(os.listdir(self.path)): - if f == '__pycache__': - continue - full_file = os.path.join(self.path, f) - if (((self.allow_files and os.path.isfile(full_file)) or - (self.allow_folders and os.path.isdir(full_file))) and - (self.match is None or self.match_re.search(f))): - self.choices.append((full_file, f)) - except OSError: - pass - - self.widget.choices = self.choices - - -class SplitDateTimeField(MultiValueField): - widget = SplitDateTimeWidget - hidden_widget = SplitHiddenDateTimeWidget - default_error_messages = { - 'invalid_date': _('Enter a valid date.'), - 'invalid_time': _('Enter a valid time.'), - } - - def __init__(self, input_date_formats=None, input_time_formats=None, *args, **kwargs): - errors = self.default_error_messages.copy() - if 'error_messages' in kwargs: - errors.update(kwargs['error_messages']) - localize = kwargs.get('localize', False) - fields = ( - DateField(input_formats=input_date_formats, - error_messages={'invalid': errors['invalid_date']}, - localize=localize), - TimeField(input_formats=input_time_formats, - error_messages={'invalid': errors['invalid_time']}, - localize=localize), - ) - super(SplitDateTimeField, self).__init__(fields, *args, **kwargs) - - def compress(self, data_list): - if data_list: - # Raise a validation error if time or date is empty - # (possible if SplitDateTimeField has required=False). - if data_list[0] in self.empty_values: - raise ValidationError(self.error_messages['invalid_date'], code='invalid_date') - if data_list[1] in self.empty_values: - raise ValidationError(self.error_messages['invalid_time'], code='invalid_time') - result = datetime.datetime.combine(*data_list) - return from_current_timezone(result) - return None - - -class IPAddressField(CharField): - default_validators = [validators.validate_ipv4_address] - - def to_python(self, value): - if value in self.empty_values: - return '' - return value.strip() - - -class GenericIPAddressField(CharField): - def __init__(self, protocol='both', unpack_ipv4=False, *args, **kwargs): - self.unpack_ipv4 = unpack_ipv4 - self.default_validators = validators.ip_address_validators(protocol, unpack_ipv4)[0] - super(GenericIPAddressField, self).__init__(*args, **kwargs) - - def to_python(self, value): - if value in self.empty_values: - return '' - value = value.strip() - if value and ':' in value: - return clean_ipv6_address(value, self.unpack_ipv4) - return value - - -class SlugField(CharField): - default_validators = [validators.validate_slug] - - def clean(self, value): - value = self.to_python(value).strip() - return super(SlugField, self).clean(value) diff --git a/lib/python2.7/site-packages/django/forms/forms.py b/lib/python2.7/site-packages/django/forms/forms.py deleted file mode 100644 index 573215d..0000000 --- a/lib/python2.7/site-packages/django/forms/forms.py +++ /dev/null @@ -1,584 +0,0 @@ -""" -Form classes -""" - -from __future__ import absolute_import, unicode_literals - -import copy -import warnings - -from django.core.exceptions import ValidationError -from django.forms.fields import Field, FileField -from django.forms.util import flatatt, ErrorDict, ErrorList -from django.forms.widgets import Media, media_property, TextInput, Textarea -from django.utils.datastructures import SortedDict -from django.utils.html import conditional_escape, format_html -from django.utils.encoding import smart_text, force_text, python_2_unicode_compatible -from django.utils.safestring import mark_safe -from django.utils.translation import ugettext as _ -from django.utils import six - - -__all__ = ('BaseForm', 'Form') - -NON_FIELD_ERRORS = '__all__' - -def pretty_name(name): - """Converts 'first_name' to 'First name'""" - if not name: - return '' - return name.replace('_', ' ').capitalize() - -def get_declared_fields(bases, attrs, with_base_fields=True): - """ - Create a list of form field instances from the passed in 'attrs', plus any - similar fields on the base classes (in 'bases'). This is used by both the - Form and ModelForm metaclasses. - - If 'with_base_fields' is True, all fields from the bases are used. - Otherwise, only fields in the 'declared_fields' attribute on the bases are - used. The distinction is useful in ModelForm subclassing. - Also integrates any additional media definitions. - """ - fields = [(field_name, attrs.pop(field_name)) for field_name, obj in list(six.iteritems(attrs)) if isinstance(obj, Field)] - fields.sort(key=lambda x: x[1].creation_counter) - - # If this class is subclassing another Form, add that Form's fields. - # Note that we loop over the bases in *reverse*. This is necessary in - # order to preserve the correct order of fields. - if with_base_fields: - for base in bases[::-1]: - if hasattr(base, 'base_fields'): - fields = list(six.iteritems(base.base_fields)) + fields - else: - for base in bases[::-1]: - if hasattr(base, 'declared_fields'): - fields = list(six.iteritems(base.declared_fields)) + fields - - return SortedDict(fields) - -class DeclarativeFieldsMetaclass(type): - """ - Metaclass that converts Field attributes to a dictionary called - 'base_fields', taking into account parent class 'base_fields' as well. - """ - def __new__(cls, name, bases, attrs): - attrs['base_fields'] = get_declared_fields(bases, attrs) - new_class = super(DeclarativeFieldsMetaclass, - 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 BaseForm(object): - # This is the main implementation of all the Form logic. Note that this - # class is different than Form. See the comments by the Form class for more - # information. Any improvements to the form API should be made to *this* - # class, not to the Form class. - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - initial=None, error_class=ErrorList, label_suffix=None, - empty_permitted=False): - self.is_bound = data is not None or files is not None - self.data = data or {} - self.files = files or {} - self.auto_id = auto_id - self.prefix = prefix - self.initial = initial or {} - self.error_class = error_class - # Translators: This is the default suffix added to form field labels - self.label_suffix = label_suffix if label_suffix is not None else _(':') - self.empty_permitted = empty_permitted - self._errors = None # Stores the errors after clean() has been called. - self._changed_data = None - - # The base_fields class attribute is the *class-wide* definition of - # fields. Because a particular *instance* of the class might want to - # alter self.fields, we create self.fields here by copying base_fields. - # Instances should always modify self.fields; they should not modify - # self.base_fields. - self.fields = copy.deepcopy(self.base_fields) - - def __str__(self): - return self.as_table() - - def __iter__(self): - for name in self.fields: - yield self[name] - - def __getitem__(self, name): - "Returns a BoundField with the given name." - try: - field = self.fields[name] - except KeyError: - raise KeyError('Key %r not found in Form' % name) - return BoundField(self, field, name) - - @property - def errors(self): - "Returns an ErrorDict for the data provided for the form" - if self._errors is None: - self.full_clean() - return self._errors - - def is_valid(self): - """ - Returns True if the form has no errors. Otherwise, False. If errors are - being ignored, returns False. - """ - return self.is_bound and not bool(self.errors) - - def add_prefix(self, field_name): - """ - Returns the field name with a prefix appended, if this Form has a - prefix set. - - Subclasses may wish to override. - """ - return '%s-%s' % (self.prefix, field_name) if self.prefix else field_name - - def add_initial_prefix(self, field_name): - """ - Add a 'initial' prefix for checking dynamic initial values - """ - return 'initial-%s' % self.add_prefix(field_name) - - def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row): - "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()." - top_errors = self.non_field_errors() # Errors that should be displayed above all fields. - output, hidden_fields = [], [] - - for name, field in self.fields.items(): - html_class_attr = '' - bf = self[name] - # Escape and cache in local variable. - bf_errors = self.error_class([conditional_escape(error) for error in bf.errors]) - if bf.is_hidden: - if bf_errors: - top_errors.extend( - [_('(Hidden field %(name)s) %(error)s') % {'name': name, 'error': force_text(e)} - for e in bf_errors]) - hidden_fields.append(six.text_type(bf)) - else: - # Create a 'class="..."' atribute if the row should have any - # CSS classes applied. - css_classes = bf.css_classes() - if css_classes: - html_class_attr = ' class="%s"' % css_classes - - if errors_on_separate_row and bf_errors: - output.append(error_row % force_text(bf_errors)) - - if bf.label: - label = conditional_escape(force_text(bf.label)) - label = bf.label_tag(label) or '' - else: - label = '' - - if field.help_text: - help_text = help_text_html % force_text(field.help_text) - else: - help_text = '' - - output.append(normal_row % { - 'errors': force_text(bf_errors), - 'label': force_text(label), - 'field': six.text_type(bf), - 'help_text': help_text, - 'html_class_attr': html_class_attr - }) - - if top_errors: - output.insert(0, error_row % force_text(top_errors)) - - if hidden_fields: # Insert any hidden fields in the last row. - str_hidden = ''.join(hidden_fields) - if output: - last_row = output[-1] - # Chop off the trailing row_ender (e.g. '</td></tr>') and - # insert the hidden fields. - if not last_row.endswith(row_ender): - # This can happen in the as_p() case (and possibly others - # that users write): if there are only top errors, we may - # not be able to conscript the last row for our purposes, - # so insert a new, empty row. - last_row = (normal_row % {'errors': '', 'label': '', - 'field': '', 'help_text':'', - 'html_class_attr': html_class_attr}) - output.append(last_row) - output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender - else: - # If there aren't any rows in the output, just append the - # hidden fields. - output.append(str_hidden) - return mark_safe('\n'.join(output)) - - def as_table(self): - "Returns this form rendered as HTML <tr>s -- excluding the <table></table>." - return self._html_output( - normal_row = '<tr%(html_class_attr)s><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', - error_row = '<tr><td colspan="2">%s</td></tr>', - row_ender = '</td></tr>', - help_text_html = '<br /><span class="helptext">%s</span>', - errors_on_separate_row = False) - - def as_ul(self): - "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>." - return self._html_output( - normal_row = '<li%(html_class_attr)s>%(errors)s%(label)s %(field)s%(help_text)s</li>', - error_row = '<li>%s</li>', - row_ender = '</li>', - help_text_html = ' <span class="helptext">%s</span>', - errors_on_separate_row = False) - - def as_p(self): - "Returns this form rendered as HTML <p>s." - return self._html_output( - normal_row = '<p%(html_class_attr)s>%(label)s %(field)s%(help_text)s</p>', - error_row = '%s', - row_ender = '</p>', - help_text_html = ' <span class="helptext">%s</span>', - errors_on_separate_row = True) - - def non_field_errors(self): - """ - Returns an ErrorList of errors that aren't associated with a particular - field -- i.e., from Form.clean(). Returns an empty ErrorList if there - are none. - """ - return self.errors.get(NON_FIELD_ERRORS, self.error_class()) - - def _raw_value(self, fieldname): - """ - Returns the raw_value for a particular field name. This is just a - convenient wrapper around widget.value_from_datadict. - """ - field = self.fields[fieldname] - prefix = self.add_prefix(fieldname) - return field.widget.value_from_datadict(self.data, self.files, prefix) - - def full_clean(self): - """ - Cleans all of self.data and populates self._errors and - self.cleaned_data. - """ - self._errors = ErrorDict() - if not self.is_bound: # Stop further processing. - return - self.cleaned_data = {} - # If the form is permitted to be empty, and none of the form data has - # changed from the initial data, short circuit any validation. - if self.empty_permitted and not self.has_changed(): - return - self._clean_fields() - self._clean_form() - self._post_clean() - - def _clean_fields(self): - for name, field in self.fields.items(): - # value_from_datadict() gets the data from the data dictionaries. - # Each widget type knows how to retrieve its own data, because some - # widgets split data over several HTML fields. - value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) - try: - if isinstance(field, FileField): - initial = self.initial.get(name, field.initial) - value = field.clean(value, initial) - else: - value = field.clean(value) - self.cleaned_data[name] = value - if hasattr(self, 'clean_%s' % name): - value = getattr(self, 'clean_%s' % name)() - self.cleaned_data[name] = value - except ValidationError as e: - self._errors[name] = self.error_class(e.messages) - if name in self.cleaned_data: - del self.cleaned_data[name] - - def _clean_form(self): - try: - self.cleaned_data = self.clean() - except ValidationError as e: - self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages) - - def _post_clean(self): - """ - An internal hook for performing additional cleaning after form cleaning - is complete. Used for model validation in model forms. - """ - pass - - def clean(self): - """ - Hook for doing any extra form-wide cleaning after Field.clean() been - called on every field. Any ValidationError raised by this method will - not be associated with a particular field; it will have a special-case - association with the field named '__all__'. - """ - return self.cleaned_data - - def has_changed(self): - """ - Returns True if data differs from initial. - """ - return bool(self.changed_data) - - @property - def changed_data(self): - if self._changed_data is None: - self._changed_data = [] - # XXX: For now we're asking the individual widgets whether or not the - # data has changed. It would probably be more efficient to hash the - # initial data, store it in a hidden field, and compare a hash of the - # submitted data, but we'd need a way to easily get the string value - # for a given field. Right now, that logic is embedded in the render - # method of each widget. - for name, field in self.fields.items(): - prefixed_name = self.add_prefix(name) - data_value = field.widget.value_from_datadict(self.data, self.files, prefixed_name) - if not field.show_hidden_initial: - initial_value = self.initial.get(name, field.initial) - if callable(initial_value): - initial_value = initial_value() - else: - initial_prefixed_name = self.add_initial_prefix(name) - hidden_widget = field.hidden_widget() - try: - initial_value = field.to_python(hidden_widget.value_from_datadict( - self.data, self.files, initial_prefixed_name)) - except ValidationError: - # Always assume data has changed if validation fails. - self._changed_data.append(name) - continue - if hasattr(field.widget, '_has_changed'): - warnings.warn("The _has_changed method on widgets is deprecated," - " define it at field level instead.", - PendingDeprecationWarning, stacklevel=2) - if field.widget._has_changed(initial_value, data_value): - self._changed_data.append(name) - elif field._has_changed(initial_value, data_value): - self._changed_data.append(name) - return self._changed_data - - @property - def media(self): - """ - Provide a description of all media required to render the widgets on this form - """ - media = Media() - for field in self.fields.values(): - media = media + field.widget.media - return media - - def is_multipart(self): - """ - Returns True if the form needs to be multipart-encoded, i.e. it has - FileInput. Otherwise, False. - """ - for field in self.fields.values(): - if field.widget.needs_multipart_form: - return True - return False - - def hidden_fields(self): - """ - Returns a list of all the BoundField objects that are hidden fields. - Useful for manual form layout in templates. - """ - return [field for field in self if field.is_hidden] - - def visible_fields(self): - """ - Returns a list of BoundField objects that aren't hidden fields. - The opposite of the hidden_fields() method. - """ - return [field for field in self if not field.is_hidden] - -class Form(six.with_metaclass(DeclarativeFieldsMetaclass, BaseForm)): - "A collection of Fields, plus their associated data." - # This is a separate class from BaseForm in order to abstract the way - # self.fields is specified. This class (Form) is the one that does the - # fancy metaclass stuff purely for the semantic sugar -- it allows one - # to define a form using declarative syntax. - # BaseForm itself has no way of designating self.fields. - -@python_2_unicode_compatible -class BoundField(object): - "A Field plus data" - def __init__(self, form, field, name): - self.form = form - self.field = field - self.name = name - self.html_name = form.add_prefix(name) - self.html_initial_name = form.add_initial_prefix(name) - self.html_initial_id = form.add_initial_prefix(self.auto_id) - if self.field.label is None: - self.label = pretty_name(name) - else: - self.label = self.field.label - self.help_text = field.help_text or '' - - def __str__(self): - """Renders this field as an HTML widget.""" - if self.field.show_hidden_initial: - return self.as_widget() + self.as_hidden(only_initial=True) - return self.as_widget() - - def __iter__(self): - """ - Yields rendered strings that comprise all widgets in this BoundField. - - This really is only useful for RadioSelect widgets, so that you can - iterate over individual radio buttons in a template. - """ - for subwidget in self.field.widget.subwidgets(self.html_name, self.value()): - yield subwidget - - def __len__(self): - return len(list(self.__iter__())) - - def __getitem__(self, idx): - return list(self.__iter__())[idx] - - @property - def errors(self): - """ - Returns an ErrorList for this field. Returns an empty ErrorList - if there are none. - """ - return self.form.errors.get(self.name, self.form.error_class()) - - def as_widget(self, widget=None, attrs=None, only_initial=False): - """ - Renders the field by rendering the passed widget, adding any HTML - attributes passed as attrs. If no widget is specified, then the - field's default widget will be used. - """ - if not widget: - widget = self.field.widget - - if self.field.localize: - widget.is_localized = True - - attrs = attrs or {} - auto_id = self.auto_id - if auto_id and 'id' not in attrs and 'id' not in widget.attrs: - if not only_initial: - attrs['id'] = auto_id - else: - attrs['id'] = self.html_initial_id - - if not only_initial: - name = self.html_name - else: - name = self.html_initial_name - return widget.render(name, self.value(), attrs=attrs) - - def as_text(self, attrs=None, **kwargs): - """ - Returns a string of HTML for representing this as an <input type="text">. - """ - return self.as_widget(TextInput(), attrs, **kwargs) - - def as_textarea(self, attrs=None, **kwargs): - "Returns a string of HTML for representing this as a <textarea>." - return self.as_widget(Textarea(), attrs, **kwargs) - - def as_hidden(self, attrs=None, **kwargs): - """ - Returns a string of HTML for representing this as an <input type="hidden">. - """ - return self.as_widget(self.field.hidden_widget(), attrs, **kwargs) - - @property - def data(self): - """ - Returns the data for this BoundField, or None if it wasn't given. - """ - return self.field.widget.value_from_datadict(self.form.data, self.form.files, self.html_name) - - def value(self): - """ - Returns the value for this BoundField, using the initial value if - the form is not bound or the data otherwise. - """ - if not self.form.is_bound: - data = self.form.initial.get(self.name, self.field.initial) - if callable(data): - data = data() - else: - data = self.field.bound_data( - self.data, self.form.initial.get(self.name, self.field.initial) - ) - return self.field.prepare_value(data) - - def label_tag(self, contents=None, attrs=None, label_suffix=None): - """ - Wraps the given contents in a <label>, if the field has an ID attribute. - contents should be 'mark_safe'd to avoid HTML escaping. If contents - aren't given, uses the field's HTML-escaped label. - - If attrs are given, they're used as HTML attributes on the <label> tag. - - label_suffix allows overriding the form's label_suffix. - """ - contents = contents or self.label - # Only add the suffix if the label does not end in punctuation. - label_suffix = label_suffix if label_suffix is not None else self.form.label_suffix - # Translators: If found as last label character, these punctuation - # characters will prevent the default label_suffix to be appended to the label - if label_suffix and contents and contents[-1] not in _(':?.!'): - contents = format_html('{0}{1}', contents, label_suffix) - widget = self.field.widget - id_ = widget.attrs.get('id') or self.auto_id - if id_: - id_for_label = widget.id_for_label(id_) - if id_for_label: - attrs = dict(attrs or {}, **{'for': id_for_label}) - attrs = flatatt(attrs) if attrs else '' - contents = format_html('<label{0}>{1}</label>', attrs, contents) - else: - contents = conditional_escape(contents) - return mark_safe(contents) - - def css_classes(self, extra_classes=None): - """ - Returns a string of space-separated CSS classes for this field. - """ - if hasattr(extra_classes, 'split'): - extra_classes = extra_classes.split() - extra_classes = set(extra_classes or []) - if self.errors and hasattr(self.form, 'error_css_class'): - extra_classes.add(self.form.error_css_class) - if self.field.required and hasattr(self.form, 'required_css_class'): - extra_classes.add(self.form.required_css_class) - return ' '.join(extra_classes) - - @property - def is_hidden(self): - "Returns True if this BoundField's widget is hidden." - return self.field.widget.is_hidden - - @property - def auto_id(self): - """ - Calculates and returns the ID attribute for this BoundField, if the - associated Form has specified auto_id. Returns an empty string otherwise. - """ - auto_id = self.form.auto_id - if auto_id and '%s' in smart_text(auto_id): - return smart_text(auto_id) % self.html_name - elif auto_id: - return self.html_name - return '' - - @property - def id_for_label(self): - """ - Wrapper around the field widget's `id_for_label` method. - Useful, for example, for focusing on this field regardless of whether - it has a single widget or a MultiWidget. - """ - widget = self.field.widget - id_ = widget.attrs.get('id') or self.auto_id - return widget.id_for_label(id_) diff --git a/lib/python2.7/site-packages/django/forms/formsets.py b/lib/python2.7/site-packages/django/forms/formsets.py deleted file mode 100644 index cb3126e..0000000 --- a/lib/python2.7/site-packages/django/forms/formsets.py +++ /dev/null @@ -1,417 +0,0 @@ -from __future__ import absolute_import, unicode_literals - -from django.core.exceptions import ValidationError -from django.forms import Form -from django.forms.fields import IntegerField, BooleanField -from django.forms.util import ErrorList -from django.forms.widgets import HiddenInput -from django.utils.encoding import python_2_unicode_compatible -from django.utils.functional import cached_property -from django.utils.safestring import mark_safe -from django.utils import six -from django.utils.six.moves import xrange -from django.utils.translation import ungettext, ugettext as _ - - -__all__ = ('BaseFormSet', 'all_valid') - -# special field names -TOTAL_FORM_COUNT = 'TOTAL_FORMS' -INITIAL_FORM_COUNT = 'INITIAL_FORMS' -MAX_NUM_FORM_COUNT = 'MAX_NUM_FORMS' -ORDERING_FIELD_NAME = 'ORDER' -DELETION_FIELD_NAME = 'DELETE' - -# default maximum number of forms in a formset, to prevent memory exhaustion -DEFAULT_MAX_NUM = 1000 - -class ManagementForm(Form): - """ - ``ManagementForm`` is used to keep track of how many form instances - are displayed on the page. If adding new forms via javascript, you should - increment the count field of this form as well. - """ - def __init__(self, *args, **kwargs): - self.base_fields[TOTAL_FORM_COUNT] = IntegerField(widget=HiddenInput) - self.base_fields[INITIAL_FORM_COUNT] = IntegerField(widget=HiddenInput) - # MAX_NUM_FORM_COUNT is output with the rest of the management form, - # but only for the convenience of client-side code. The POST - # value of MAX_NUM_FORM_COUNT returned from the client is not checked. - self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField(required=False, widget=HiddenInput) - super(ManagementForm, self).__init__(*args, **kwargs) - -@python_2_unicode_compatible -class BaseFormSet(object): - """ - A collection of instances of the same Form class. - """ - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - initial=None, error_class=ErrorList): - self.is_bound = data is not None or files is not None - self.prefix = prefix or self.get_default_prefix() - self.auto_id = auto_id - self.data = data or {} - self.files = files or {} - self.initial = initial - self.error_class = error_class - self._errors = None - self._non_form_errors = None - - def __str__(self): - return self.as_table() - - def __iter__(self): - """Yields the forms in the order they should be rendered""" - return iter(self.forms) - - def __getitem__(self, index): - """Returns the form at the given index, based on the rendering order""" - return self.forms[index] - - def __len__(self): - return len(self.forms) - - def __bool__(self): - """All formsets have a management form which is not included in the length""" - return True - - def __nonzero__(self): # Python 2 compatibility - return type(self).__bool__(self) - - @property - def management_form(self): - """Returns the ManagementForm instance for this FormSet.""" - if self.is_bound: - form = ManagementForm(self.data, auto_id=self.auto_id, prefix=self.prefix) - if not form.is_valid(): - raise ValidationError( - _('ManagementForm data is missing or has been tampered with'), - code='missing_management_form', - ) - else: - form = ManagementForm(auto_id=self.auto_id, prefix=self.prefix, initial={ - TOTAL_FORM_COUNT: self.total_form_count(), - INITIAL_FORM_COUNT: self.initial_form_count(), - MAX_NUM_FORM_COUNT: self.max_num - }) - return form - - def total_form_count(self): - """Returns the total number of forms in this FormSet.""" - if self.is_bound: - # return absolute_max if it is lower than the actual total form - # count in the data; this is DoS protection to prevent clients - # from forcing the server to instantiate arbitrary numbers of - # forms - return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max) - else: - initial_forms = self.initial_form_count() - total_forms = initial_forms + self.extra - # Allow all existing related objects/inlines to be displayed, - # but don't allow extra beyond max_num. - if initial_forms > self.max_num >= 0: - total_forms = initial_forms - elif total_forms > self.max_num >= 0: - total_forms = self.max_num - return total_forms - - def initial_form_count(self): - """Returns the number of forms that are required in this FormSet.""" - if self.is_bound: - return self.management_form.cleaned_data[INITIAL_FORM_COUNT] - else: - # Use the length of the initial data if it's there, 0 otherwise. - initial_forms = len(self.initial) if self.initial else 0 - return initial_forms - - @cached_property - def forms(self): - """ - Instantiate forms at first property access. - """ - # DoS protection is included in total_form_count() - forms = [self._construct_form(i) for i in xrange(self.total_form_count())] - return forms - - def _construct_form(self, i, **kwargs): - """ - Instantiates and returns the i-th form instance in a formset. - """ - defaults = { - 'auto_id': self.auto_id, - 'prefix': self.add_prefix(i), - 'error_class': self.error_class, - } - if self.is_bound: - defaults['data'] = self.data - defaults['files'] = self.files - if self.initial and not 'initial' in kwargs: - try: - defaults['initial'] = self.initial[i] - except IndexError: - pass - # Allow extra forms to be empty. - if i >= self.initial_form_count(): - defaults['empty_permitted'] = True - defaults.update(kwargs) - form = self.form(**defaults) - self.add_fields(form, i) - return form - - @property - def initial_forms(self): - """Return a list of all the initial forms in this formset.""" - return self.forms[:self.initial_form_count()] - - @property - def extra_forms(self): - """Return a list of all the extra forms in this formset.""" - return self.forms[self.initial_form_count():] - - @property - def empty_form(self): - form = self.form( - auto_id=self.auto_id, - prefix=self.add_prefix('__prefix__'), - empty_permitted=True, - ) - self.add_fields(form, None) - return form - - @property - def cleaned_data(self): - """ - Returns a list of form.cleaned_data dicts for every form in self.forms. - """ - if not self.is_valid(): - raise AttributeError("'%s' object has no attribute 'cleaned_data'" % self.__class__.__name__) - return [form.cleaned_data for form in self.forms] - - @property - def deleted_forms(self): - """ - Returns a list of forms that have been marked for deletion. - """ - if not self.is_valid() or not self.can_delete: - return [] - # construct _deleted_form_indexes which is just a list of form indexes - # that have had their deletion widget set to True - if not hasattr(self, '_deleted_form_indexes'): - self._deleted_form_indexes = [] - for i in range(0, self.total_form_count()): - form = self.forms[i] - # if this is an extra form and hasn't changed, don't consider it - if i >= self.initial_form_count() and not form.has_changed(): - continue - if self._should_delete_form(form): - self._deleted_form_indexes.append(i) - return [self.forms[i] for i in self._deleted_form_indexes] - - @property - def ordered_forms(self): - """ - Returns a list of form in the order specified by the incoming data. - Raises an AttributeError if ordering is not allowed. - """ - if not self.is_valid() or not self.can_order: - raise AttributeError("'%s' object has no attribute 'ordered_forms'" % self.__class__.__name__) - # Construct _ordering, which is a list of (form_index, order_field_value) - # tuples. After constructing this list, we'll sort it by order_field_value - # so we have a way to get to the form indexes in the order specified - # by the form data. - if not hasattr(self, '_ordering'): - self._ordering = [] - for i in range(0, self.total_form_count()): - form = self.forms[i] - # if this is an extra form and hasn't changed, don't consider it - if i >= self.initial_form_count() and not form.has_changed(): - continue - # don't add data marked for deletion to self.ordered_data - if self.can_delete and self._should_delete_form(form): - continue - self._ordering.append((i, form.cleaned_data[ORDERING_FIELD_NAME])) - # After we're done populating self._ordering, sort it. - # A sort function to order things numerically ascending, but - # None should be sorted below anything else. Allowing None as - # a comparison value makes it so we can leave ordering fields - # blank. - def compare_ordering_key(k): - if k[1] is None: - return (1, 0) # +infinity, larger than any number - return (0, k[1]) - self._ordering.sort(key=compare_ordering_key) - # Return a list of form.cleaned_data dicts in the order specified by - # the form data. - return [self.forms[i[0]] for i in self._ordering] - - @classmethod - def get_default_prefix(cls): - return 'form' - - def non_form_errors(self): - """ - Returns an ErrorList of errors that aren't associated with a particular - form -- i.e., from formset.clean(). Returns an empty ErrorList if there - are none. - """ - if self._non_form_errors is None: - self.full_clean() - return self._non_form_errors - - @property - def errors(self): - """ - Returns a list of form.errors for every form in self.forms. - """ - if self._errors is None: - self.full_clean() - return self._errors - - def total_error_count(self): - """ - Returns the number of errors across all forms in the formset. - """ - return len(self.non_form_errors()) +\ - sum(len(form_errors) for form_errors in self.errors) - - def _should_delete_form(self, form): - """ - Returns whether or not the form was marked for deletion. - """ - return form.cleaned_data.get(DELETION_FIELD_NAME, False) - - def is_valid(self): - """ - Returns True if every form in self.forms is valid. - """ - if not self.is_bound: - return False - # We loop over every form.errors here rather than short circuiting on the - # first failure to make sure validation gets triggered for every form. - forms_valid = True - err = self.errors - for i in range(0, self.total_form_count()): - form = self.forms[i] - if self.can_delete: - if self._should_delete_form(form): - # This form is going to be deleted so any of its errors - # should not cause the entire formset to be invalid. - continue - forms_valid &= form.is_valid() - return forms_valid and not bool(self.non_form_errors()) - - def full_clean(self): - """ - Cleans all of self.data and populates self._errors and - self._non_form_errors. - """ - self._errors = [] - self._non_form_errors = self.error_class() - - if not self.is_bound: # Stop further processing. - return - for i in range(0, self.total_form_count()): - form = self.forms[i] - self._errors.append(form.errors) - try: - if (self.validate_max and - self.total_form_count() - len(self.deleted_forms) > self.max_num) or \ - self.management_form.cleaned_data[TOTAL_FORM_COUNT] > self.absolute_max: - raise ValidationError(ungettext( - "Please submit %d or fewer forms.", - "Please submit %d or fewer forms.", self.max_num) % self.max_num, - code='too_many_forms', - ) - # Give self.clean() a chance to do cross-form validation. - self.clean() - except ValidationError as e: - self._non_form_errors = self.error_class(e.messages) - - def clean(self): - """ - Hook for doing any extra formset-wide cleaning after Form.clean() has - been called on every form. Any ValidationError raised by this method - will not be associated with a particular form; it will be accesible - via formset.non_form_errors() - """ - pass - - def has_changed(self): - """ - Returns true if data in any form differs from initial. - """ - return any(form.has_changed() for form in self) - - def add_fields(self, form, index): - """A hook for adding extra fields on to each form instance.""" - if self.can_order: - # Only pre-fill the ordering field for initial forms. - if index is not None and index < self.initial_form_count(): - form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_('Order'), initial=index+1, required=False) - else: - form.fields[ORDERING_FIELD_NAME] = IntegerField(label=_('Order'), required=False) - if self.can_delete: - form.fields[DELETION_FIELD_NAME] = BooleanField(label=_('Delete'), required=False) - - def add_prefix(self, index): - return '%s-%s' % (self.prefix, index) - - def is_multipart(self): - """ - Returns True if the formset needs to be multipart, i.e. it - has FileInput. Otherwise, False. - """ - if self.forms: - return self.forms[0].is_multipart() - else: - return self.empty_form.is_multipart() - - @property - def media(self): - # All the forms on a FormSet are the same, so you only need to - # interrogate the first form for media. - if self.forms: - return self.forms[0].media - else: - return self.empty_form.media - - def as_table(self): - "Returns this formset rendered as HTML <tr>s -- excluding the <table></table>." - # XXX: there is no semantic division between forms here, there - # probably should be. It might make sense to render each form as a - # table row with each field as a td. - forms = ' '.join([form.as_table() for form in self]) - return mark_safe('\n'.join([six.text_type(self.management_form), forms])) - - def as_p(self): - "Returns this formset rendered as HTML <p>s." - forms = ' '.join([form.as_p() for form in self]) - return mark_safe('\n'.join([six.text_type(self.management_form), forms])) - - def as_ul(self): - "Returns this formset rendered as HTML <li>s." - forms = ' '.join([form.as_ul() for form in self]) - return mark_safe('\n'.join([six.text_type(self.management_form), forms])) - -def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False, - can_delete=False, max_num=None, validate_max=False): - """Return a FormSet for the given form class.""" - if max_num is None: - max_num = DEFAULT_MAX_NUM - # hard limit on forms instantiated, to prevent memory-exhaustion attacks - # limit is simply max_num + DEFAULT_MAX_NUM (which is 2*DEFAULT_MAX_NUM - # if max_num is None in the first place) - absolute_max = max_num + DEFAULT_MAX_NUM - attrs = {'form': form, 'extra': extra, - 'can_order': can_order, 'can_delete': can_delete, - 'max_num': max_num, 'absolute_max': absolute_max, - 'validate_max' : validate_max} - return type(form.__name__ + str('FormSet'), (formset,), attrs) - -def all_valid(formsets): - """Returns true if every formset in formsets is valid.""" - valid = True - for formset in formsets: - if not formset.is_valid(): - valid = False - return valid diff --git a/lib/python2.7/site-packages/django/forms/models.py b/lib/python2.7/site-packages/django/forms/models.py deleted file mode 100644 index 15c0015..0000000 --- a/lib/python2.7/site-packages/django/forms/models.py +++ /dev/null @@ -1,1231 +0,0 @@ -""" -Helper functions for creating Form classes from Django models -and database field objects. -""" - -from __future__ import absolute_import, unicode_literals - -import warnings - -from django.core.exceptions import ValidationError, NON_FIELD_ERRORS, FieldError -from django.forms.fields import Field, ChoiceField -from django.forms.forms import BaseForm, get_declared_fields -from django.forms.formsets import BaseFormSet, formset_factory -from django.forms.util import ErrorList -from django.forms.widgets import (SelectMultiple, HiddenInput, - MultipleHiddenInput, media_property, CheckboxSelectMultiple) -from django.utils.encoding import smart_text, force_text -from django.utils.datastructures import SortedDict -from django.utils import six -from django.utils.text import get_text_list, capfirst -from django.utils.translation import ugettext_lazy as _, ugettext, string_concat - - -__all__ = ( - 'ModelForm', 'BaseModelForm', 'model_to_dict', 'fields_for_model', - 'save_instance', 'ModelChoiceField', 'ModelMultipleChoiceField', - 'ALL_FIELDS', -) - -ALL_FIELDS = '__all__' - - -def construct_instance(form, instance, fields=None, exclude=None): - """ - Constructs and returns a model instance from the bound ``form``'s - ``cleaned_data``, but does not save the returned instance to the - database. - """ - from django.db import models - opts = instance._meta - - cleaned_data = form.cleaned_data - file_field_list = [] - for f in opts.fields: - if not f.editable or isinstance(f, models.AutoField) \ - or not f.name in cleaned_data: - continue - if fields is not None and f.name not in fields: - continue - if exclude and f.name in exclude: - continue - # Defer saving file-type fields until after the other fields, so a - # callable upload_to can use the values from other fields. - if isinstance(f, models.FileField): - file_field_list.append(f) - else: - f.save_form_data(instance, cleaned_data[f.name]) - - for f in file_field_list: - f.save_form_data(instance, cleaned_data[f.name]) - - return instance - -def save_instance(form, instance, fields=None, fail_message='saved', - commit=True, exclude=None, construct=True): - """ - Saves bound Form ``form``'s cleaned_data into model instance ``instance``. - - If commit=True, then the changes to ``instance`` will be saved to the - database. Returns ``instance``. - - If construct=False, assume ``instance`` has already been constructed and - just needs to be saved. - """ - if construct: - instance = construct_instance(form, instance, fields, exclude) - opts = instance._meta - if form.errors: - raise ValueError("The %s could not be %s because the data didn't" - " validate." % (opts.object_name, fail_message)) - - # Wrap up the saving of m2m data as a function. - def save_m2m(): - cleaned_data = form.cleaned_data - # Note that for historical reasons we want to include also - # virtual_fields here. (GenericRelation was previously a fake - # m2m field). - for f in opts.many_to_many + opts.virtual_fields: - if not hasattr(f, 'save_form_data'): - continue - if fields and f.name not in fields: - continue - if exclude and f.name in exclude: - continue - if f.name in cleaned_data: - f.save_form_data(instance, cleaned_data[f.name]) - if commit: - # If we are committing, save the instance and the m2m data immediately. - instance.save() - save_m2m() - else: - # We're not committing. Add a method to the form to allow deferred - # saving of m2m data. - form.save_m2m = save_m2m - return instance - - -# ModelForms ################################################################# - -def model_to_dict(instance, fields=None, exclude=None): - """ - Returns a dict containing the data in ``instance`` suitable for passing as - a Form's ``initial`` keyword argument. - - ``fields`` is an optional list of field names. If provided, only the named - fields will be included in the returned dict. - - ``exclude`` is an optional list of field names. If provided, the named - fields will be excluded from the returned dict, even if they are listed in - the ``fields`` argument. - """ - # avoid a circular import - from django.db.models.fields.related import ManyToManyField - opts = instance._meta - data = {} - for f in opts.concrete_fields + opts.virtual_fields + opts.many_to_many: - if not getattr(f, 'editable', False): - continue - if fields and not f.name in fields: - continue - if exclude and f.name in exclude: - continue - if isinstance(f, ManyToManyField): - # If the object doesn't have a primary key yet, just use an empty - # list for its m2m fields. Calling f.value_from_object will raise - # an exception. - if instance.pk is None: - data[f.name] = [] - else: - # MultipleChoiceWidget needs a list of pks, not object instances. - data[f.name] = list(f.value_from_object(instance).values_list('pk', flat=True)) - else: - data[f.name] = f.value_from_object(instance) - return data - -def fields_for_model(model, fields=None, exclude=None, widgets=None, - formfield_callback=None, localized_fields=None, - labels=None, help_texts=None, error_messages=None): - """ - Returns a ``SortedDict`` containing form fields for the given model. - - ``fields`` is an optional list of field names. If provided, only the named - fields will be included in the returned fields. - - ``exclude`` is an optional list of field names. If provided, the named - fields will be excluded from the returned fields, even if they are listed - in the ``fields`` argument. - - ``widgets`` is a dictionary of model field names mapped to a widget. - - ``localized_fields`` is a list of names of fields which should be localized. - - ``labels`` is a dictionary of model field names mapped to a label. - - ``help_texts`` is a dictionary of model field names mapped to a help text. - - ``error_messages`` is a dictionary of model field names mapped to a - dictionary of error messages. - - ``formfield_callback`` is a callable that takes a model field and returns - a form field. - """ - field_list = [] - ignored = [] - opts = model._meta - # Avoid circular import - from django.db.models.fields import Field as ModelField - sortable_virtual_fields = [f for f in opts.virtual_fields - if isinstance(f, ModelField)] - for f in sorted(opts.concrete_fields + sortable_virtual_fields + opts.many_to_many): - if not getattr(f, 'editable', False): - continue - if fields is not None and not f.name in fields: - continue - if exclude and f.name in exclude: - continue - - kwargs = {} - if widgets and f.name in widgets: - kwargs['widget'] = widgets[f.name] - if localized_fields == ALL_FIELDS or (localized_fields and f.name in localized_fields): - kwargs['localize'] = True - if labels and f.name in labels: - kwargs['label'] = labels[f.name] - if help_texts and f.name in help_texts: - kwargs['help_text'] = help_texts[f.name] - if error_messages and f.name in error_messages: - kwargs['error_messages'] = error_messages[f.name] - - if formfield_callback is None: - formfield = f.formfield(**kwargs) - elif not callable(formfield_callback): - raise TypeError('formfield_callback must be a function or callable') - else: - formfield = formfield_callback(f, **kwargs) - - if formfield: - field_list.append((f.name, formfield)) - else: - ignored.append(f.name) - field_dict = SortedDict(field_list) - if fields: - field_dict = SortedDict( - [(f, field_dict.get(f)) for f in fields - if ((not exclude) or (exclude and f not in exclude)) and (f not in ignored)] - ) - return field_dict - -class ModelFormOptions(object): - def __init__(self, options=None): - self.model = getattr(options, 'model', None) - self.fields = getattr(options, 'fields', None) - self.exclude = getattr(options, 'exclude', None) - self.widgets = getattr(options, 'widgets', None) - self.localized_fields = getattr(options, 'localized_fields', None) - self.labels = getattr(options, 'labels', None) - self.help_texts = getattr(options, 'help_texts', None) - self.error_messages = getattr(options, 'error_messages', None) - - -class ModelFormMetaclass(type): - def __new__(cls, name, bases, attrs): - formfield_callback = attrs.pop('formfield_callback', None) - try: - parents = [b for b in bases if issubclass(b, ModelForm)] - except NameError: - # We are defining ModelForm itself. - parents = None - declared_fields = get_declared_fields(bases, attrs, False) - new_class = super(ModelFormMetaclass, cls).__new__(cls, name, bases, - attrs) - if not parents: - return new_class - - if 'media' not in attrs: - new_class.media = media_property(new_class) - opts = new_class._meta = ModelFormOptions(getattr(new_class, 'Meta', None)) - - # We check if a string was passed to `fields` or `exclude`, - # which is likely to be a mistake where the user typed ('foo') instead - # of ('foo',) - for opt in ['fields', 'exclude', 'localized_fields']: - value = getattr(opts, opt) - if isinstance(value, six.string_types) and value != ALL_FIELDS: - msg = ("%(model)s.Meta.%(opt)s cannot be a string. " - "Did you mean to type: ('%(value)s',)?" % { - 'model': new_class.__name__, - 'opt': opt, - 'value': value, - }) - raise TypeError(msg) - - if opts.model: - # If a model is defined, extract form fields from it. - - if opts.fields is None and opts.exclude is None: - # This should be some kind of assertion error once deprecation - # cycle is complete. - warnings.warn("Creating a ModelForm without either the 'fields' attribute " - "or the 'exclude' attribute is deprecated - form %s " - "needs updating" % name, - PendingDeprecationWarning, stacklevel=2) - - if opts.fields == ALL_FIELDS: - # sentinel for fields_for_model to indicate "get the list of - # fields from the model" - opts.fields = None - - fields = fields_for_model(opts.model, opts.fields, opts.exclude, - opts.widgets, formfield_callback, - opts.localized_fields, opts.labels, - opts.help_texts, opts.error_messages) - - # make sure opts.fields doesn't specify an invalid field - none_model_fields = [k for k, v in six.iteritems(fields) if not v] - missing_fields = set(none_model_fields) - \ - set(declared_fields.keys()) - if missing_fields: - message = 'Unknown field(s) (%s) specified for %s' - message = message % (', '.join(missing_fields), - opts.model.__name__) - raise FieldError(message) - # Override default model fields with any custom declared ones - # (plus, include all the other declared fields). - fields.update(declared_fields) - else: - fields = declared_fields - new_class.declared_fields = declared_fields - new_class.base_fields = fields - return new_class - -class BaseModelForm(BaseForm): - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - initial=None, error_class=ErrorList, label_suffix=None, - empty_permitted=False, instance=None): - opts = self._meta - if opts.model is None: - raise ValueError('ModelForm has no model class specified.') - if instance is None: - # if we didn't get an instance, instantiate a new one - self.instance = opts.model() - object_data = {} - else: - self.instance = instance - object_data = model_to_dict(instance, opts.fields, opts.exclude) - # if initial was provided, it should override the values from instance - if initial is not None: - object_data.update(initial) - # self._validate_unique will be set to True by BaseModelForm.clean(). - # It is False by default so overriding self.clean() and failing to call - # super will stop validate_unique from being called. - self._validate_unique = False - super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data, - error_class, label_suffix, empty_permitted) - - def _update_errors(self, errors): - for field, messages in errors.error_dict.items(): - if field not in self.fields: - continue - field = self.fields[field] - for message in messages: - if isinstance(message, ValidationError): - if message.code in field.error_messages: - message.message = field.error_messages[message.code] - - message_dict = errors.message_dict - for k, v in message_dict.items(): - if k != NON_FIELD_ERRORS: - self._errors.setdefault(k, self.error_class()).extend(v) - # Remove the data from the cleaned_data dict since it was invalid - if k in self.cleaned_data: - del self.cleaned_data[k] - if NON_FIELD_ERRORS in message_dict: - messages = message_dict[NON_FIELD_ERRORS] - self._errors.setdefault(NON_FIELD_ERRORS, self.error_class()).extend(messages) - - def _get_validation_exclusions(self): - """ - For backwards-compatibility, several types of fields need to be - excluded from model validation. See the following tickets for - details: #12507, #12521, #12553 - """ - exclude = [] - # Build up a list of fields that should be excluded from model field - # validation and unique checks. - for f in self.instance._meta.fields: - field = f.name - # Exclude fields that aren't on the form. The developer may be - # adding these values to the model after form validation. - if field not in self.fields: - exclude.append(f.name) - - # Don't perform model validation on fields that were defined - # manually on the form and excluded via the ModelForm's Meta - # class. See #12901. - elif self._meta.fields and field not in self._meta.fields: - exclude.append(f.name) - elif self._meta.exclude and field in self._meta.exclude: - exclude.append(f.name) - - # Exclude fields that failed form validation. There's no need for - # the model fields to validate them as well. - elif field in self._errors.keys(): - exclude.append(f.name) - - # Exclude empty fields that are not required by the form, if the - # underlying model field is required. This keeps the model field - # from raising a required error. Note: don't exclude the field from - # validation if the model field allows blanks. If it does, the blank - # value may be included in a unique check, so cannot be excluded - # from validation. - else: - form_field = self.fields[field] - field_value = self.cleaned_data.get(field, None) - if not f.blank and not form_field.required and field_value in form_field.empty_values: - exclude.append(f.name) - return exclude - - def clean(self): - self._validate_unique = True - return self.cleaned_data - - def _post_clean(self): - opts = self._meta - # Update the model instance with self.cleaned_data. - self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude) - - exclude = self._get_validation_exclusions() - - # Foreign Keys being used to represent inline relationships - # are excluded from basic field value validation. This is for two - # reasons: firstly, the value may not be supplied (#12507; the - # case of providing new values to the admin); secondly the - # object being referred to may not yet fully exist (#12749). - # However, these fields *must* be included in uniqueness checks, - # so this can't be part of _get_validation_exclusions(). - for f_name, field in self.fields.items(): - if isinstance(field, InlineForeignKeyField): - exclude.append(f_name) - - try: - self.instance.full_clean(exclude=exclude, - validate_unique=False) - except ValidationError as e: - self._update_errors(e) - - # Validate uniqueness if needed. - if self._validate_unique: - self.validate_unique() - - def validate_unique(self): - """ - Calls the instance's validate_unique() method and updates the form's - validation errors if any were raised. - """ - exclude = self._get_validation_exclusions() - try: - self.instance.validate_unique(exclude=exclude) - except ValidationError as e: - self._update_errors(e) - - def save(self, commit=True): - """ - Saves this ``form``'s cleaned_data into model instance - ``self.instance``. - - If commit=True, then the changes to ``instance`` will be saved to the - database. Returns ``instance``. - """ - if self.instance.pk is None: - fail_message = 'created' - else: - fail_message = 'changed' - return save_instance(self, self.instance, self._meta.fields, - fail_message, commit, self._meta.exclude, - construct=False) - - save.alters_data = True - -class ModelForm(six.with_metaclass(ModelFormMetaclass, BaseModelForm)): - pass - -def modelform_factory(model, form=ModelForm, fields=None, exclude=None, - formfield_callback=None, widgets=None, localized_fields=None, - labels=None, help_texts=None, error_messages=None): - """ - Returns a ModelForm containing form fields for the given model. - - ``fields`` is an optional list of field names. If provided, only the named - fields will be included in the returned fields. If omitted or '__all__', - all fields will be used. - - ``exclude`` is an optional list of field names. If provided, the named - fields will be excluded from the returned fields, even if they are listed - in the ``fields`` argument. - - ``widgets`` is a dictionary of model field names mapped to a widget. - - ``localized_fields`` is a list of names of fields which should be localized. - - ``formfield_callback`` is a callable that takes a model field and returns - a form field. - - ``labels`` is a dictionary of model field names mapped to a label. - - ``help_texts`` is a dictionary of model field names mapped to a help text. - - ``error_messages`` is a dictionary of model field names mapped to a - dictionary of error messages. - """ - # Create the inner Meta class. FIXME: ideally, we should be able to - # construct a ModelForm without creating and passing in a temporary - # inner class. - - # Build up a list of attributes that the Meta object will have. - attrs = {'model': model} - if fields is not None: - attrs['fields'] = fields - if exclude is not None: - attrs['exclude'] = exclude - if widgets is not None: - attrs['widgets'] = widgets - if localized_fields is not None: - attrs['localized_fields'] = localized_fields - if labels is not None: - attrs['labels'] = labels - if help_texts is not None: - attrs['help_texts'] = help_texts - if error_messages is not None: - attrs['error_messages'] = error_messages - - # If parent form class already has an inner Meta, the Meta we're - # creating needs to inherit from the parent's inner meta. - parent = (object,) - if hasattr(form, 'Meta'): - parent = (form.Meta, object) - Meta = type(str('Meta'), parent, attrs) - - # Give this new form class a reasonable name. - class_name = model.__name__ + str('Form') - - # Class attributes for the new form class. - form_class_attrs = { - 'Meta': Meta, - 'formfield_callback': formfield_callback - } - - # The ModelFormMetaclass will trigger a similar warning/error, but this will - # be difficult to debug for code that needs updating, so we produce the - # warning here too. - if (getattr(Meta, 'fields', None) is None and - getattr(Meta, 'exclude', None) is None): - warnings.warn("Calling modelform_factory without defining 'fields' or " - "'exclude' explicitly is deprecated", - PendingDeprecationWarning, stacklevel=2) - - # Instatiate type(form) in order to use the same metaclass as form. - return type(form)(class_name, (form,), form_class_attrs) - - -# ModelFormSets ############################################################## - -class BaseModelFormSet(BaseFormSet): - """ - A ``FormSet`` for editing a queryset and/or adding new objects to it. - """ - model = None - - def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, - queryset=None, **kwargs): - self.queryset = queryset - self.initial_extra = kwargs.pop('initial', None) - defaults = {'data': data, 'files': files, 'auto_id': auto_id, 'prefix': prefix} - defaults.update(kwargs) - super(BaseModelFormSet, self).__init__(**defaults) - - def initial_form_count(self): - """Returns the number of forms that are required in this FormSet.""" - if not (self.data or self.files): - return len(self.get_queryset()) - return super(BaseModelFormSet, self).initial_form_count() - - def _existing_object(self, pk): - if not hasattr(self, '_object_dict'): - self._object_dict = dict([(o.pk, o) for o in self.get_queryset()]) - return self._object_dict.get(pk) - - def _construct_form(self, i, **kwargs): - if self.is_bound and i < self.initial_form_count(): - # Import goes here instead of module-level because importing - # django.db has side effects. - from django.db import connections - pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name) - pk = self.data[pk_key] - pk_field = self.model._meta.pk - pk = pk_field.get_db_prep_lookup('exact', pk, - connection=connections[self.get_queryset().db]) - if isinstance(pk, list): - pk = pk[0] - kwargs['instance'] = self._existing_object(pk) - if i < self.initial_form_count() and not kwargs.get('instance'): - kwargs['instance'] = self.get_queryset()[i] - if i >= self.initial_form_count() and self.initial_extra: - # Set initial values for extra forms - try: - kwargs['initial'] = self.initial_extra[i-self.initial_form_count()] - except IndexError: - pass - return super(BaseModelFormSet, self)._construct_form(i, **kwargs) - - def get_queryset(self): - if not hasattr(self, '_queryset'): - if self.queryset is not None: - qs = self.queryset - else: - qs = self.model._default_manager.get_queryset() - - # If the queryset isn't already ordered we need to add an - # artificial ordering here to make sure that all formsets - # constructed from this queryset have the same form order. - if not qs.ordered: - qs = qs.order_by(self.model._meta.pk.name) - - # Removed queryset limiting here. As per discussion re: #13023 - # on django-dev, max_num should not prevent existing - # related objects/inlines from being displayed. - self._queryset = qs - return self._queryset - - def save_new(self, form, commit=True): - """Saves and returns a new model instance for the given form.""" - return form.save(commit=commit) - - def save_existing(self, form, instance, commit=True): - """Saves and returns an existing model instance for the given form.""" - return form.save(commit=commit) - - def save(self, commit=True): - """Saves model instances for every form, adding and changing instances - as necessary, and returns the list of instances. - """ - if not commit: - self.saved_forms = [] - def save_m2m(): - for form in self.saved_forms: - form.save_m2m() - self.save_m2m = save_m2m - return self.save_existing_objects(commit) + self.save_new_objects(commit) - - save.alters_data = True - - def clean(self): - self.validate_unique() - - def validate_unique(self): - # Collect unique_checks and date_checks to run from all the forms. - all_unique_checks = set() - all_date_checks = set() - forms_to_delete = self.deleted_forms - valid_forms = [form for form in self.forms if form.is_valid() and form not in forms_to_delete] - for form in valid_forms: - exclude = form._get_validation_exclusions() - unique_checks, date_checks = form.instance._get_unique_checks(exclude=exclude) - all_unique_checks = all_unique_checks.union(set(unique_checks)) - all_date_checks = all_date_checks.union(set(date_checks)) - - errors = [] - # Do each of the unique checks (unique and unique_together) - for uclass, unique_check in all_unique_checks: - seen_data = set() - for form in valid_forms: - # get data for each field of each of unique_check - row_data = tuple([form.cleaned_data[field] for field in unique_check if field in form.cleaned_data]) - if row_data and not None in row_data: - # if we've already seen it then we have a uniqueness failure - if row_data in seen_data: - # poke error messages into the right places and mark - # the form as invalid - errors.append(self.get_unique_error_message(unique_check)) - form._errors[NON_FIELD_ERRORS] = self.error_class([self.get_form_error()]) - # remove the data from the cleaned_data dict since it was invalid - for field in unique_check: - if field in form.cleaned_data: - del form.cleaned_data[field] - # mark the data as seen - seen_data.add(row_data) - # iterate over each of the date checks now - for date_check in all_date_checks: - seen_data = set() - uclass, lookup, field, unique_for = date_check - for form in valid_forms: - # see if we have data for both fields - if (form.cleaned_data and form.cleaned_data[field] is not None - and form.cleaned_data[unique_for] is not None): - # if it's a date lookup we need to get the data for all the fields - if lookup == 'date': - date = form.cleaned_data[unique_for] - date_data = (date.year, date.month, date.day) - # otherwise it's just the attribute on the date/datetime - # object - else: - date_data = (getattr(form.cleaned_data[unique_for], lookup),) - data = (form.cleaned_data[field],) + date_data - # if we've already seen it then we have a uniqueness failure - if data in seen_data: - # poke error messages into the right places and mark - # the form as invalid - errors.append(self.get_date_error_message(date_check)) - form._errors[NON_FIELD_ERRORS] = self.error_class([self.get_form_error()]) - # remove the data from the cleaned_data dict since it was invalid - del form.cleaned_data[field] - # mark the data as seen - seen_data.add(data) - if errors: - raise ValidationError(errors) - - def get_unique_error_message(self, unique_check): - if len(unique_check) == 1: - return ugettext("Please correct the duplicate data for %(field)s.") % { - "field": unique_check[0], - } - else: - return ugettext("Please correct the duplicate data for %(field)s, " - "which must be unique.") % { - "field": get_text_list(unique_check, six.text_type(_("and"))), - } - - def get_date_error_message(self, date_check): - return ugettext("Please correct the duplicate data for %(field_name)s " - "which must be unique for the %(lookup)s in %(date_field)s.") % { - 'field_name': date_check[2], - 'date_field': date_check[3], - 'lookup': six.text_type(date_check[1]), - } - - def get_form_error(self): - return ugettext("Please correct the duplicate values below.") - - def save_existing_objects(self, commit=True): - self.changed_objects = [] - self.deleted_objects = [] - if not self.initial_forms: - return [] - - saved_instances = [] - forms_to_delete = self.deleted_forms - for form in self.initial_forms: - pk_name = self._pk_field.name - raw_pk_value = form._raw_value(pk_name) - - # clean() for different types of PK fields can sometimes return - # the model instance, and sometimes the PK. Handle either. - pk_value = form.fields[pk_name].clean(raw_pk_value) - pk_value = getattr(pk_value, 'pk', pk_value) - - obj = self._existing_object(pk_value) - if form in forms_to_delete: - self.deleted_objects.append(obj) - obj.delete() - continue - if form.has_changed(): - self.changed_objects.append((obj, form.changed_data)) - saved_instances.append(self.save_existing(form, obj, commit=commit)) - if not commit: - self.saved_forms.append(form) - return saved_instances - - def save_new_objects(self, commit=True): - self.new_objects = [] - for form in self.extra_forms: - if not form.has_changed(): - continue - # If someone has marked an add form for deletion, don't save the - # object. - if self.can_delete and self._should_delete_form(form): - continue - self.new_objects.append(self.save_new(form, commit=commit)) - if not commit: - self.saved_forms.append(form) - return self.new_objects - - def add_fields(self, form, index): - """Add a hidden field for the object's primary key.""" - from django.db.models import AutoField, OneToOneField, ForeignKey - self._pk_field = pk = self.model._meta.pk - # If a pk isn't editable, then it won't be on the form, so we need to - # add it here so we can tell which object is which when we get the - # data back. Generally, pk.editable should be false, but for some - # reason, auto_created pk fields and AutoField's editable attribute is - # True, so check for that as well. - def pk_is_not_editable(pk): - return ((not pk.editable) or (pk.auto_created or isinstance(pk, AutoField)) - or (pk.rel and pk.rel.parent_link and pk_is_not_editable(pk.rel.to._meta.pk))) - if pk_is_not_editable(pk) or pk.name not in form.fields: - if form.is_bound: - pk_value = form.instance.pk - else: - try: - if index is not None: - pk_value = self.get_queryset()[index].pk - else: - pk_value = None - except IndexError: - pk_value = None - if isinstance(pk, OneToOneField) or isinstance(pk, ForeignKey): - qs = pk.rel.to._default_manager.get_queryset() - else: - qs = self.model._default_manager.get_queryset() - qs = qs.using(form.instance._state.db) - if form._meta.widgets: - widget = form._meta.widgets.get(self._pk_field.name, HiddenInput) - else: - widget = HiddenInput - form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=widget) - super(BaseModelFormSet, self).add_fields(form, index) - -def modelformset_factory(model, form=ModelForm, formfield_callback=None, - formset=BaseModelFormSet, extra=1, can_delete=False, - can_order=False, max_num=None, fields=None, exclude=None, - widgets=None, validate_max=False, localized_fields=None, - labels=None, help_texts=None, error_messages=None): - """ - Returns a FormSet class for the given Django model class. - """ - # modelform_factory will produce the same warning/error, but that will be - # difficult to debug for code that needs upgrading, so we produce the - # warning here too. This logic is reproducing logic inside - # modelform_factory, but it can be removed once the deprecation cycle is - # complete, since the validation exception will produce a helpful - # stacktrace. - meta = getattr(form, 'Meta', None) - if meta is None: - meta = type(str('Meta'), (object,), {}) - if (getattr(meta, 'fields', fields) is None and - getattr(meta, 'exclude', exclude) is None): - warnings.warn("Calling modelformset_factory without defining 'fields' or " - "'exclude' explicitly is deprecated", - PendingDeprecationWarning, stacklevel=2) - - form = modelform_factory(model, form=form, fields=fields, exclude=exclude, - formfield_callback=formfield_callback, - widgets=widgets, localized_fields=localized_fields, - labels=labels, help_texts=help_texts, error_messages=error_messages) - FormSet = formset_factory(form, formset, extra=extra, max_num=max_num, - can_order=can_order, can_delete=can_delete, - validate_max=validate_max) - FormSet.model = model - return FormSet - - -# InlineFormSets ############################################################# - -class BaseInlineFormSet(BaseModelFormSet): - """A formset for child objects related to a parent.""" - def __init__(self, data=None, files=None, instance=None, - save_as_new=False, prefix=None, queryset=None, **kwargs): - if instance is None: - self.instance = self.fk.rel.to() - else: - self.instance = instance - self.save_as_new = save_as_new - if queryset is None: - queryset = self.model._default_manager - if self.instance.pk is not None: - qs = queryset.filter(**{self.fk.name: self.instance}) - else: - qs = queryset.none() - super(BaseInlineFormSet, self).__init__(data, files, prefix=prefix, - queryset=qs, **kwargs) - - def initial_form_count(self): - if self.save_as_new: - return 0 - return super(BaseInlineFormSet, self).initial_form_count() - - - def _construct_form(self, i, **kwargs): - form = super(BaseInlineFormSet, self)._construct_form(i, **kwargs) - if self.save_as_new: - # Remove the primary key from the form's data, we are only - # creating new instances - form.data[form.add_prefix(self._pk_field.name)] = None - - # Remove the foreign key from the form's data - form.data[form.add_prefix(self.fk.name)] = None - - # Set the fk value here so that the form can do its validation. - setattr(form.instance, self.fk.get_attname(), self.instance.pk) - return form - - @classmethod - def get_default_prefix(cls): - from django.db.models.fields.related import RelatedObject - return RelatedObject(cls.fk.rel.to, cls.model, cls.fk).get_accessor_name().replace('+','') - - def save_new(self, form, commit=True): - # Use commit=False so we can assign the parent key afterwards, then - # save the object. - obj = form.save(commit=False) - pk_value = getattr(self.instance, self.fk.rel.field_name) - setattr(obj, self.fk.get_attname(), getattr(pk_value, 'pk', pk_value)) - if commit: - obj.save() - # form.save_m2m() can be called via the formset later on if commit=False - if commit and hasattr(form, 'save_m2m'): - form.save_m2m() - return obj - - def add_fields(self, form, index): - super(BaseInlineFormSet, self).add_fields(form, index) - if self._pk_field == self.fk: - name = self._pk_field.name - kwargs = {'pk_field': True} - else: - # The foreign key field might not be on the form, so we poke at the - # Model field to get the label, since we need that for error messages. - name = self.fk.name - kwargs = { - 'label': getattr(form.fields.get(name), 'label', capfirst(self.fk.verbose_name)) - } - if self.fk.rel.field_name != self.fk.rel.to._meta.pk.name: - kwargs['to_field'] = self.fk.rel.field_name - - form.fields[name] = InlineForeignKeyField(self.instance, **kwargs) - - # Add the generated field to form._meta.fields if it's defined to make - # sure validation isn't skipped on that field. - if form._meta.fields: - if isinstance(form._meta.fields, tuple): - form._meta.fields = list(form._meta.fields) - form._meta.fields.append(self.fk.name) - - def get_unique_error_message(self, unique_check): - unique_check = [field for field in unique_check if field != self.fk.name] - return super(BaseInlineFormSet, self).get_unique_error_message(unique_check) - - -def _get_foreign_key(parent_model, model, fk_name=None, can_fail=False): - """ - Finds and returns the ForeignKey from model to parent if there is one - (returns None if can_fail is True and no such field exists). If fk_name is - provided, assume it is the name of the ForeignKey field. Unles can_fail is - True, an exception is raised if there is no ForeignKey from model to - parent_model. - """ - # avoid circular import - from django.db.models import ForeignKey - opts = model._meta - if fk_name: - fks_to_parent = [f for f in opts.fields if f.name == fk_name] - if len(fks_to_parent) == 1: - fk = fks_to_parent[0] - if not isinstance(fk, ForeignKey) or \ - (fk.rel.to != parent_model and - fk.rel.to not in parent_model._meta.get_parent_list()): - raise Exception("fk_name '%s' is not a ForeignKey to %s" % (fk_name, parent_model)) - elif len(fks_to_parent) == 0: - raise Exception("%s has no field named '%s'" % (model, fk_name)) - else: - # Try to discover what the ForeignKey from model to parent_model is - fks_to_parent = [ - f for f in opts.fields - if isinstance(f, ForeignKey) - and (f.rel.to == parent_model - or f.rel.to in parent_model._meta.get_parent_list()) - ] - if len(fks_to_parent) == 1: - fk = fks_to_parent[0] - elif len(fks_to_parent) == 0: - if can_fail: - return - raise Exception("%s has no ForeignKey to %s" % (model, parent_model)) - else: - raise Exception("%s has more than 1 ForeignKey to %s" % (model, parent_model)) - return fk - - -def inlineformset_factory(parent_model, model, form=ModelForm, - formset=BaseInlineFormSet, fk_name=None, - fields=None, exclude=None, extra=3, can_order=False, - can_delete=True, max_num=None, formfield_callback=None, - widgets=None, validate_max=False, localized_fields=None, - labels=None, help_texts=None, error_messages=None): - """ - Returns an ``InlineFormSet`` for the given kwargs. - - You must provide ``fk_name`` if ``model`` has more than one ``ForeignKey`` - to ``parent_model``. - """ - fk = _get_foreign_key(parent_model, model, fk_name=fk_name) - # enforce a max_num=1 when the foreign key to the parent model is unique. - if fk.unique: - max_num = 1 - kwargs = { - 'form': form, - 'formfield_callback': formfield_callback, - 'formset': formset, - 'extra': extra, - 'can_delete': can_delete, - 'can_order': can_order, - 'fields': fields, - 'exclude': exclude, - 'max_num': max_num, - 'widgets': widgets, - 'validate_max': validate_max, - 'localized_fields': localized_fields, - 'labels': labels, - 'help_texts': help_texts, - 'error_messages': error_messages, - } - FormSet = modelformset_factory(model, **kwargs) - FormSet.fk = fk - return FormSet - - -# Fields ##################################################################### - -class InlineForeignKeyField(Field): - """ - A basic integer field that deals with validating the given value to a - given parent instance in an inline. - """ - widget = HiddenInput - default_error_messages = { - 'invalid_choice': _('The inline foreign key did not match the parent instance primary key.'), - } - - def __init__(self, parent_instance, *args, **kwargs): - self.parent_instance = parent_instance - self.pk_field = kwargs.pop("pk_field", False) - self.to_field = kwargs.pop("to_field", None) - if self.parent_instance is not None: - if self.to_field: - kwargs["initial"] = getattr(self.parent_instance, self.to_field) - else: - kwargs["initial"] = self.parent_instance.pk - kwargs["required"] = False - super(InlineForeignKeyField, self).__init__(*args, **kwargs) - - def clean(self, value): - if value in self.empty_values: - if self.pk_field: - return None - # if there is no value act as we did before. - return self.parent_instance - # ensure the we compare the values as equal types. - if self.to_field: - orig = getattr(self.parent_instance, self.to_field) - else: - orig = self.parent_instance.pk - if force_text(value) != force_text(orig): - raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice') - return self.parent_instance - - def _has_changed(self, initial, data): - return False - -class ModelChoiceIterator(object): - def __init__(self, field): - self.field = field - self.queryset = field.queryset - - def __iter__(self): - if self.field.empty_label is not None: - yield ("", self.field.empty_label) - if self.field.cache_choices: - if self.field.choice_cache is None: - self.field.choice_cache = [ - self.choice(obj) for obj in self.queryset.all() - ] - for choice in self.field.choice_cache: - yield choice - else: - for obj in self.queryset.all(): - yield self.choice(obj) - - def __len__(self): - return len(self.queryset) +\ - (1 if self.field.empty_label is not None else 0) - - def choice(self, obj): - return (self.field.prepare_value(obj), self.field.label_from_instance(obj)) - -class ModelChoiceField(ChoiceField): - """A ChoiceField whose choices are a model QuerySet.""" - # This class is a subclass of ChoiceField for purity, but it doesn't - # actually use any of ChoiceField's implementation. - default_error_messages = { - 'invalid_choice': _('Select a valid choice. That choice is not one of' - ' the available choices.'), - } - - def __init__(self, queryset, empty_label="---------", cache_choices=False, - required=True, widget=None, label=None, initial=None, - help_text='', to_field_name=None, *args, **kwargs): - if required and (initial is not None): - self.empty_label = None - else: - self.empty_label = empty_label - self.cache_choices = cache_choices - - # Call Field instead of ChoiceField __init__() because we don't need - # ChoiceField.__init__(). - Field.__init__(self, required, widget, label, initial, help_text, - *args, **kwargs) - self.queryset = queryset - self.choice_cache = None - self.to_field_name = to_field_name - - def __deepcopy__(self, memo): - result = super(ChoiceField, self).__deepcopy__(memo) - # Need to force a new ModelChoiceIterator to be created, bug #11183 - result.queryset = result.queryset - return result - - def _get_queryset(self): - return self._queryset - - def _set_queryset(self, queryset): - self._queryset = queryset - self.widget.choices = self.choices - - queryset = property(_get_queryset, _set_queryset) - - # this method will be used to create object labels by the QuerySetIterator. - # Override it to customize the label. - def label_from_instance(self, obj): - """ - This method is used to convert objects into strings; it's used to - generate the labels for the choices presented by this object. Subclasses - can override this method to customize the display of the choices. - """ - return smart_text(obj) - - def _get_choices(self): - # If self._choices is set, then somebody must have manually set - # the property self.choices. In this case, just return self._choices. - if hasattr(self, '_choices'): - return self._choices - - # Otherwise, execute the QuerySet in self.queryset to determine the - # choices dynamically. Return a fresh ModelChoiceIterator that has not been - # consumed. Note that we're instantiating a new ModelChoiceIterator *each* - # time _get_choices() is called (and, thus, each time self.choices is - # accessed) so that we can ensure the QuerySet has not been consumed. This - # construct might look complicated but it allows for lazy evaluation of - # the queryset. - return ModelChoiceIterator(self) - - choices = property(_get_choices, ChoiceField._set_choices) - - def prepare_value(self, value): - if hasattr(value, '_meta'): - if self.to_field_name: - return value.serializable_value(self.to_field_name) - else: - return value.pk - return super(ModelChoiceField, self).prepare_value(value) - - def to_python(self, value): - if value in self.empty_values: - return None - try: - key = self.to_field_name or 'pk' - value = self.queryset.get(**{key: value}) - except (ValueError, self.queryset.model.DoesNotExist): - raise ValidationError(self.error_messages['invalid_choice'], code='invalid_choice') - return value - - def validate(self, value): - return Field.validate(self, value) - - def _has_changed(self, initial, data): - initial_value = initial if initial is not None else '' - data_value = data if data is not None else '' - return force_text(self.prepare_value(initial_value)) != force_text(data_value) - -class ModelMultipleChoiceField(ModelChoiceField): - """A MultipleChoiceField whose choices are a model QuerySet.""" - widget = SelectMultiple - hidden_widget = MultipleHiddenInput - default_error_messages = { - 'list': _('Enter a list of values.'), - 'invalid_choice': _('Select a valid choice. %(value)s is not one of the' - ' available choices.'), - 'invalid_pk_value': _('"%(pk)s" is not a valid value for a primary key.') - } - - def __init__(self, queryset, cache_choices=False, required=True, - widget=None, label=None, initial=None, - help_text='', *args, **kwargs): - super(ModelMultipleChoiceField, self).__init__(queryset, None, - cache_choices, required, widget, label, initial, help_text, - *args, **kwargs) - # Remove this in Django 1.8 - if isinstance(self.widget, SelectMultiple) and not isinstance(self.widget, CheckboxSelectMultiple): - msg = _('Hold down "Control", or "Command" on a Mac, to select more than one.') - self.help_text = string_concat(self.help_text, ' ', msg) - - def to_python(self, value): - if not value: - return [] - to_py = super(ModelMultipleChoiceField, self).to_python - return [to_py(val) for val in value] - - def clean(self, value): - if self.required and not value: - raise ValidationError(self.error_messages['required'], code='required') - elif not self.required and not value: - return self.queryset.none() - if not isinstance(value, (list, tuple)): - raise ValidationError(self.error_messages['list'], code='list') - key = self.to_field_name or 'pk' - for pk in value: - try: - self.queryset.filter(**{key: pk}) - except ValueError: - raise ValidationError( - self.error_messages['invalid_pk_value'], - code='invalid_pk_value', - params={'pk': pk}, - ) - qs = self.queryset.filter(**{'%s__in' % key: value}) - pks = set([force_text(getattr(o, key)) for o in qs]) - for val in value: - if force_text(val) not in pks: - raise ValidationError( - self.error_messages['invalid_choice'], - code='invalid_choice', - params={'value': val}, - ) - # Since this overrides the inherited ModelChoiceField.clean - # we run custom validators here - self.run_validators(value) - return qs - - def prepare_value(self, value): - if (hasattr(value, '__iter__') and - not isinstance(value, six.text_type) and - not hasattr(value, '_meta')): - return [super(ModelMultipleChoiceField, self).prepare_value(v) for v in value] - return super(ModelMultipleChoiceField, self).prepare_value(value) - - def _has_changed(self, initial, data): - if initial is None: - initial = [] - if data is None: - data = [] - if len(initial) != len(data): - return True - initial_set = set([force_text(value) for value in self.prepare_value(initial)]) - data_set = set([force_text(value) for value in data]) - return data_set != initial_set - - -def modelform_defines_fields(form_class): - return (form_class is not None and ( - hasattr(form_class, '_meta') and - (form_class._meta.fields is not None or - form_class._meta.exclude is not None) - )) diff --git a/lib/python2.7/site-packages/django/forms/util.py b/lib/python2.7/site-packages/django/forms/util.py deleted file mode 100644 index 0a73320..0000000 --- a/lib/python2.7/site-packages/django/forms/util.py +++ /dev/null @@ -1,103 +0,0 @@ -from __future__ import unicode_literals - -from django.conf import settings -from django.utils.html import format_html, format_html_join -from django.utils.encoding import force_text, python_2_unicode_compatible -from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ -from django.utils import six -import sys - -# Import ValidationError so that it can be imported from this -# module to maintain backwards compatibility. -from django.core.exceptions import ValidationError - -def flatatt(attrs): - """ - Convert a dictionary of attributes to a single string. - The returned string will contain a leading space followed by key="value", - XML-style pairs. It is assumed that the keys do not need to be XML-escaped. - If the passed dictionary is empty, then return an empty string. - - The result is passed through 'mark_safe'. - """ - return format_html_join('', ' {0}="{1}"', sorted(attrs.items())) - -@python_2_unicode_compatible -class ErrorDict(dict): - """ - A collection of errors that knows how to display itself in various formats. - - The dictionary keys are the field names, and the values are the errors. - """ - def __str__(self): - return self.as_ul() - - def as_ul(self): - if not self: return '' - return format_html('<ul class="errorlist">{0}</ul>', - format_html_join('', '<li>{0}{1}</li>', - ((k, force_text(v)) - for k, v in self.items()) - )) - - def as_text(self): - return '\n'.join(['* %s\n%s' % (k, '\n'.join([' * %s' % force_text(i) for i in v])) for k, v in self.items()]) - -@python_2_unicode_compatible -class ErrorList(list): - """ - A collection of errors that knows how to display itself in various formats. - """ - def __str__(self): - return self.as_ul() - - def as_ul(self): - if not self: return '' - return format_html('<ul class="errorlist">{0}</ul>', - format_html_join('', '<li>{0}</li>', - ((force_text(e),) for e in self) - ) - ) - - def as_text(self): - if not self: return '' - return '\n'.join(['* %s' % force_text(e) for e in self]) - - def __repr__(self): - return repr([force_text(e) for e in self]) - -# Utilities for time zone support in DateTimeField et al. - -def from_current_timezone(value): - """ - When time zone support is enabled, convert naive datetimes - entered in the current time zone to aware datetimes. - """ - if settings.USE_TZ and value is not None and timezone.is_naive(value): - current_timezone = timezone.get_current_timezone() - try: - return timezone.make_aware(value, current_timezone) - except Exception: - message = _( - '%(datetime)s couldn\'t be interpreted ' - 'in time zone %(current_timezone)s; it ' - 'may be ambiguous or it may not exist.' - ) - params = {'datetime': value, 'current_timezone': current_timezone} - six.reraise(ValidationError, ValidationError( - message, - code='ambiguous_timezone', - params=params, - ), sys.exc_info()[2]) - return value - -def to_current_timezone(value): - """ - When time zone support is enabled, convert aware datetimes - to naive dateimes in the current time zone for display. - """ - if settings.USE_TZ and value is not None and timezone.is_aware(value): - current_timezone = timezone.get_current_timezone() - return timezone.make_naive(value, current_timezone) - return value 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 |