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,
30
MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select,
31
NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput,
32
SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION)
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'
46
Helper function to stay backward compatible.
48
from django.conf.locale.en import formats
50
"`django.forms.fields.DEFAULT_%s` is deprecated; use `django.utils.formats.get_format('%s')` instead." % (name, name),
53
return getattr(formats, name)
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.'),
64
# Tracks each time a Field instance is created. Used to retain order.
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.
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
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.
90
label = smart_unicode(label)
91
self.required, self.label, self.initial = required, label, initial
92
self.show_hidden_initial = show_hidden_initial
96
self.help_text = smart_unicode(help_text)
97
widget = widget or self.widget
98
if isinstance(widget, type):
101
# Trigger the localization machinery if needed.
102
self.localize = localize
104
widget.is_localized = True
106
# Let the widget know whether it should display as required.
107
widget.is_required = self.required
109
# Hook into self.widget_attrs() for any Field-specific HTML attributes.
110
extra_attrs = self.widget_attrs(widget)
112
widget.attrs.update(extra_attrs)
116
# Increase the creation counter, and save our local copy.
117
self.creation_counter = Field.creation_counter
118
Field.creation_counter += 1
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
126
self.validators = self.default_validators + validators
128
def prepare_value(self, value):
131
def to_python(self, value):
134
def validate(self, value):
135
if value in validators.EMPTY_VALUES and self.required:
136
raise ValidationError(self.error_messages['required'])
138
def run_validators(self, value):
139
if value in validators.EMPTY_VALUES:
142
for v in self.validators:
145
except ValidationError, e:
146
if hasattr(e, 'code') and e.code in self.error_messages:
147
message = self.error_messages[e.code]
149
message = message % e.params
150
errors.append(message)
152
errors.extend(e.messages)
154
raise ValidationError(errors)
156
def clean(self, value):
158
Validates the given value and returns its "cleaned" value as an
159
appropriate Python object.
161
Raises ValidationError for any errors.
163
value = self.to_python(value)
165
self.run_validators(value)
168
def bound_data(self, data, initial):
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
174
For most fields, this will simply be data; FileFields need to handle it
179
def widget_attrs(self, widget):
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
187
def __deepcopy__(self, memo):
188
result = copy.copy(self)
189
memo[id(self)] = result
190
result.widget = copy.deepcopy(self.widget, memo)
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))
202
def to_python(self, value):
203
"Returns a Unicode object."
204
if value in validators.EMPTY_VALUES:
206
return smart_unicode(value)
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)}
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.'),
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)
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))
229
def to_python(self, value):
231
Validates that int() can be called on the input. Returns the result
232
of int(). Returns None for empty values.
234
value = super(IntegerField, self).to_python(value)
235
if value in validators.EMPTY_VALUES:
238
value = formats.sanitize_separators(value)
240
value = int(str(value))
241
except (ValueError, TypeError):
242
raise ValidationError(self.error_messages['invalid'])
245
class FloatField(IntegerField):
246
default_error_messages = {
247
'invalid': _(u'Enter a number.'),
250
def to_python(self, value):
252
Validates that float() can be called on the input. Returns the result
253
of float(). Returns None for empty values.
255
value = super(IntegerField, self).to_python(value)
256
if value in validators.EMPTY_VALUES:
259
value = formats.sanitize_separators(value)
262
except (ValueError, TypeError):
263
raise ValidationError(self.error_messages['invalid'])
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.')
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)
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))
286
def to_python(self, value):
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.
293
if value in validators.EMPTY_VALUES:
296
value = formats.sanitize_separators(value)
297
value = smart_str(value).strip()
299
value = Decimal(value)
300
except DecimalException:
301
raise ValidationError(self.error_messages['invalid'])
304
def validate(self, value):
305
super(DecimalField, self).validate(value)
306
if value in validators.EMPTY_VALUES:
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.
323
whole_digits = digits - decimals
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))
333
class DateField(Field):
335
default_error_messages = {
336
'invalid': _(u'Enter a valid date.'),
339
def __init__(self, input_formats=None, *args, **kwargs):
340
super(DateField, self).__init__(*args, **kwargs)
341
self.input_formats = input_formats
343
def to_python(self, value):
345
Validates that the input can be converted to a date. Returns a Python
346
datetime.date object.
348
if value in validators.EMPTY_VALUES:
350
if isinstance(value, datetime.datetime):
352
if isinstance(value, datetime.date):
354
for format in self.input_formats or formats.get_format('DATE_INPUT_FORMATS'):
356
return datetime.date(*time.strptime(value, format)[:3])
359
raise ValidationError(self.error_messages['invalid'])
361
class TimeField(Field):
363
default_error_messages = {
364
'invalid': _(u'Enter a valid time.')
367
def __init__(self, input_formats=None, *args, **kwargs):
368
super(TimeField, self).__init__(*args, **kwargs)
369
self.input_formats = input_formats
371
def to_python(self, value):
373
Validates that the input can be converted to a time. Returns a Python
374
datetime.time object.
376
if value in validators.EMPTY_VALUES:
378
if isinstance(value, datetime.time):
380
for format in self.input_formats or formats.get_format('TIME_INPUT_FORMATS'):
382
return datetime.time(*time.strptime(value, format)[3:6])
385
raise ValidationError(self.error_messages['invalid'])
387
class DateTimeField(Field):
388
widget = DateTimeInput
389
default_error_messages = {
390
'invalid': _(u'Enter a valid date/time.'),
393
def __init__(self, input_formats=None, *args, **kwargs):
394
super(DateTimeField, self).__init__(*args, **kwargs)
395
self.input_formats = input_formats
397
def to_python(self, value):
399
Validates that the input can be converted to a datetime. Returns a
400
Python datetime.datetime object.
402
if value in validators.EMPTY_VALUES:
404
if isinstance(value, datetime.datetime):
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.
412
raise ValidationError(self.error_messages['invalid'])
413
if value[0] in validators.EMPTY_VALUES and value[1] in validators.EMPTY_VALUES:
415
value = '%s %s' % tuple(value)
416
for format in self.input_formats or formats.get_format('DATETIME_INPUT_FORMATS'):
418
return datetime.datetime(*time.strptime(value, format)[:6])
421
raise ValidationError(self.error_messages['invalid'])
423
class RegexField(CharField):
424
def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs):
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.
430
# error_message is just kept for backwards compatibility:
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)
439
self.validators.append(validators.RegexValidator(regex=regex))
441
class EmailField(CharField):
442
default_error_messages = {
443
'invalid': _(u'Enter a valid e-mail address.'),
445
default_validators = [validators.validate_email]
447
def clean(self, value):
448
value = self.to_python(value).strip()
449
return super(EmailField, self).clean(value)
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.')
461
def __init__(self, *args, **kwargs):
462
self.max_length = kwargs.pop('max_length', None)
463
super(FileField, self).__init__(*args, **kwargs)
465
def to_python(self, data):
466
if data in validators.EMPTY_VALUES:
469
# UploadedFile objects should have name and size attributes.
471
file_name = data.name
472
file_size = data.size
473
except AttributeError:
474
raise ValidationError(self.error_messages['invalid'])
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)
480
raise ValidationError(self.error_messages['invalid'])
482
raise ValidationError(self.error_messages['empty'])
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
493
if not self.required:
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).
501
if not data and initial:
503
return super(FileField, self).clean(data)
505
def bound_data(self, data, initial):
506
if data in (None, FILE_INPUT_CONTRADICTION):
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."),
515
def to_python(self, data):
517
Checks that the file-upload field data contains a valid image (GIF, JPG,
518
PNG, possibly others -- whatever the Python Imaging Library supports).
520
f = super(ImageField, self).to_python(data)
524
# Try to import PIL in either of the two ways it can end up installed.
526
from PIL import Image
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()
535
if hasattr(data, 'read'):
536
file = StringIO(data.read())
538
file = StringIO(data['content'])
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()
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.
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):
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.'),
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,
566
self.validators.append(validators.URLValidator(verify_exists=verify_exists, validator_user_agent=validator_user_agent))
568
def to_python(self, 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]
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
586
value = urlparse.urlunsplit(url_fields)
587
return super(URLField, self).to_python(value)
589
class BooleanField(Field):
590
widget = CheckboxInput
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'):
602
value = super(BooleanField, self).to_python(value)
603
if not value and self.required:
604
raise ValidationError(self.error_messages['required'])
607
class NullBooleanField(BooleanField):
609
A field whose valid values are None, True and False. Invalid values are
612
widget = NullBooleanSelect
614
def to_python(self, value):
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
621
if value in (True, 'True', '1'):
623
elif value in (False, 'False', '0'):
628
def validate(self, value):
631
class ChoiceField(Field):
633
default_error_messages = {
634
'invalid_choice': _(u'Select a valid choice. %(value)s is not one of the available choices.'),
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
643
def _get_choices(self):
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)
652
choices = property(_get_choices, _set_choices)
654
def to_python(self, value):
655
"Returns a Unicode object."
656
if value in validators.EMPTY_VALUES:
658
return smart_unicode(value)
660
def validate(self, value):
662
Validates that the input is in self.choices.
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})
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
674
if value == smart_unicode(k2):
677
if value == smart_unicode(k):
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)
687
def to_python(self, value):
689
Validates that the value is in self.choices and can be coerced to the
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
697
value = self.coerce(value)
698
except (ValueError, TypeError, ValidationError):
699
raise ValidationError(self.error_messages['invalid_choice'] % {'value': value})
702
def validate(self, value):
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.'),
713
def to_python(self, value):
716
elif not isinstance(value, (list, tuple)):
717
raise ValidationError(self.error_messages['invalid_list'])
718
return [smart_unicode(val) for val in value]
720
def validate(self, value):
722
Validates that the input is a list or tuple.
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.
728
if not self.valid_value(val):
729
raise ValidationError(self.error_messages['invalid_choice'] % {'value': val})
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)
737
def to_python(self, value):
739
Validates that the values are in self.choices and can be coerced to the
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
749
new_value.append(self.coerce(choice))
750
except (ValueError, TypeError, ValidationError):
751
raise ValidationError(self.error_messages['invalid_choice'] % {'value': choice})
754
def validate(self, value):
757
class ComboField(Field):
759
A Field whose clean() method calls multiple Field clean() methods.
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
770
def clean(self, value):
772
Validates the given value against all of self.fields, which is a
773
list of Field instances.
775
super(ComboField, self).clean(value)
776
for field in self.fields:
777
value = field.clean(value)
780
class MultiValueField(Field):
782
A Field that aggregates the logic of multiple Fields.
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.
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.
795
You'll probably want to use this with MultiWidget.
797
default_error_messages = {
798
'invalid': _(u'Enter a list of values.'),
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
810
def validate(self, value):
813
def clean(self, value):
815
Validates every value in the given list. A value is validated against
816
the corresponding Field in self.fields.
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]).
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]:
827
raise ValidationError(self.error_messages['required'])
829
return self.compress([])
831
raise ValidationError(self.error_messages['invalid'])
832
for i, field in enumerate(self.fields):
834
field_value = value[i]
837
if self.required and field_value in validators.EMPTY_VALUES:
838
raise ValidationError(self.error_messages['required'])
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)
847
raise ValidationError(errors)
849
out = self.compress(clean_data)
853
def compress(self, data_list):
855
Returns a single value for the given list of values. The values can be
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.
862
raise NotImplementedError('Subclasses must implement this method.')
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,
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,
876
self.choices = [("", "---------")]
878
if self.match is not None:
879
self.match_re = re.compile(self.match)
882
for root, dirs, files in sorted(os.walk(self.path)):
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)))
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))
896
self.widget.choices = self.choices
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.'),
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)
912
DateField(input_formats=input_date_formats,
913
error_messages={'invalid': errors['invalid_date']},
915
TimeField(input_formats=input_time_formats,
916
error_messages={'invalid': errors['invalid_time']},
919
super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
921
def compress(self, 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)
933
class IPAddressField(CharField):
934
default_error_messages = {
935
'invalid': _(u'Enter a valid IPv4 address.'),
937
default_validators = [validators.validate_ipv4_address]
940
class SlugField(CharField):
941
default_error_messages = {
942
'invalid': _(u"Enter a valid 'slug' consisting of letters, numbers,"
943
u" underscores or hyphens."),
945
default_validators = [validators.validate_slug]