App Engine Python SDK version 1.9.12
[gae.git] / python / lib / django-0.96 / django / newforms / fields.py
blobfed516ee15f57d74243956e736bcacbf60ec94cd
1 """
2 Field classes
3 """
5 from django.utils.translation import gettext
6 from util import ErrorList, ValidationError, smart_unicode
7 from widgets import TextInput, PasswordInput, HiddenInput, MultipleHiddenInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple
8 import datetime
9 import re
10 import time
12 __all__ = (
13 'Field', 'CharField', 'IntegerField',
14 'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
15 'DEFAULT_TIME_INPUT_FORMATS', 'TimeField',
16 'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
17 'RegexField', 'EmailField', 'URLField', 'BooleanField',
18 'ChoiceField', 'NullBooleanField', 'MultipleChoiceField',
19 'ComboField', 'MultiValueField',
20 'SplitDateTimeField',
23 # These values, if given to to_python(), will trigger the self.required check.
24 EMPTY_VALUES = (None, '')
26 try:
27 set # Only available in Python 2.4+
28 except NameError:
29 from sets import Set as set # Python 2.3 fallback
31 class Field(object):
32 widget = TextInput # Default widget to use when rendering this type of Field.
33 hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden".
35 # Tracks each time a Field instance is created. Used to retain order.
36 creation_counter = 0
38 def __init__(self, required=True, widget=None, label=None, initial=None, help_text=None):
39 # required -- Boolean that specifies whether the field is required.
40 # True by default.
41 # widget -- A Widget class, or instance of a Widget class, that should be
42 # used for this Field when displaying it. Each Field has a default
43 # Widget that it'll use if you don't specify this. In most cases,
44 # the default widget is TextInput.
45 # label -- A verbose name for this field, for use in displaying this field in
46 # a form. By default, Django will use a "pretty" version of the form
47 # field name, if the Field is part of a Form.
48 # initial -- A value to use in this Field's initial display. This value is
49 # *not* used as a fallback if data isn't given.
50 # help_text -- An optional string to use as "help text" for this Field.
51 if label is not None:
52 label = smart_unicode(label)
53 self.required, self.label, self.initial = required, label, initial
54 self.help_text = smart_unicode(help_text or '')
55 widget = widget or self.widget
56 if isinstance(widget, type):
57 widget = widget()
59 # Hook into self.widget_attrs() for any Field-specific HTML attributes.
60 extra_attrs = self.widget_attrs(widget)
61 if extra_attrs:
62 widget.attrs.update(extra_attrs)
64 self.widget = widget
66 # Increase the creation counter, and save our local copy.
67 self.creation_counter = Field.creation_counter
68 Field.creation_counter += 1
70 def clean(self, value):
71 """
72 Validates the given value and returns its "cleaned" value as an
73 appropriate Python object.
75 Raises ValidationError for any errors.
76 """
77 if self.required and value in EMPTY_VALUES:
78 raise ValidationError(gettext(u'This field is required.'))
79 return value
81 def widget_attrs(self, widget):
82 """
83 Given a Widget instance (*not* a Widget class), returns a dictionary of
84 any HTML attributes that should be added to the Widget, based on this
85 Field.
86 """
87 return {}
89 class CharField(Field):
90 def __init__(self, max_length=None, min_length=None, *args, **kwargs):
91 self.max_length, self.min_length = max_length, min_length
92 super(CharField, self).__init__(*args, **kwargs)
94 def clean(self, value):
95 "Validates max_length and min_length. Returns a Unicode object."
96 super(CharField, self).clean(value)
97 if value in EMPTY_VALUES:
98 return u''
99 value = smart_unicode(value)
100 if self.max_length is not None and len(value) > self.max_length:
101 raise ValidationError(gettext(u'Ensure this value has at most %d characters.') % self.max_length)
102 if self.min_length is not None and len(value) < self.min_length:
103 raise ValidationError(gettext(u'Ensure this value has at least %d characters.') % self.min_length)
104 return value
106 def widget_attrs(self, widget):
107 if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
108 return {'maxlength': str(self.max_length)}
110 class IntegerField(Field):
111 def __init__(self, max_value=None, min_value=None, *args, **kwargs):
112 self.max_value, self.min_value = max_value, min_value
113 super(IntegerField, self).__init__(*args, **kwargs)
115 def clean(self, value):
117 Validates that int() can be called on the input. Returns the result
118 of int(). Returns None for empty values.
120 super(IntegerField, self).clean(value)
121 if value in EMPTY_VALUES:
122 return None
123 try:
124 value = int(value)
125 except (ValueError, TypeError):
126 raise ValidationError(gettext(u'Enter a whole number.'))
127 if self.max_value is not None and value > self.max_value:
128 raise ValidationError(gettext(u'Ensure this value is less than or equal to %s.') % self.max_value)
129 if self.min_value is not None and value < self.min_value:
130 raise ValidationError(gettext(u'Ensure this value is greater than or equal to %s.') % self.min_value)
131 return value
133 DEFAULT_DATE_INPUT_FORMATS = (
134 '%Y-%m-%d', '%m/%d/%Y', '%m/%d/%y', # '2006-10-25', '10/25/2006', '10/25/06'
135 '%b %d %Y', '%b %d, %Y', # 'Oct 25 2006', 'Oct 25, 2006'
136 '%d %b %Y', '%d %b, %Y', # '25 Oct 2006', '25 Oct, 2006'
137 '%B %d %Y', '%B %d, %Y', # 'October 25 2006', 'October 25, 2006'
138 '%d %B %Y', '%d %B, %Y', # '25 October 2006', '25 October, 2006'
141 class DateField(Field):
142 def __init__(self, input_formats=None, *args, **kwargs):
143 super(DateField, self).__init__(*args, **kwargs)
144 self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
146 def clean(self, value):
148 Validates that the input can be converted to a date. Returns a Python
149 datetime.date object.
151 super(DateField, self).clean(value)
152 if value in EMPTY_VALUES:
153 return None
154 if isinstance(value, datetime.datetime):
155 return value.date()
156 if isinstance(value, datetime.date):
157 return value
158 for format in self.input_formats:
159 try:
160 return datetime.date(*time.strptime(value, format)[:3])
161 except ValueError:
162 continue
163 raise ValidationError(gettext(u'Enter a valid date.'))
165 DEFAULT_TIME_INPUT_FORMATS = (
166 '%H:%M:%S', # '14:30:59'
167 '%H:%M', # '14:30'
170 class TimeField(Field):
171 def __init__(self, input_formats=None, *args, **kwargs):
172 super(TimeField, self).__init__(*args, **kwargs)
173 self.input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS
175 def clean(self, value):
177 Validates that the input can be converted to a time. Returns a Python
178 datetime.time object.
180 super(TimeField, self).clean(value)
181 if value in EMPTY_VALUES:
182 return None
183 if isinstance(value, datetime.time):
184 return value
185 for format in self.input_formats:
186 try:
187 return datetime.time(*time.strptime(value, format)[3:6])
188 except ValueError:
189 continue
190 raise ValidationError(gettext(u'Enter a valid time.'))
192 DEFAULT_DATETIME_INPUT_FORMATS = (
193 '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
194 '%Y-%m-%d %H:%M', # '2006-10-25 14:30'
195 '%Y-%m-%d', # '2006-10-25'
196 '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
197 '%m/%d/%Y %H:%M', # '10/25/2006 14:30'
198 '%m/%d/%Y', # '10/25/2006'
199 '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
200 '%m/%d/%y %H:%M', # '10/25/06 14:30'
201 '%m/%d/%y', # '10/25/06'
204 class DateTimeField(Field):
205 def __init__(self, input_formats=None, *args, **kwargs):
206 super(DateTimeField, self).__init__(*args, **kwargs)
207 self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
209 def clean(self, value):
211 Validates that the input can be converted to a datetime. Returns a
212 Python datetime.datetime object.
214 super(DateTimeField, self).clean(value)
215 if value in EMPTY_VALUES:
216 return None
217 if isinstance(value, datetime.datetime):
218 return value
219 if isinstance(value, datetime.date):
220 return datetime.datetime(value.year, value.month, value.day)
221 for format in self.input_formats:
222 try:
223 return datetime.datetime(*time.strptime(value, format)[:6])
224 except ValueError:
225 continue
226 raise ValidationError(gettext(u'Enter a valid date/time.'))
228 class RegexField(Field):
229 def __init__(self, regex, max_length=None, min_length=None, error_message=None, *args, **kwargs):
231 regex can be either a string or a compiled regular expression object.
232 error_message is an optional error message to use, if
233 'Enter a valid value' is too generic for you.
235 super(RegexField, self).__init__(*args, **kwargs)
236 if isinstance(regex, basestring):
237 regex = re.compile(regex)
238 self.regex = regex
239 self.max_length, self.min_length = max_length, min_length
240 self.error_message = error_message or gettext(u'Enter a valid value.')
242 def clean(self, value):
244 Validates that the input matches the regular expression. Returns a
245 Unicode object.
247 super(RegexField, self).clean(value)
248 if value in EMPTY_VALUES:
249 value = u''
250 value = smart_unicode(value)
251 if value == u'':
252 return value
253 if self.max_length is not None and len(value) > self.max_length:
254 raise ValidationError(gettext(u'Ensure this value has at most %d characters.') % self.max_length)
255 if self.min_length is not None and len(value) < self.min_length:
256 raise ValidationError(gettext(u'Ensure this value has at least %d characters.') % self.min_length)
257 if not self.regex.search(value):
258 raise ValidationError(self.error_message)
259 return value
261 email_re = re.compile(
262 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
263 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
264 r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE) # domain
266 class EmailField(RegexField):
267 def __init__(self, max_length=None, min_length=None, *args, **kwargs):
268 RegexField.__init__(self, email_re, max_length, min_length,
269 gettext(u'Enter a valid e-mail address.'), *args, **kwargs)
271 url_re = re.compile(
272 r'^https?://' # http:// or https://
273 r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
274 r'localhost|' #localhost...
275 r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
276 r'(?::\d+)?' # optional port
277 r'(?:/?|/\S+)$', re.IGNORECASE)
279 try:
280 from django.conf import settings
281 URL_VALIDATOR_USER_AGENT = settings.URL_VALIDATOR_USER_AGENT
282 except ImportError:
283 # It's OK if Django settings aren't configured.
284 URL_VALIDATOR_USER_AGENT = 'Django (http://www.djangoproject.com/)'
286 class URLField(RegexField):
287 def __init__(self, max_length=None, min_length=None, verify_exists=False,
288 validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
289 super(URLField, self).__init__(url_re, max_length, min_length, gettext(u'Enter a valid URL.'), *args, **kwargs)
290 self.verify_exists = verify_exists
291 self.user_agent = validator_user_agent
293 def clean(self, value):
294 value = super(URLField, self).clean(value)
295 if value == u'':
296 return value
297 if self.verify_exists:
298 import urllib2
299 from django.conf import settings
300 headers = {
301 "Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
302 "Accept-Language": "en-us,en;q=0.5",
303 "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
304 "Connection": "close",
305 "User-Agent": self.user_agent,
307 try:
308 req = urllib2.Request(value, None, headers)
309 u = urllib2.urlopen(req)
310 except ValueError:
311 raise ValidationError(gettext(u'Enter a valid URL.'))
312 except: # urllib2.URLError, httplib.InvalidURL, etc.
313 raise ValidationError(gettext(u'This URL appears to be a broken link.'))
314 return value
316 class BooleanField(Field):
317 widget = CheckboxInput
319 def clean(self, value):
320 "Returns a Python boolean object."
321 super(BooleanField, self).clean(value)
322 return bool(value)
324 class NullBooleanField(BooleanField):
326 A field whose valid values are None, True and False. Invalid values are
327 cleaned to None.
329 widget = NullBooleanSelect
331 def clean(self, value):
332 return {True: True, False: False}.get(value, None)
334 class ChoiceField(Field):
335 def __init__(self, choices=(), required=True, widget=Select, label=None, initial=None, help_text=None):
336 super(ChoiceField, self).__init__(required, widget, label, initial, help_text)
337 self.choices = choices
339 def _get_choices(self):
340 return self._choices
342 def _set_choices(self, value):
343 # Setting choices also sets the choices on the widget.
344 # choices can be any iterable, but we call list() on it because
345 # it will be consumed more than once.
346 self._choices = self.widget.choices = list(value)
348 choices = property(_get_choices, _set_choices)
350 def clean(self, value):
352 Validates that the input is in self.choices.
354 value = super(ChoiceField, self).clean(value)
355 if value in EMPTY_VALUES:
356 value = u''
357 value = smart_unicode(value)
358 if value == u'':
359 return value
360 valid_values = set([str(k) for k, v in self.choices])
361 if value not in valid_values:
362 raise ValidationError(gettext(u'Select a valid choice. That choice is not one of the available choices.'))
363 return value
365 class MultipleChoiceField(ChoiceField):
366 hidden_widget = MultipleHiddenInput
368 def __init__(self, choices=(), required=True, widget=SelectMultiple, label=None, initial=None, help_text=None):
369 super(MultipleChoiceField, self).__init__(choices, required, widget, label, initial, help_text)
371 def clean(self, value):
373 Validates that the input is a list or tuple.
375 if self.required and not value:
376 raise ValidationError(gettext(u'This field is required.'))
377 elif not self.required and not value:
378 return []
379 if not isinstance(value, (list, tuple)):
380 raise ValidationError(gettext(u'Enter a list of values.'))
381 new_value = []
382 for val in value:
383 val = smart_unicode(val)
384 new_value.append(val)
385 # Validate that each value in the value list is in self.choices.
386 valid_values = set([smart_unicode(k) for k, v in self.choices])
387 for val in new_value:
388 if val not in valid_values:
389 raise ValidationError(gettext(u'Select a valid choice. %s is not one of the available choices.') % val)
390 return new_value
392 class ComboField(Field):
394 A Field whose clean() method calls multiple Field clean() methods.
396 def __init__(self, fields=(), *args, **kwargs):
397 super(ComboField, self).__init__(*args, **kwargs)
398 # Set 'required' to False on the individual fields, because the
399 # required validation will be handled by ComboField, not by those
400 # individual fields.
401 for f in fields:
402 f.required = False
403 self.fields = fields
405 def clean(self, value):
407 Validates the given value against all of self.fields, which is a
408 list of Field instances.
410 super(ComboField, self).clean(value)
411 for field in self.fields:
412 value = field.clean(value)
413 return value
415 class MultiValueField(Field):
417 A Field that is composed of multiple Fields.
419 Its clean() method takes a "decompressed" list of values. Each value in
420 this list is cleaned by the corresponding field -- the first value is
421 cleaned by the first field, the second value is cleaned by the second
422 field, etc. Once all fields are cleaned, the list of clean values is
423 "compressed" into a single value.
425 Subclasses should implement compress(), which specifies how a list of
426 valid values should be converted to a single value. Subclasses should not
427 have to implement clean().
429 You'll probably want to use this with MultiWidget.
431 def __init__(self, fields=(), *args, **kwargs):
432 super(MultiValueField, self).__init__(*args, **kwargs)
433 # Set 'required' to False on the individual fields, because the
434 # required validation will be handled by MultiValueField, not by those
435 # individual fields.
436 for f in fields:
437 f.required = False
438 self.fields = fields
440 def clean(self, value):
442 Validates every value in the given list. A value is validated against
443 the corresponding Field in self.fields.
445 For example, if this MultiValueField was instantiated with
446 fields=(DateField(), TimeField()), clean() would call
447 DateField.clean(value[0]) and TimeField.clean(value[1]).
449 clean_data = []
450 errors = ErrorList()
451 if self.required and not value:
452 raise ValidationError(gettext(u'This field is required.'))
453 elif not self.required and not value:
454 return self.compress([])
455 if not isinstance(value, (list, tuple)):
456 raise ValidationError(gettext(u'Enter a list of values.'))
457 for i, field in enumerate(self.fields):
458 try:
459 field_value = value[i]
460 except KeyError:
461 field_value = None
462 if self.required and field_value in EMPTY_VALUES:
463 raise ValidationError(gettext(u'This field is required.'))
464 try:
465 clean_data.append(field.clean(field_value))
466 except ValidationError, e:
467 # Collect all validation errors in a single list, which we'll
468 # raise at the end of clean(), rather than raising a single
469 # exception for the first error we encounter.
470 errors.extend(e.messages)
471 if errors:
472 raise ValidationError(errors)
473 return self.compress(clean_data)
475 def compress(self, data_list):
477 Returns a single value for the given list of values. The values can be
478 assumed to be valid.
480 For example, if this MultiValueField was instantiated with
481 fields=(DateField(), TimeField()), this might return a datetime
482 object created by combining the date and time in data_list.
484 raise NotImplementedError('Subclasses must implement this method.')
486 class SplitDateTimeField(MultiValueField):
487 def __init__(self, *args, **kwargs):
488 fields = (DateField(), TimeField())
489 super(SplitDateTimeField, self).__init__(fields, *args, **kwargs)
491 def compress(self, data_list):
492 if data_list:
493 return datetime.datetime.combine(*data_list)
494 return None