~ubuntu-branches/ubuntu/precise/python-django/precise-proposed

« back to all changes in this revision

Viewing changes to .pc/genericipaddressfield.diff/django/forms/fields.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez, Julian Edwards
  • Date: 2012-11-20 16:00:41 UTC
  • Revision ID: package-import@ubuntu.com-20121120160041-140ztibl9h0omz79
Tags: 1.3.1-4ubuntu1.5
[ Julian Edwards ]
* debian/patches:
  - genericipaddressfield.diff: Backport GenericIPAddressField
    from 1.4 (LP: #1081391)
  - prefetch_related.diff: Backport prefetch_related from 1.4 (LP: #1081388)
  - bug15496-base64-multipart-fix.diff: Include fix for upstream bug #15496
    which makes 'Content-Transfer-Encoding: base64: work for multipart
    messages. (LP: #1081392)

Show diffs side-by-side

added added

removed removed

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