web/lib/django/forms/fields.py
changeset 0 0d40e90630ef
child 29 cc9b7e14412b
equal deleted inserted replaced
-1:000000000000 0:0d40e90630ef
       
     1 """
       
     2 Field classes.
       
     3 """
       
     4 
       
     5 import copy
       
     6 import datetime
       
     7 import os
       
     8 import re
       
     9 import time
       
    10 import urlparse
       
    11 try:
       
    12     from cStringIO import StringIO
       
    13 except ImportError:
       
    14     from StringIO import StringIO
       
    15 
       
    16 # Python 2.3 fallbacks
       
    17 try:
       
    18     from decimal import Decimal, DecimalException
       
    19 except ImportError:
       
    20     from django.utils._decimal import Decimal, DecimalException
       
    21 try:
       
    22     set
       
    23 except NameError:
       
    24     from sets import Set as set
       
    25 
       
    26 import django.core.exceptions
       
    27 from django.utils.translation import ugettext_lazy as _
       
    28 from django.utils.encoding import smart_unicode, smart_str
       
    29 
       
    30 from util import ErrorList, ValidationError
       
    31 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, FileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget
       
    32 
       
    33 __all__ = (
       
    34     'Field', 'CharField', 'IntegerField',
       
    35     'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
       
    36     'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
       
    37     'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField', 'TimeField',
       
    38     'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
       
    39     'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
       
    40     'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
       
    41     'SplitDateTimeField', 'IPAddressField', 'FilePathField', 'SlugField',
       
    42     'TypedChoiceField'
       
    43 )
       
    44 
       
    45 # These values, if given to to_python(), will trigger the self.required check.
       
    46 EMPTY_VALUES = (None, '')
       
    47 
       
    48 
       
    49 class Field(object):
       
    50     widget = TextInput # Default widget to use when rendering this type of Field.
       
    51     hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden".
       
    52     default_error_messages = {
       
    53         'required': _(u'This field is required.'),
       
    54         'invalid': _(u'Enter a valid value.'),
       
    55     }
       
    56 
       
    57     # Tracks each time a Field instance is created. Used to retain order.
       
    58     creation_counter = 0
       
    59 
       
    60     def __init__(self, required=True, widget=None, label=None, initial=None,
       
    61                  help_text=None, error_messages=None, show_hidden_initial=False):
       
    62         # required -- Boolean that specifies whether the field is required.
       
    63         #             True by default.
       
    64         # widget -- A Widget class, or instance of a Widget class, that should
       
    65         #           be used for this Field when displaying it. Each Field has a
       
    66         #           default Widget that it'll use if you don't specify this. In
       
    67         #           most cases, the default widget is TextInput.
       
    68         # label -- A verbose name for this field, for use in displaying this
       
    69         #          field in a form. By default, Django will use a "pretty"
       
    70         #          version of the form field name, if the Field is part of a
       
    71         #          Form.
       
    72         # initial -- A value to use in this Field's initial display. This value
       
    73         #            is *not* used as a fallback if data isn't given.
       
    74         # help_text -- An optional string to use as "help text" for this Field.
       
    75         # show_hidden_initial -- Boolean that specifies if it is needed to render a
       
    76         #                        hidden widget with initial value after widget.
       
    77         if label is not None:
       
    78             label = smart_unicode(label)
       
    79         self.required, self.label, self.initial = required, label, initial
       
    80         self.show_hidden_initial = show_hidden_initial
       
    81         if help_text is None:
       
    82             self.help_text = u''
       
    83         else:
       
    84             self.help_text = smart_unicode(help_text)
       
    85         widget = widget or self.widget
       
    86         if isinstance(widget, type):
       
    87             widget = widget()
       
    88 
       
    89         # Hook into self.widget_attrs() for any Field-specific HTML attributes.
       
    90         extra_attrs = self.widget_attrs(widget)
       
    91         if extra_attrs:
       
    92             widget.attrs.update(extra_attrs)
       
    93 
       
    94         self.widget = widget
       
    95 
       
    96         # Increase the creation counter, and save our local copy.
       
    97         self.creation_counter = Field.creation_counter
       
    98         Field.creation_counter += 1
       
    99 
       
   100         def set_class_error_messages(messages, klass):
       
   101             for base_class in klass.__bases__:
       
   102                 set_class_error_messages(messages, base_class)
       
   103             messages.update(getattr(klass, 'default_error_messages', {}))
       
   104 
       
   105         messages = {}
       
   106         set_class_error_messages(messages, self.__class__)
       
   107         messages.update(error_messages or {})
       
   108         self.error_messages = messages
       
   109 
       
   110     def clean(self, value):
       
   111         """
       
   112         Validates the given value and returns its "cleaned" value as an
       
   113         appropriate Python object.
       
   114 
       
   115         Raises ValidationError for any errors.
       
   116         """
       
   117         if self.required and value in EMPTY_VALUES:
       
   118             raise ValidationError(self.error_messages['required'])
       
   119         return value
       
   120 
       
   121     def widget_attrs(self, widget):
       
   122         """
       
   123         Given a Widget instance (*not* a Widget class), returns a dictionary of
       
   124         any HTML attributes that should be added to the Widget, based on this
       
   125         Field.
       
   126         """
       
   127         return {}
       
   128 
       
   129     def __deepcopy__(self, memo):
       
   130         result = copy.copy(self)
       
   131         memo[id(self)] = result
       
   132         result.widget = copy.deepcopy(self.widget, memo)
       
   133         return result
       
   134 
       
   135 class CharField(Field):
       
   136     default_error_messages = {
       
   137         'max_length': _(u'Ensure this value has at most %(max)d characters (it has %(length)d).'),
       
   138         'min_length': _(u'Ensure this value has at least %(min)d characters (it has %(length)d).'),
       
   139     }
       
   140 
       
   141     def __init__(self, max_length=None, min_length=None, *args, **kwargs):
       
   142         self.max_length, self.min_length = max_length, min_length
       
   143         super(CharField, self).__init__(*args, **kwargs)
       
   144 
       
   145     def clean(self, value):
       
   146         "Validates max_length and min_length. Returns a Unicode object."
       
   147         super(CharField, self).clean(value)
       
   148         if value in EMPTY_VALUES:
       
   149             return u''
       
   150         value = smart_unicode(value)
       
   151         value_length = len(value)
       
   152         if self.max_length is not None and value_length > self.max_length:
       
   153             raise ValidationError(self.error_messages['max_length'] % {'max': self.max_length, 'length': value_length})
       
   154         if self.min_length is not None and value_length < self.min_length:
       
   155             raise ValidationError(self.error_messages['min_length'] % {'min': self.min_length, 'length': value_length})
       
   156         return value
       
   157 
       
   158     def widget_attrs(self, widget):
       
   159         if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
       
   160             # The HTML attribute is maxlength, not max_length.
       
   161             return {'maxlength': str(self.max_length)}
       
   162 
       
   163 class IntegerField(Field):
       
   164     default_error_messages = {
       
   165         'invalid': _(u'Enter a whole number.'),
       
   166         'max_value': _(u'Ensure this value is less than or equal to %s.'),
       
   167         'min_value': _(u'Ensure this value is greater than or equal to %s.'),
       
   168     }
       
   169 
       
   170     def __init__(self, max_value=None, min_value=None, *args, **kwargs):
       
   171         self.max_value, self.min_value = max_value, min_value
       
   172         super(IntegerField, self).__init__(*args, **kwargs)
       
   173 
       
   174     def clean(self, value):
       
   175         """
       
   176         Validates that int() can be called on the input. Returns the result
       
   177         of int(). Returns None for empty values.
       
   178         """
       
   179         super(IntegerField, self).clean(value)
       
   180         if value in EMPTY_VALUES:
       
   181             return None
       
   182         try:
       
   183             value = int(str(value))
       
   184         except (ValueError, TypeError):
       
   185             raise ValidationError(self.error_messages['invalid'])
       
   186         if self.max_value is not None and value > self.max_value:
       
   187             raise ValidationError(self.error_messages['max_value'] % self.max_value)
       
   188         if self.min_value is not None and value < self.min_value:
       
   189             raise ValidationError(self.error_messages['min_value'] % self.min_value)
       
   190         return value
       
   191 
       
   192 class FloatField(Field):
       
   193     default_error_messages = {
       
   194         'invalid': _(u'Enter a number.'),
       
   195         'max_value': _(u'Ensure this value is less than or equal to %s.'),
       
   196         'min_value': _(u'Ensure this value is greater than or equal to %s.'),
       
   197     }
       
   198 
       
   199     def __init__(self, max_value=None, min_value=None, *args, **kwargs):
       
   200         self.max_value, self.min_value = max_value, min_value
       
   201         Field.__init__(self, *args, **kwargs)
       
   202 
       
   203     def clean(self, value):
       
   204         """
       
   205         Validates that float() can be called on the input. Returns a float.
       
   206         Returns None for empty values.
       
   207         """
       
   208         super(FloatField, self).clean(value)
       
   209         if not self.required and value in EMPTY_VALUES:
       
   210             return None
       
   211         try:
       
   212             value = float(value)
       
   213         except (ValueError, TypeError):
       
   214             raise ValidationError(self.error_messages['invalid'])
       
   215         if self.max_value is not None and value > self.max_value:
       
   216             raise ValidationError(self.error_messages['max_value'] % self.max_value)
       
   217         if self.min_value is not None and value < self.min_value:
       
   218             raise ValidationError(self.error_messages['min_value'] % self.min_value)
       
   219         return value
       
   220 
       
   221 class DecimalField(Field):
       
   222     default_error_messages = {
       
   223         'invalid': _(u'Enter a number.'),
       
   224         'max_value': _(u'Ensure this value is less than or equal to %s.'),
       
   225         'min_value': _(u'Ensure this value is greater than or equal to %s.'),
       
   226         'max_digits': _('Ensure that there are no more than %s digits in total.'),
       
   227         'max_decimal_places': _('Ensure that there are no more than %s decimal places.'),
       
   228         'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.')
       
   229     }
       
   230 
       
   231     def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
       
   232         self.max_value, self.min_value = max_value, min_value
       
   233         self.max_digits, self.decimal_places = max_digits, decimal_places
       
   234         Field.__init__(self, *args, **kwargs)
       
   235 
       
   236     def clean(self, value):
       
   237         """
       
   238         Validates that the input is a decimal number. Returns a Decimal
       
   239         instance. Returns None for empty values. Ensures that there are no more
       
   240         than max_digits in the number, and no more than decimal_places digits
       
   241         after the decimal point.
       
   242         """
       
   243         super(DecimalField, self).clean(value)
       
   244         if not self.required and value in EMPTY_VALUES:
       
   245             return None
       
   246         value = smart_str(value).strip()
       
   247         try:
       
   248             value = Decimal(value)
       
   249         except DecimalException:
       
   250             raise ValidationError(self.error_messages['invalid'])
       
   251 
       
   252         sign, digittuple, exponent = value.as_tuple()
       
   253         decimals = abs(exponent)
       
   254         # digittuple doesn't include any leading zeros.
       
   255         digits = len(digittuple)
       
   256         if decimals > digits:
       
   257             # We have leading zeros up to or past the decimal point.  Count
       
   258             # everything past the decimal point as a digit.  We do not count
       
   259             # 0 before the decimal point as a digit since that would mean
       
   260             # we would not allow max_digits = decimal_places.
       
   261             digits = decimals
       
   262         whole_digits = digits - decimals
       
   263 
       
   264         if self.max_value is not None and value > self.max_value:
       
   265             raise ValidationError(self.error_messages['max_value'] % self.max_value)
       
   266         if self.min_value is not None and value < self.min_value:
       
   267             raise ValidationError(self.error_messages['min_value'] % self.min_value)
       
   268         if self.max_digits is not None and digits > self.max_digits:
       
   269             raise ValidationError(self.error_messages['max_digits'] % self.max_digits)
       
   270         if self.decimal_places is not None and decimals > self.decimal_places:
       
   271             raise ValidationError(self.error_messages['max_decimal_places'] % self.decimal_places)
       
   272         if self.max_digits is not None and self.decimal_places is not None and whole_digits > (self.max_digits - self.decimal_places):
       
   273             raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places))
       
   274         return value
       
   275 
       
   276 DEFAULT_DATE_INPUT_FORMATS = (
       
   277     '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
       
   278     '%b %d %Y', '%b %d, %Y',            # 'Oct 25 2006', 'Oct 25, 2006'
       
   279     '%d %b %Y', '%d %b, %Y',            # '25 Oct 2006', '25 Oct, 2006'
       
   280     '%B %d %Y', '%B %d, %Y',            # 'October 25 2006', 'October 25, 2006'
       
   281     '%d %B %Y', '%d %B, %Y',            # '25 October 2006', '25 October, 2006'
       
   282 )
       
   283 
       
   284 class DateField(Field):
       
   285     widget = DateInput
       
   286     default_error_messages = {
       
   287         'invalid': _(u'Enter a valid date.'),
       
   288     }
       
   289 
       
   290     def __init__(self, input_formats=None, *args, **kwargs):
       
   291         super(DateField, self).__init__(*args, **kwargs)
       
   292         self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
       
   293 
       
   294     def clean(self, value):
       
   295         """
       
   296         Validates that the input can be converted to a date. Returns a Python
       
   297         datetime.date object.
       
   298         """
       
   299         super(DateField, self).clean(value)
       
   300         if value in EMPTY_VALUES:
       
   301             return None
       
   302         if isinstance(value, datetime.datetime):
       
   303             return value.date()
       
   304         if isinstance(value, datetime.date):
       
   305             return value
       
   306         for format in self.input_formats:
       
   307             try:
       
   308                 return datetime.date(*time.strptime(value, format)[:3])
       
   309             except ValueError:
       
   310                 continue
       
   311         raise ValidationError(self.error_messages['invalid'])
       
   312 
       
   313 DEFAULT_TIME_INPUT_FORMATS = (
       
   314     '%H:%M:%S',     # '14:30:59'
       
   315     '%H:%M',        # '14:30'
       
   316 )
       
   317 
       
   318 class TimeField(Field):
       
   319     widget = TimeInput
       
   320     default_error_messages = {
       
   321         'invalid': _(u'Enter a valid time.')
       
   322     }
       
   323 
       
   324     def __init__(self, input_formats=None, *args, **kwargs):
       
   325         super(TimeField, self).__init__(*args, **kwargs)
       
   326         self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS
       
   327 
       
   328     def clean(self, value):
       
   329         """
       
   330         Validates that the input can be converted to a time. Returns a Python
       
   331         datetime.time object.
       
   332         """
       
   333         super(TimeField, self).clean(value)
       
   334         if value in EMPTY_VALUES:
       
   335             return None
       
   336         if isinstance(value, datetime.time):
       
   337             return value
       
   338         for format in self.input_formats:
       
   339             try:
       
   340                 return datetime.time(*time.strptime(value, format)[3:6])
       
   341             except ValueError:
       
   342                 continue
       
   343         raise ValidationError(self.error_messages['invalid'])
       
   344 
       
   345 DEFAULT_DATETIME_INPUT_FORMATS = (
       
   346     '%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59'
       
   347     '%Y-%m-%d %H:%M',        # '2006-10-25 14:30'
       
   348     '%Y-%m-%d',              # '2006-10-25'
       
   349     '%m/%d/%Y %H:%M:%S',     # '10/25/2006 14:30:59'
       
   350     '%m/%d/%Y %H:%M',        # '10/25/2006 14:30'
       
   351     '%m/%d/%Y',              # '10/25/2006'
       
   352     '%m/%d/%y %H:%M:%S',     # '10/25/06 14:30:59'
       
   353     '%m/%d/%y %H:%M',        # '10/25/06 14:30'
       
   354     '%m/%d/%y',              # '10/25/06'
       
   355 )
       
   356 
       
   357 class DateTimeField(Field):
       
   358     widget = DateTimeInput
       
   359     default_error_messages = {
       
   360         'invalid': _(u'Enter a valid date/time.'),
       
   361     }
       
   362 
       
   363     def __init__(self, input_formats=None, *args, **kwargs):
       
   364         super(DateTimeField, self).__init__(*args, **kwargs)
       
   365         self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
       
   366 
       
   367     def clean(self, value):
       
   368         """
       
   369         Validates that the input can be converted to a datetime. Returns a
       
   370         Python datetime.datetime object.
       
   371         """
       
   372         super(DateTimeField, self).clean(value)
       
   373         if value in EMPTY_VALUES:
       
   374             return None
       
   375         if isinstance(value, datetime.datetime):
       
   376             return value
       
   377         if isinstance(value, datetime.date):
       
   378             return datetime.datetime(value.year, value.month, value.day)
       
   379         if isinstance(value, list):
       
   380             # Input comes from a SplitDateTimeWidget, for example. So, it's two
       
   381             # components: date and time.
       
   382             if len(value) != 2:
       
   383                 raise ValidationError(self.error_messages['invalid'])
       
   384             value = '%s %s' % tuple(value)
       
   385         for format in self.input_formats:
       
   386             try:
       
   387                 return datetime.datetime(*time.strptime(value, format)[:6])
       
   388             except ValueError:
       
   389                 continue
       
   390         raise ValidationError(self.error_messages['invalid'])
       
   391 
       
   392 class RegexField(CharField):
       
   393     def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs):
       
   394         """
       
   395         regex can be either a string or a compiled regular expression object.
       
   396         error_message is an optional error message to use, if
       
   397         'Enter a valid value' is too generic for you.
       
   398         """
       
   399         # error_message is just kept for backwards compatibility:
       
   400         if error_message:
       
   401             error_messages = kwargs.get('error_messages') or {}
       
   402             error_messages['invalid'] = error_message
       
   403             kwargs['error_messages'] = error_messages
       
   404         super(RegexField, self).__init__(max_length, min_length, *args, **kwargs)
       
   405         if isinstance(regex, basestring):
       
   406             regex = re.compile(regex)
       
   407         self.regex = regex
       
   408 
       
   409     def clean(self, value):
       
   410         """
       
   411         Validates that the input matches the regular expression. Returns a
       
   412         Unicode object.
       
   413         """
       
   414         value = super(RegexField, self).clean(value)
       
   415         if value == u'':
       
   416             return value
       
   417         if not self.regex.search(value):
       
   418             raise ValidationError(self.error_messages['invalid'])
       
   419         return value
       
   420 
       
   421 email_re = re.compile(
       
   422     r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
       
   423     r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
       
   424     r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain
       
   425 
       
   426 class EmailField(RegexField):
       
   427     default_error_messages = {
       
   428         'invalid': _(u'Enter a valid e-mail address.'),
       
   429     }
       
   430 
       
   431     def __init__(self, max_length=None, min_length=None, *args, **kwargs):
       
   432         RegexField.__init__(self, email_re, max_length, min_length, *args,
       
   433                             **kwargs)
       
   434 
       
   435 try:
       
   436     from django.conf import settings
       
   437     URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
       
   438 except ImportError:
       
   439     # It's OK if Django settings aren't configured.
       
   440     URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
       
   441 
       
   442 
       
   443 class FileField(Field):
       
   444     widget = FileInput
       
   445     default_error_messages = {
       
   446         'invalid': _(u"No file was submitted. Check the encoding type on the form."),
       
   447         'missing': _(u"No file was submitted."),
       
   448         'empty': _(u"The submitted file is empty."),
       
   449         'max_length': _(u'Ensure this filename has at most %(max)d characters (it has %(length)d).'),
       
   450     }
       
   451 
       
   452     def __init__(self, *args, **kwargs):
       
   453         self.max_length = kwargs.pop('max_length', None)
       
   454         super(FileField, self).__init__(*args, **kwargs)
       
   455 
       
   456     def clean(self, data, initial=None):
       
   457         super(FileField, self).clean(initial or data)
       
   458         if not self.required and data in EMPTY_VALUES:
       
   459             return None
       
   460         elif not data and initial:
       
   461             return initial
       
   462 
       
   463         # UploadedFile objects should have name and size attributes.
       
   464         try:
       
   465             file_name = data.name
       
   466             file_size = data.size
       
   467         except AttributeError:
       
   468             raise ValidationError(self.error_messages['invalid'])
       
   469 
       
   470         if self.max_length is not None and len(file_name) > self.max_length:
       
   471             error_values =  {'max': self.max_length, 'length': len(file_name)}
       
   472             raise ValidationError(self.error_messages['max_length'] % error_values)
       
   473         if not file_name:
       
   474             raise ValidationError(self.error_messages['invalid'])
       
   475         if not file_size:
       
   476             raise ValidationError(self.error_messages['empty'])
       
   477 
       
   478         return data
       
   479 
       
   480 class ImageField(FileField):
       
   481     default_error_messages = {
       
   482         'invalid_image': _(u"Upload a valid image. The file you uploaded was either not an image or a corrupted image."),
       
   483     }
       
   484 
       
   485     def clean(self, data, initial=None):
       
   486         """
       
   487         Checks that the file-upload field data contains a valid image (GIF, JPG,
       
   488         PNG, possibly others -- whatever the Python Imaging Library supports).
       
   489         """
       
   490         f = super(ImageField, self).clean(data, initial)
       
   491         if f is None:
       
   492             return None
       
   493         elif not data and initial:
       
   494             return initial
       
   495         from PIL import Image
       
   496 
       
   497         # We need to get a file object for PIL. We might have a path or we might
       
   498         # have to read the data into memory.
       
   499         if hasattr(data, 'temporary_file_path'):
       
   500             file = data.temporary_file_path()
       
   501         else:
       
   502             if hasattr(data, 'read'):
       
   503                 file = StringIO(data.read())
       
   504             else:
       
   505                 file = StringIO(data['content'])
       
   506 
       
   507         try:
       
   508             # load() is the only method that can spot a truncated JPEG,
       
   509             #  but it cannot be called sanely after verify()
       
   510             trial_image = Image.open(file)
       
   511             trial_image.load()
       
   512 
       
   513             # Since we're about to use the file again we have to reset the
       
   514             # file object if possible.
       
   515             if hasattr(file, 'reset'):
       
   516                 file.reset()
       
   517 
       
   518             # verify() is the only method that can spot a corrupt PNG,
       
   519             #  but it must be called immediately after the constructor
       
   520             trial_image = Image.open(file)
       
   521             trial_image.verify()
       
   522         except ImportError:
       
   523             # Under PyPy, it is possible to import PIL. However, the underlying
       
   524             # _imaging C module isn't available, so an ImportError will be
       
   525             # raised. Catch and re-raise.
       
   526             raise
       
   527         except Exception: # Python Imaging Library doesn't recognize it as an image
       
   528             raise ValidationError(self.error_messages['invalid_image'])
       
   529         if hasattr(f, 'seek') and callable(f.seek):
       
   530             f.seek(0)
       
   531         return f
       
   532 
       
   533 url_re = re.compile(
       
   534     r'^https?://' # http:// or https://
       
   535     r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
       
   536     r'localhost|' #localhost...
       
   537     r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
       
   538     r'(?::\d+)?' # optional port
       
   539     r'(?:/?|/\S+)$', re.IGNORECASE)
       
   540 
       
   541 class URLField(RegexField):
       
   542     default_error_messages = {
       
   543         'invalid': _(u'Enter a valid URL.'),
       
   544         'invalid_link': _(u'This URL appears to be a broken link.'),
       
   545     }
       
   546 
       
   547     def __init__(self, max_length=None, min_length=None, verify_exists=False,
       
   548             validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
       
   549         super(URLField, self).__init__(url_re, max_length, min_length, *args,
       
   550                                        **kwargs)
       
   551         self.verify_exists = verify_exists
       
   552         self.user_agent = validator_user_agent
       
   553 
       
   554     def clean(self, value):
       
   555         # If no URL scheme given, assume http://
       
   556         if value and '://' not in value:
       
   557             value = u'http://%s' % value
       
   558         # If no URL path given, assume /
       
   559         if value and not urlparse.urlsplit(value)[2]:
       
   560             value += '/'
       
   561         value = super(URLField, self).clean(value)
       
   562         if value == u'':
       
   563             return value
       
   564         if self.verify_exists:
       
   565             import urllib2
       
   566             headers = {
       
   567                 "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
       
   568                 "Accept-Language": "en-us,en;q=0.5",
       
   569                 "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
       
   570                 "Connection": "close",
       
   571                 "User-Agent": self.user_agent,
       
   572             }
       
   573             try:
       
   574                 req = urllib2.Request(value, None, headers)
       
   575                 u = urllib2.urlopen(req)
       
   576             except ValueError:
       
   577                 raise ValidationError(self.error_messages['invalid'])
       
   578             except: # urllib2.URLError, httplib.InvalidURL, etc.
       
   579                 raise ValidationError(self.error_messages['invalid_link'])
       
   580         return value
       
   581 
       
   582 class BooleanField(Field):
       
   583     widget = CheckboxInput
       
   584 
       
   585     def clean(self, value):
       
   586         """Returns a Python boolean object."""
       
   587         # Explicitly check for the string 'False', which is what a hidden field
       
   588         # will submit for False. Also check for '0', since this is what
       
   589         # RadioSelect will provide. Because bool("True") == bool('1') == True,
       
   590         # we don't need to handle that explicitly.
       
   591         if value in ('False', '0'):
       
   592             value = False
       
   593         else:
       
   594             value = bool(value)
       
   595         super(BooleanField, self).clean(value)
       
   596         if not value and self.required:
       
   597             raise ValidationError(self.error_messages['required'])
       
   598         return value
       
   599 
       
   600 class NullBooleanField(BooleanField):
       
   601     """
       
   602     A field whose valid values are None, True and False. Invalid values are
       
   603     cleaned to None.
       
   604     """
       
   605     widget = NullBooleanSelect
       
   606 
       
   607     def clean(self, value):
       
   608         """
       
   609         Explicitly checks for the string 'True' and 'False', which is what a
       
   610         hidden field will submit for True and False, and for '1' and '0', which
       
   611         is what a RadioField will submit. Unlike the Booleanfield we need to
       
   612         explicitly check for True, because we are not using the bool() function
       
   613         """
       
   614         if value in (True, 'True', '1'):
       
   615             return True
       
   616         elif value in (False, 'False', '0'):
       
   617             return False
       
   618         else:
       
   619             return None
       
   620 
       
   621 class ChoiceField(Field):
       
   622     widget = Select
       
   623     default_error_messages = {
       
   624         'invalid_choice': _(u'Select a valid choice. %(value)s is not one of the available choices.'),
       
   625     }
       
   626 
       
   627     def __init__(self, choices=(), required=True, widget=None, label=None,
       
   628                  initial=None, help_text=None, *args, **kwargs):
       
   629         super(ChoiceField, self).__init__(required, widget, label, initial,
       
   630                                           help_text, *args, **kwargs)
       
   631         self.choices = choices
       
   632 
       
   633     def _get_choices(self):
       
   634         return self._choices
       
   635 
       
   636     def _set_choices(self, value):
       
   637         # Setting choices also sets the choices on the widget.
       
   638         # choices can be any iterable, but we call list() on it because
       
   639         # it will be consumed more than once.
       
   640         self._choices = self.widget.choices = list(value)
       
   641 
       
   642     choices = property(_get_choices, _set_choices)
       
   643 
       
   644     def clean(self, value):
       
   645         """
       
   646         Validates that the input is in self.choices.
       
   647         """
       
   648         value = super(ChoiceField, self).clean(value)
       
   649         if value in EMPTY_VALUES:
       
   650             value = u''
       
   651         value = smart_unicode(value)
       
   652         if value == u'':
       
   653             return value
       
   654         if not self.valid_value(value):
       
   655             raise ValidationError(self.error_messages['invalid_choice'] % {'value': value})
       
   656         return value
       
   657 
       
   658     def valid_value(self, value):
       
   659         "Check to see if the provided value is a valid choice"
       
   660         for k, v in self.choices:
       
   661             if type(v) in (tuple, list):
       
   662                 # This is an optgroup, so look inside the group for options
       
   663                 for k2, v2 in v:
       
   664                     if value == smart_unicode(k2):
       
   665                         return True
       
   666             else:
       
   667                 if value == smart_unicode(k):
       
   668                     return True
       
   669         return False
       
   670 
       
   671 class TypedChoiceField(ChoiceField):
       
   672     def __init__(self, *args, **kwargs):
       
   673         self.coerce = kwargs.pop('coerce', lambda val: val)
       
   674         self.empty_value = kwargs.pop('empty_value', '')
       
   675         super(TypedChoiceField, self).__init__(*args, **kwargs)
       
   676 
       
   677     def clean(self, value):
       
   678         """
       
   679         Validate that the value is in self.choices and can be coerced to the
       
   680         right type.
       
   681         """
       
   682         value = super(TypedChoiceField, self).clean(value)
       
   683         if value == self.empty_value or value in EMPTY_VALUES:
       
   684             return self.empty_value
       
   685 
       
   686         # Hack alert: This field is purpose-made to use with Field.to_python as
       
   687         # a coercion function so that ModelForms with choices work. However,
       
   688         # Django's Field.to_python raises
       
   689         # django.core.exceptions.ValidationError, which is a *different*
       
   690         # exception than django.forms.util.ValidationError. So we need to catch
       
   691         # both.
       
   692         try:
       
   693             value = self.coerce(value)
       
   694         except (ValueError, TypeError, django.core.exceptions.ValidationError):
       
   695             raise ValidationError(self.error_messages['invalid_choice'] % {'value': value})
       
   696         return value
       
   697 
       
   698 class MultipleChoiceField(ChoiceField):
       
   699     hidden_widget = MultipleHiddenInput
       
   700     widget = SelectMultiple
       
   701     default_error_messages = {
       
   702         'invalid_choice': _(u'Select a valid choice. %(value)s is not one of the available choices.'),
       
   703         'invalid_list': _(u'Enter a list of values.'),
       
   704     }
       
   705 
       
   706     def clean(self, value):
       
   707         """
       
   708         Validates that the input is a list or tuple.
       
   709         """
       
   710         if self.required and not value:
       
   711             raise ValidationError(self.error_messages['required'])
       
   712         elif not self.required and not value:
       
   713             return []
       
   714         if not isinstance(value, (list, tuple)):
       
   715             raise ValidationError(self.error_messages['invalid_list'])
       
   716         new_value = [smart_unicode(val) for val in value]
       
   717         # Validate that each value in the value list is in self.choices.
       
   718         for val in new_value:
       
   719             if not self.valid_value(val):
       
   720                 raise ValidationError(self.error_messages['invalid_choice'] % {'value': val})
       
   721         return new_value
       
   722 
       
   723 class ComboField(Field):
       
   724     """
       
   725     A Field whose clean() method calls multiple Field clean() methods.
       
   726     """
       
   727     def __init__(self, fields=(), *args, **kwargs):
       
   728         super(ComboField, self).__init__(*args, **kwargs)
       
   729         # Set 'required' to False on the individual fields, because the
       
   730         # required validation will be handled by ComboField, not by those
       
   731         # individual fields.
       
   732         for f in fields:
       
   733             f.required = False
       
   734         self.fields = fields
       
   735 
       
   736     def clean(self, value):
       
   737         """
       
   738         Validates the given value against all of self.fields, which is a
       
   739         list of Field instances.
       
   740         """
       
   741         super(ComboField, self).clean(value)
       
   742         for field in self.fields:
       
   743             value = field.clean(value)
       
   744         return value
       
   745 
       
   746 class MultiValueField(Field):
       
   747     """
       
   748     A Field that aggregates the logic of multiple Fields.
       
   749 
       
   750     Its clean() method takes a "decompressed" list of values, which are then
       
   751     cleaned into a single value according to self.fields. Each value in
       
   752     this list is cleaned by the corresponding field -- the first value is
       
   753     cleaned by the first field, the second value is cleaned by the second
       
   754     field, etc. Once all fields are cleaned, the list of clean values is
       
   755     "compressed" into a single value.
       
   756 
       
   757     Subclasses should not have to implement clean(). Instead, they must
       
   758     implement compress(), which takes a list of valid values and returns a
       
   759     "compressed" version of those values -- a single value.
       
   760 
       
   761     You'll probably want to use this with MultiWidget.
       
   762     """
       
   763     default_error_messages = {
       
   764         'invalid': _(u'Enter a list of values.'),
       
   765     }
       
   766 
       
   767     def __init__(self, fields=(), *args, **kwargs):
       
   768         super(MultiValueField, self).__init__(*args, **kwargs)
       
   769         # Set 'required' to False on the individual fields, because the
       
   770         # required validation will be handled by MultiValueField, not by those
       
   771         # individual fields.
       
   772         for f in fields:
       
   773             f.required = False
       
   774         self.fields = fields
       
   775 
       
   776     def clean(self, value):
       
   777         """
       
   778         Validates every value in the given list. A value is validated against
       
   779         the corresponding Field in self.fields.
       
   780 
       
   781         For example, if this MultiValueField was instantiated with
       
   782         fields=(DateField(), TimeField()), clean() would call
       
   783         DateField.clean(value[0]) and TimeField.clean(value[1]).
       
   784         """
       
   785         clean_data = []
       
   786         errors = ErrorList()
       
   787         if not value or isinstance(value, (list, tuple)):
       
   788             if not value or not [v for v in value if v not in EMPTY_VALUES]:
       
   789                 if self.required:
       
   790                     raise ValidationError(self.error_messages['required'])
       
   791                 else:
       
   792                     return self.compress([])
       
   793         else:
       
   794             raise ValidationError(self.error_messages['invalid'])
       
   795         for i, field in enumerate(self.fields):
       
   796             try:
       
   797                 field_value = value[i]
       
   798             except IndexError:
       
   799                 field_value = None
       
   800             if self.required and field_value in EMPTY_VALUES:
       
   801                 raise ValidationError(self.error_messages['required'])
       
   802             try:
       
   803                 clean_data.append(field.clean(field_value))
       
   804             except ValidationError, e:
       
   805                 # Collect all validation errors in a single list, which we'll
       
   806                 # raise at the end of clean(), rather than raising a single
       
   807                 # exception for the first error we encounter.
       
   808                 errors.extend(e.messages)
       
   809         if errors:
       
   810             raise ValidationError(errors)
       
   811         return self.compress(clean_data)
       
   812 
       
   813     def compress(self, data_list):
       
   814         """
       
   815         Returns a single value for the given list of values. The values can be
       
   816         assumed to be valid.
       
   817 
       
   818         For example, if this MultiValueField was instantiated with
       
   819         fields=(DateField(), TimeField()), this might return a datetime
       
   820         object created by combining the date and time in data_list.
       
   821         """
       
   822         raise NotImplementedError('Subclasses must implement this method.')
       
   823 
       
   824 class FilePathField(ChoiceField):
       
   825     def __init__(self, path, match=None, recursive=False, required=True,
       
   826                  widget=None, label=None, initial=None, help_text=None,
       
   827                  *args, **kwargs):
       
   828         self.path, self.match, self.recursive = path, match, recursive
       
   829         super(FilePathField, self).__init__(choices=(), required=required,
       
   830             widget=widget, label=label, initial=initial, help_text=help_text,
       
   831             *args, **kwargs)
       
   832 
       
   833         if self.required:
       
   834             self.choices = []
       
   835         else:
       
   836             self.choices = [("", "---------")]
       
   837 
       
   838         if self.match is not None:
       
   839             self.match_re = re.compile(self.match)
       
   840 
       
   841         if recursive:
       
   842             for root, dirs, files in os.walk(self.path):
       
   843                 for f in files:
       
   844                     if self.match is None or self.match_re.search(f):
       
   845                         f = os.path.join(root, f)
       
   846                         self.choices.append((f, f.replace(path, "", 1)))
       
   847         else:
       
   848             try:
       
   849                 for f in os.listdir(self.path):
       
   850                     full_file = os.path.join(self.path, f)
       
   851                     if os.path.isfile(full_file) and (self.match is None or self.match_re.search(f)):
       
   852                         self.choices.append((full_file, f))
       
   853             except OSError:
       
   854                 pass
       
   855 
       
   856         self.widget.choices = self.choices
       
   857 
       
   858 class SplitDateTimeField(MultiValueField):
       
   859     widget = SplitDateTimeWidget
       
   860     hidden_widget = SplitHiddenDateTimeWidget
       
   861     default_error_messages = {
       
   862         'invalid_date': _(u'Enter a valid date.'),
       
   863         'invalid_time': _(u'Enter a valid time.'),
       
   864     }
       
   865 
       
   866     def __init__(self, input_date_formats=None, input_time_formats=None, *args, **kwargs):
       
   867         errors = self.default_error_messages.copy()
       
   868         if 'error_messages' in kwargs:
       
   869             errors.update(kwargs['error_messages'])
       
   870         fields = (
       
   871             DateField(input_formats=input_date_formats, error_messages={'invalid': errors['invalid_date']}),
       
   872             TimeField(input_formats=input_time_formats, error_messages={'invalid': errors['invalid_time']}),
       
   873         )
       
   874         super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
       
   875 
       
   876     def compress(self, data_list):
       
   877         if data_list:
       
   878             # Raise a validation error if time or date is empty
       
   879             # (possible if SplitDateTimeField has required=False).
       
   880             if data_list[0] in EMPTY_VALUES:
       
   881                 raise ValidationError(self.error_messages['invalid_date'])
       
   882             if data_list[1] in EMPTY_VALUES:
       
   883                 raise ValidationError(self.error_messages['invalid_time'])
       
   884             return datetime.datetime.combine(*data_list)
       
   885         return None
       
   886 
       
   887 ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
       
   888 
       
   889 class IPAddressField(RegexField):
       
   890     default_error_messages = {
       
   891         'invalid': _(u'Enter a valid IPv4 address.'),
       
   892     }
       
   893 
       
   894     def __init__(self, *args, **kwargs):
       
   895         super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs)
       
   896 
       
   897 slug_re = re.compile(r'^[-\w]+$')
       
   898 
       
   899 class SlugField(RegexField):
       
   900     default_error_messages = {
       
   901         'invalid': _(u"Enter a valid 'slug' consisting of letters, numbers,"
       
   902                      u" underscores or hyphens."),
       
   903     }
       
   904 
       
   905     def __init__(self, *args, **kwargs):
       
   906         super(SlugField, self).__init__(slug_re, *args, **kwargs)