11 from decimal
import Decimal
, DecimalException
13 from cStringIO
import StringIO
15 from StringIO
import StringIO
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
25 # Provide this import for backwards compatibility.
26 from django
.core
.validators
import EMPTY_VALUES
28 from util
import ErrorList
29 from widgets
import TextInput
, PasswordInput
, HiddenInput
, MultipleHiddenInput
, \
30 FileInput
, CheckboxInput
, Select
, NullBooleanSelect
, SelectMultiple
, \
31 DateInput
, DateTimeInput
, TimeInput
, SplitDateTimeWidget
, SplitHiddenDateTimeWidget
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',
47 Helper function to stay backward compatible.
49 from django
.conf
.locale
.en
import formats
51 "`django.forms.fields.DEFAULT_%s` is deprecated; use `django.utils.formats.get_format('%s')` instead." % (name
, name
),
52 PendingDeprecationWarning
54 return getattr(formats
, name
)
56 DEFAULT_DATE_INPUT_FORMATS
= lazy(lambda: en_format('DATE_INPUT_FORMATS'), tuple, list)()
57 DEFAULT_TIME_INPUT_FORMATS
= lazy(lambda: en_format('TIME_INPUT_FORMATS'), tuple, list)()
58 DEFAULT_DATETIME_INPUT_FORMATS
= lazy(lambda: en_format('DATETIME_INPUT_FORMATS'), tuple, list)()
61 widget
= TextInput
# Default widget to use when rendering this type of Field.
62 hidden_widget
= HiddenInput
# Default widget to use when rendering this as "hidden".
63 default_validators
= [] # Default set of validators
64 default_error_messages
= {
65 'required': _(u
'This field is required.'),
66 'invalid': _(u
'Enter a valid value.'),
69 # Tracks each time a Field instance is created. Used to retain order.
72 def __init__(self
, required
=True, widget
=None, label
=None, initial
=None,
73 help_text
=None, error_messages
=None, show_hidden_initial
=False,
74 validators
=[], localize
=False):
75 # required -- Boolean that specifies whether the field is required.
77 # widget -- A Widget class, or instance of a Widget class, that should
78 # be used for this Field when displaying it. Each Field has a
79 # default Widget that it'll use if you don't specify this. In
80 # most cases, the default widget is TextInput.
81 # label -- A verbose name for this field, for use in displaying this
82 # field in a form. By default, Django will use a "pretty"
83 # version of the form field name, if the Field is part of a
85 # initial -- A value to use in this Field's initial display. This value
86 # is *not* used as a fallback if data isn't given.
87 # help_text -- An optional string to use as "help text" for this Field.
88 # error_messages -- An optional dictionary to override the default
89 # messages that the field will raise.
90 # show_hidden_initial -- Boolean that specifies if it is needed to render a
91 # hidden widget with initial value after widget.
92 # validators -- List of addtional validators to use
93 # localize -- Boolean that specifies if the field should be localized.
95 label
= smart_unicode(label
)
96 self
.required
, self
.label
, self
.initial
= required
, label
, initial
97 self
.show_hidden_initial
= show_hidden_initial
101 self
.help_text
= smart_unicode(help_text
)
102 widget
= widget
or self
.widget
103 if isinstance(widget
, type):
106 # Trigger the localization machinery if needed.
107 self
.localize
= localize
109 widget
.is_localized
= True
111 # Hook into self.widget_attrs() for any Field-specific HTML attributes.
112 extra_attrs
= self
.widget_attrs(widget
)
114 widget
.attrs
.update(extra_attrs
)
118 # Increase the creation counter, and save our local copy.
119 self
.creation_counter
= Field
.creation_counter
120 Field
.creation_counter
+= 1
123 for c
in reversed(self
.__class
__.__mro
__):
124 messages
.update(getattr(c
, 'default_error_messages', {}))
125 messages
.update(error_messages
or {})
126 self
.error_messages
= messages
128 self
.validators
= self
.default_validators
+ validators
130 def to_python(self
, value
):
133 def validate(self
, value
):
134 if value
in validators
.EMPTY_VALUES
and self
.required
:
135 raise ValidationError(self
.error_messages
['required'])
137 def run_validators(self
, value
):
138 if value
in validators
.EMPTY_VALUES
:
141 for v
in self
.validators
:
144 except ValidationError
, e
:
145 if hasattr(e
, 'code') and e
.code
in self
.error_messages
:
146 message
= self
.error_messages
[e
.code
]
148 message
= message
% e
.params
149 errors
.append(message
)
151 errors
.extend(e
.messages
)
153 raise ValidationError(errors
)
155 def clean(self
, value
):
157 Validates the given value and returns its "cleaned" value as an
158 appropriate Python object.
160 Raises ValidationError for any errors.
162 value
= self
.to_python(value
)
164 self
.run_validators(value
)
167 def widget_attrs(self
, widget
):
169 Given a Widget instance (*not* a Widget class), returns a dictionary of
170 any HTML attributes that should be added to the Widget, based on this
175 def __deepcopy__(self
, memo
):
176 result
= copy
.copy(self
)
177 memo
[id(self
)] = result
178 result
.widget
= copy
.deepcopy(self
.widget
, memo
)
181 class CharField(Field
):
182 def __init__(self
, max_length
=None, min_length
=None, *args
, **kwargs
):
183 self
.max_length
, self
.min_length
= max_length
, min_length
184 super(CharField
, self
).__init
__(*args
, **kwargs
)
185 if min_length
is not None:
186 self
.validators
.append(validators
.MinLengthValidator(min_length
))
187 if max_length
is not None:
188 self
.validators
.append(validators
.MaxLengthValidator(max_length
))
190 def to_python(self
, value
):
191 "Returns a Unicode object."
192 if value
in validators
.EMPTY_VALUES
:
194 return smart_unicode(value
)
196 def widget_attrs(self
, widget
):
197 if self
.max_length
is not None and isinstance(widget
, (TextInput
, PasswordInput
)):
198 # The HTML attribute is maxlength, not max_length.
199 return {'maxlength': str(self
.max_length
)}
201 class IntegerField(Field
):
202 default_error_messages
= {
203 'invalid': _(u
'Enter a whole number.'),
204 'max_value': _(u
'Ensure this value is less than or equal to %(limit_value)s.'),
205 'min_value': _(u
'Ensure this value is greater than or equal to %(limit_value)s.'),
208 def __init__(self
, max_value
=None, min_value
=None, *args
, **kwargs
):
209 super(IntegerField
, self
).__init
__(*args
, **kwargs
)
211 if max_value
is not None:
212 self
.validators
.append(validators
.MaxValueValidator(max_value
))
213 if min_value
is not None:
214 self
.validators
.append(validators
.MinValueValidator(min_value
))
216 def to_python(self
, value
):
218 Validates that int() can be called on the input. Returns the result
219 of int(). Returns None for empty values.
221 value
= super(IntegerField
, self
).to_python(value
)
222 if value
in validators
.EMPTY_VALUES
:
225 value
= formats
.sanitize_separators(value
)
227 value
= int(str(value
))
228 except (ValueError, TypeError):
229 raise ValidationError(self
.error_messages
['invalid'])
232 class FloatField(IntegerField
):
233 default_error_messages
= {
234 'invalid': _(u
'Enter a number.'),
237 def to_python(self
, value
):
239 Validates that float() can be called on the input. Returns the result
240 of float(). Returns None for empty values.
242 value
= super(IntegerField
, self
).to_python(value
)
243 if value
in validators
.EMPTY_VALUES
:
246 value
= formats
.sanitize_separators(value
)
249 except (ValueError, TypeError):
250 raise ValidationError(self
.error_messages
['invalid'])
253 class DecimalField(Field
):
254 default_error_messages
= {
255 'invalid': _(u
'Enter a number.'),
256 'max_value': _(u
'Ensure this value is less than or equal to %(limit_value)s.'),
257 'min_value': _(u
'Ensure this value is greater than or equal to %(limit_value)s.'),
258 'max_digits': _('Ensure that there are no more than %s digits in total.'),
259 'max_decimal_places': _('Ensure that there are no more than %s decimal places.'),
260 'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.')
263 def __init__(self
, max_value
=None, min_value
=None, max_digits
=None, decimal_places
=None, *args
, **kwargs
):
264 self
.max_digits
, self
.decimal_places
= max_digits
, decimal_places
265 Field
.__init
__(self
, *args
, **kwargs
)
267 if max_value
is not None:
268 self
.validators
.append(validators
.MaxValueValidator(max_value
))
269 if min_value
is not None:
270 self
.validators
.append(validators
.MinValueValidator(min_value
))
272 def to_python(self
, value
):
274 Validates that the input is a decimal number. Returns a Decimal
275 instance. Returns None for empty values. Ensures that there are no more
276 than max_digits in the number, and no more than decimal_places digits
277 after the decimal point.
279 if value
in validators
.EMPTY_VALUES
:
282 value
= formats
.sanitize_separators(value
)
283 value
= smart_str(value
).strip()
285 value
= Decimal(value
)
286 except DecimalException
:
287 raise ValidationError(self
.error_messages
['invalid'])
290 def validate(self
, value
):
291 super(DecimalField
, self
).validate(value
)
292 if value
in validators
.EMPTY_VALUES
:
294 # Check for NaN, Inf and -Inf values. We can't compare directly for NaN,
295 # since it is never equal to itself. However, NaN is the only value that
296 # isn't equal to itself, so we can use this to identify NaN
297 if value
!= value
or value
== Decimal("Inf") or value
== Decimal("-Inf"):
298 raise ValidationError(self
.error_messages
['invalid'])
299 sign
, digittuple
, exponent
= value
.as_tuple()
300 decimals
= abs(exponent
)
301 # digittuple doesn't include any leading zeros.
302 digits
= len(digittuple
)
303 if decimals
> digits
:
304 # We have leading zeros up to or past the decimal point. Count
305 # everything past the decimal point as a digit. We do not count
306 # 0 before the decimal point as a digit since that would mean
307 # we would not allow max_digits = decimal_places.
309 whole_digits
= digits
- decimals
311 if self
.max_digits
is not None and digits
> self
.max_digits
:
312 raise ValidationError(self
.error_messages
['max_digits'] % self
.max_digits
)
313 if self
.decimal_places
is not None and decimals
> self
.decimal_places
:
314 raise ValidationError(self
.error_messages
['max_decimal_places'] % self
.decimal_places
)
315 if self
.max_digits
is not None and self
.decimal_places
is not None and whole_digits
> (self
.max_digits
- self
.decimal_places
):
316 raise ValidationError(self
.error_messages
['max_whole_digits'] % (self
.max_digits
- self
.decimal_places
))
319 class DateField(Field
):
321 default_error_messages
= {
322 'invalid': _(u
'Enter a valid date.'),
325 def __init__(self
, input_formats
=None, *args
, **kwargs
):
326 super(DateField
, self
).__init
__(*args
, **kwargs
)
327 self
.input_formats
= input_formats
329 def to_python(self
, value
):
331 Validates that the input can be converted to a date. Returns a Python
332 datetime.date object.
334 if value
in validators
.EMPTY_VALUES
:
336 if isinstance(value
, datetime
.datetime
):
338 if isinstance(value
, datetime
.date
):
340 for format
in self
.input_formats
or formats
.get_format('DATE_INPUT_FORMATS'):
342 return datetime
.date(*time
.strptime(value
, format
)[:3])
345 raise ValidationError(self
.error_messages
['invalid'])
347 class TimeField(Field
):
349 default_error_messages
= {
350 'invalid': _(u
'Enter a valid time.')
353 def __init__(self
, input_formats
=None, *args
, **kwargs
):
354 super(TimeField
, self
).__init
__(*args
, **kwargs
)
355 self
.input_formats
= input_formats
357 def to_python(self
, value
):
359 Validates that the input can be converted to a time. Returns a Python
360 datetime.time object.
362 if value
in validators
.EMPTY_VALUES
:
364 if isinstance(value
, datetime
.time
):
366 for format
in self
.input_formats
or formats
.get_format('TIME_INPUT_FORMATS'):
368 return datetime
.time(*time
.strptime(value
, format
)[3:6])
371 raise ValidationError(self
.error_messages
['invalid'])
373 class DateTimeField(Field
):
374 widget
= DateTimeInput
375 default_error_messages
= {
376 'invalid': _(u
'Enter a valid date/time.'),
379 def __init__(self
, input_formats
=None, *args
, **kwargs
):
380 super(DateTimeField
, self
).__init
__(*args
, **kwargs
)
381 self
.input_formats
= input_formats
383 def to_python(self
, value
):
385 Validates that the input can be converted to a datetime. Returns a
386 Python datetime.datetime object.
388 if value
in validators
.EMPTY_VALUES
:
390 if isinstance(value
, datetime
.datetime
):
392 if isinstance(value
, datetime
.date
):
393 return datetime
.datetime(value
.year
, value
.month
, value
.day
)
394 if isinstance(value
, list):
395 # Input comes from a SplitDateTimeWidget, for example. So, it's two
396 # components: date and time.
398 raise ValidationError(self
.error_messages
['invalid'])
399 value
= '%s %s' % tuple(value
)
400 for format
in self
.input_formats
or formats
.get_format('DATETIME_INPUT_FORMATS'):
402 return datetime
.datetime(*time
.strptime(value
, format
)[:6])
405 raise ValidationError(self
.error_messages
['invalid'])
407 class RegexField(CharField
):
408 def __init__(self
, regex
, max_length
=None, min_length
=None, error_message
=None, *args
, **kwargs
):
410 regex can be either a string or a compiled regular expression object.
411 error_message is an optional error message to use, if
412 'Enter a valid value' is too generic for you.
414 # error_message is just kept for backwards compatibility:
416 error_messages
= kwargs
.get('error_messages') or {}
417 error_messages
['invalid'] = error_message
418 kwargs
['error_messages'] = error_messages
419 super(RegexField
, self
).__init
__(max_length
, min_length
, *args
, **kwargs
)
420 if isinstance(regex
, basestring
):
421 regex
= re
.compile(regex
)
423 self
.validators
.append(validators
.RegexValidator(regex
=regex
))
425 class EmailField(CharField
):
426 default_error_messages
= {
427 'invalid': _(u
'Enter a valid e-mail address.'),
429 default_validators
= [validators
.validate_email
]
431 class FileField(Field
):
433 default_error_messages
= {
434 'invalid': _(u
"No file was submitted. Check the encoding type on the form."),
435 'missing': _(u
"No file was submitted."),
436 'empty': _(u
"The submitted file is empty."),
437 'max_length': _(u
'Ensure this filename has at most %(max)d characters (it has %(length)d).'),
440 def __init__(self
, *args
, **kwargs
):
441 self
.max_length
= kwargs
.pop('max_length', None)
442 super(FileField
, self
).__init
__(*args
, **kwargs
)
444 def to_python(self
, data
):
445 if data
in validators
.EMPTY_VALUES
:
448 # UploadedFile objects should have name and size attributes.
450 file_name
= data
.name
451 file_size
= data
.size
452 except AttributeError:
453 raise ValidationError(self
.error_messages
['invalid'])
455 if self
.max_length
is not None and len(file_name
) > self
.max_length
:
456 error_values
= {'max': self
.max_length
, 'length': len(file_name
)}
457 raise ValidationError(self
.error_messages
['max_length'] % error_values
)
459 raise ValidationError(self
.error_messages
['invalid'])
461 raise ValidationError(self
.error_messages
['empty'])
465 def clean(self
, data
, initial
=None):
466 if not data
and initial
:
468 return super(FileField
, self
).clean(data
)
470 class ImageField(FileField
):
471 default_error_messages
= {
472 'invalid_image': _(u
"Upload a valid image. The file you uploaded was either not an image or a corrupted image."),
475 def to_python(self
, data
):
477 Checks that the file-upload field data contains a valid image (GIF, JPG,
478 PNG, possibly others -- whatever the Python Imaging Library supports).
480 f
= super(ImageField
, self
).to_python(data
)
484 # Try to import PIL in either of the two ways it can end up installed.
486 from PIL
import Image
490 # We need to get a file object for PIL. We might have a path or we might
491 # have to read the data into memory.
492 if hasattr(data
, 'temporary_file_path'):
493 file = data
.temporary_file_path()
495 if hasattr(data
, 'read'):
496 file = StringIO(data
.read())
498 file = StringIO(data
['content'])
501 # load() is the only method that can spot a truncated JPEG,
502 # but it cannot be called sanely after verify()
503 trial_image
= Image
.open(file)
506 # Since we're about to use the file again we have to reset the
507 # file object if possible.
508 if hasattr(file, 'reset'):
511 # verify() is the only method that can spot a corrupt PNG,
512 # but it must be called immediately after the constructor
513 trial_image
= Image
.open(file)
516 # Under PyPy, it is possible to import PIL. However, the underlying
517 # _imaging C module isn't available, so an ImportError will be
518 # raised. Catch and re-raise.
520 except Exception: # Python Imaging Library doesn't recognize it as an image
521 raise ValidationError(self
.error_messages
['invalid_image'])
522 if hasattr(f
, 'seek') and callable(f
.seek
):
526 class URLField(CharField
):
527 default_error_messages
= {
528 'invalid': _(u
'Enter a valid URL.'),
529 'invalid_link': _(u
'This URL appears to be a broken link.'),
532 def __init__(self
, max_length
=None, min_length
=None, verify_exists
=False,
533 validator_user_agent
=validators
.URL_VALIDATOR_USER_AGENT
, *args
, **kwargs
):
534 super(URLField
, self
).__init
__(max_length
, min_length
, *args
,
536 self
.validators
.append(validators
.URLValidator(verify_exists
=verify_exists
, validator_user_agent
=validator_user_agent
))
538 def to_python(self
, value
):
540 if '://' not in value
:
541 # If no URL scheme given, assume http://
542 value
= u
'http://%s' % value
543 url_fields
= list(urlparse
.urlsplit(value
))
544 if not url_fields
[2]:
545 # the path portion may need to be added before query params
547 value
= urlparse
.urlunsplit(url_fields
)
548 return super(URLField
, self
).to_python(value
)
550 class BooleanField(Field
):
551 widget
= CheckboxInput
553 def to_python(self
, value
):
554 """Returns a Python boolean object."""
555 # Explicitly check for the string 'False', which is what a hidden field
556 # will submit for False. Also check for '0', since this is what
557 # RadioSelect will provide. Because bool("True") == bool('1') == True,
558 # we don't need to handle that explicitly.
559 if value
in ('False', '0'):
563 value
= super(BooleanField
, self
).to_python(value
)
564 if not value
and self
.required
:
565 raise ValidationError(self
.error_messages
['required'])
568 class NullBooleanField(BooleanField
):
570 A field whose valid values are None, True and False. Invalid values are
573 widget
= NullBooleanSelect
575 def to_python(self
, value
):
577 Explicitly checks for the string 'True' and 'False', which is what a
578 hidden field will submit for True and False, and for '1' and '0', which
579 is what a RadioField will submit. Unlike the Booleanfield we need to
580 explicitly check for True, because we are not using the bool() function
582 if value
in (True, 'True', '1'):
584 elif value
in (False, 'False', '0'):
589 def validate(self
, value
):
592 class ChoiceField(Field
):
594 default_error_messages
= {
595 'invalid_choice': _(u
'Select a valid choice. %(value)s is not one of the available choices.'),
598 def __init__(self
, choices
=(), required
=True, widget
=None, label
=None,
599 initial
=None, help_text
=None, *args
, **kwargs
):
600 super(ChoiceField
, self
).__init
__(required
=required
, widget
=widget
, label
=label
,
601 initial
=initial
, help_text
=help_text
, *args
, **kwargs
)
602 self
.choices
= choices
604 def _get_choices(self
):
607 def _set_choices(self
, value
):
608 # Setting choices also sets the choices on the widget.
609 # choices can be any iterable, but we call list() on it because
610 # it will be consumed more than once.
611 self
._choices
= self
.widget
.choices
= list(value
)
613 choices
= property(_get_choices
, _set_choices
)
615 def to_python(self
, value
):
616 "Returns a Unicode object."
617 if value
in validators
.EMPTY_VALUES
:
619 return smart_unicode(value
)
621 def validate(self
, value
):
623 Validates that the input is in self.choices.
625 super(ChoiceField
, self
).validate(value
)
626 if value
and not self
.valid_value(value
):
627 raise ValidationError(self
.error_messages
['invalid_choice'] % {'value': value
})
629 def valid_value(self
, value
):
630 "Check to see if the provided value is a valid choice"
631 for k
, v
in self
.choices
:
632 if isinstance(v
, (list, tuple)):
633 # This is an optgroup, so look inside the group for options
635 if value
== smart_unicode(k2
):
638 if value
== smart_unicode(k
):
642 class TypedChoiceField(ChoiceField
):
643 def __init__(self
, *args
, **kwargs
):
644 self
.coerce = kwargs
.pop('coerce', lambda val
: val
)
645 self
.empty_value
= kwargs
.pop('empty_value', '')
646 super(TypedChoiceField
, self
).__init
__(*args
, **kwargs
)
648 def to_python(self
, value
):
650 Validate that the value is in self.choices and can be coerced to the
653 value
= super(TypedChoiceField
, self
).to_python(value
)
654 super(TypedChoiceField
, self
).validate(value
)
655 if value
== self
.empty_value
or value
in validators
.EMPTY_VALUES
:
656 return self
.empty_value
658 value
= self
.coerce(value
)
659 except (ValueError, TypeError, ValidationError
):
660 raise ValidationError(self
.error_messages
['invalid_choice'] % {'value': value
})
663 def validate(self
, value
):
666 class MultipleChoiceField(ChoiceField
):
667 hidden_widget
= MultipleHiddenInput
668 widget
= SelectMultiple
669 default_error_messages
= {
670 'invalid_choice': _(u
'Select a valid choice. %(value)s is not one of the available choices.'),
671 'invalid_list': _(u
'Enter a list of values.'),
674 def to_python(self
, value
):
677 elif not isinstance(value
, (list, tuple)):
678 raise ValidationError(self
.error_messages
['invalid_list'])
679 return [smart_unicode(val
) for val
in value
]
681 def validate(self
, value
):
683 Validates that the input is a list or tuple.
685 if self
.required
and not value
:
686 raise ValidationError(self
.error_messages
['required'])
687 # Validate that each value in the value list is in self.choices.
689 if not self
.valid_value(val
):
690 raise ValidationError(self
.error_messages
['invalid_choice'] % {'value': val
})
692 class ComboField(Field
):
694 A Field whose clean() method calls multiple Field clean() methods.
696 def __init__(self
, fields
=(), *args
, **kwargs
):
697 super(ComboField
, self
).__init
__(*args
, **kwargs
)
698 # Set 'required' to False on the individual fields, because the
699 # required validation will be handled by ComboField, not by those
705 def clean(self
, value
):
707 Validates the given value against all of self.fields, which is a
708 list of Field instances.
710 super(ComboField
, self
).clean(value
)
711 for field
in self
.fields
:
712 value
= field
.clean(value
)
715 class MultiValueField(Field
):
717 A Field that aggregates the logic of multiple Fields.
719 Its clean() method takes a "decompressed" list of values, which are then
720 cleaned into a single value according to self.fields. Each value in
721 this list is cleaned by the corresponding field -- the first value is
722 cleaned by the first field, the second value is cleaned by the second
723 field, etc. Once all fields are cleaned, the list of clean values is
724 "compressed" into a single value.
726 Subclasses should not have to implement clean(). Instead, they must
727 implement compress(), which takes a list of valid values and returns a
728 "compressed" version of those values -- a single value.
730 You'll probably want to use this with MultiWidget.
732 default_error_messages
= {
733 'invalid': _(u
'Enter a list of values.'),
736 def __init__(self
, fields
=(), *args
, **kwargs
):
737 super(MultiValueField
, self
).__init
__(*args
, **kwargs
)
738 # Set 'required' to False on the individual fields, because the
739 # required validation will be handled by MultiValueField, not by those
745 def validate(self
, value
):
748 def clean(self
, value
):
750 Validates every value in the given list. A value is validated against
751 the corresponding Field in self.fields.
753 For example, if this MultiValueField was instantiated with
754 fields=(DateField(), TimeField()), clean() would call
755 DateField.clean(value[0]) and TimeField.clean(value[1]).
759 if not value
or isinstance(value
, (list, tuple)):
760 if not value
or not [v
for v
in value
if v
not in validators
.EMPTY_VALUES
]:
762 raise ValidationError(self
.error_messages
['required'])
764 return self
.compress([])
766 raise ValidationError(self
.error_messages
['invalid'])
767 for i
, field
in enumerate(self
.fields
):
769 field_value
= value
[i
]
772 if self
.required
and field_value
in validators
.EMPTY_VALUES
:
773 raise ValidationError(self
.error_messages
['required'])
775 clean_data
.append(field
.clean(field_value
))
776 except ValidationError
, e
:
777 # Collect all validation errors in a single list, which we'll
778 # raise at the end of clean(), rather than raising a single
779 # exception for the first error we encounter.
780 errors
.extend(e
.messages
)
782 raise ValidationError(errors
)
784 out
= self
.compress(clean_data
)
788 def compress(self
, data_list
):
790 Returns a single value for the given list of values. The values can be
793 For example, if this MultiValueField was instantiated with
794 fields=(DateField(), TimeField()), this might return a datetime
795 object created by combining the date and time in data_list.
797 raise NotImplementedError('Subclasses must implement this method.')
799 class FilePathField(ChoiceField
):
800 def __init__(self
, path
, match
=None, recursive
=False, required
=True,
801 widget
=None, label
=None, initial
=None, help_text
=None,
803 self
.path
, self
.match
, self
.recursive
= path
, match
, recursive
804 super(FilePathField
, self
).__init
__(choices
=(), required
=required
,
805 widget
=widget
, label
=label
, initial
=initial
, help_text
=help_text
,
811 self
.choices
= [("", "---------")]
813 if self
.match
is not None:
814 self
.match_re
= re
.compile(self
.match
)
817 for root
, dirs
, files
in os
.walk(self
.path
):
819 if self
.match
is None or self
.match_re
.search(f
):
820 f
= os
.path
.join(root
, f
)
821 self
.choices
.append((f
, f
.replace(path
, "", 1)))
824 for f
in os
.listdir(self
.path
):
825 full_file
= os
.path
.join(self
.path
, f
)
826 if os
.path
.isfile(full_file
) and (self
.match
is None or self
.match_re
.search(f
)):
827 self
.choices
.append((full_file
, f
))
831 self
.widget
.choices
= self
.choices
833 class SplitDateTimeField(MultiValueField
):
834 widget
= SplitDateTimeWidget
835 hidden_widget
= SplitHiddenDateTimeWidget
836 default_error_messages
= {
837 'invalid_date': _(u
'Enter a valid date.'),
838 'invalid_time': _(u
'Enter a valid time.'),
841 def __init__(self
, input_date_formats
=None, input_time_formats
=None, *args
, **kwargs
):
842 errors
= self
.default_error_messages
.copy()
843 if 'error_messages' in kwargs
:
844 errors
.update(kwargs
['error_messages'])
845 localize
= kwargs
.get('localize', False)
847 DateField(input_formats
=input_date_formats
,
848 error_messages
={'invalid': errors
['invalid_date']},
850 TimeField(input_formats
=input_time_formats
,
851 error_messages
={'invalid': errors
['invalid_time']},
854 super(SplitDateTimeField
, self
).__init
__(fields
, *args
, **kwargs
)
856 def compress(self
, data_list
):
858 # Raise a validation error if time or date is empty
859 # (possible if SplitDateTimeField has required=False).
860 if data_list
[0] in validators
.EMPTY_VALUES
:
861 raise ValidationError(self
.error_messages
['invalid_date'])
862 if data_list
[1] in validators
.EMPTY_VALUES
:
863 raise ValidationError(self
.error_messages
['invalid_time'])
864 return datetime
.datetime
.combine(*data_list
)
868 class IPAddressField(CharField
):
869 default_error_messages
= {
870 'invalid': _(u
'Enter a valid IPv4 address.'),
872 default_validators
= [validators
.validate_ipv4_address
]
875 class SlugField(CharField
):
876 default_error_messages
= {
877 'invalid': _(u
"Enter a valid 'slug' consisting of letters, numbers,"
878 u
" underscores or hyphens."),
880 default_validators
= [validators
.validate_slug
]