summaryrefslogtreecommitdiff
path: root/django/newforms/fields.py
diff options
context:
space:
mode:
authorJason Pellerin <jpellerin@gmail.com>2006-12-04 20:29:44 +0000
committerJason Pellerin <jpellerin@gmail.com>2006-12-04 20:29:44 +0000
commitb7a897eebbd4797c58b004eda7c6a30f9971eac2 (patch)
treefd79ac06b0f20909a770a46e2b692fbe506441a2 /django/newforms/fields.py
parent040f2272e0aec724a36e7abda445b61ee065a8f1 (diff)
[multi-db] Merged trunk to [4000]. Some tests still failing.
git-svn-id: http://code.djangoproject.com/svn/django/branches/multiple-db-support@4156 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/newforms/fields.py')
-rw-r--r--django/newforms/fields.py125
1 files changed, 109 insertions, 16 deletions
diff --git a/django/newforms/fields.py b/django/newforms/fields.py
index ea401fdfab..79558bbf9e 100644
--- a/django/newforms/fields.py
+++ b/django/newforms/fields.py
@@ -3,7 +3,7 @@ Field classes
"""
from util import ValidationError, DEFAULT_ENCODING
-from widgets import TextInput, CheckboxInput
+from widgets import TextInput, CheckboxInput, Select, SelectMultiple
import datetime
import re
import time
@@ -12,12 +12,19 @@ __all__ = (
'Field', 'CharField', 'IntegerField',
'DEFAULT_DATE_INPUT_FORMATS', 'DateField',
'DEFAULT_DATETIME_INPUT_FORMATS', 'DateTimeField',
- 'RegexField', 'EmailField', 'BooleanField',
+ 'RegexField', 'EmailField', 'URLField', 'BooleanField',
+ 'ChoiceField', 'MultipleChoiceField',
+ 'ComboField',
)
# These values, if given to to_python(), will trigger the self.required check.
EMPTY_VALUES = (None, '')
+try:
+ set # Only available in Python 2.4+
+except NameError:
+ from sets import Set as set # Python 2.3 fallback
+
class Field(object):
widget = TextInput # Default widget to use when rendering this type of Field.
@@ -28,9 +35,9 @@ class Field(object):
widget = widget()
self.widget = widget
- def to_python(self, value):
+ def clean(self, value):
"""
- Validates the given value and returns its "normalized" value as an
+ Validates the given value and returns its "cleaned" value as an
appropriate Python object.
Raises ValidationError for any errors.
@@ -44,9 +51,9 @@ class CharField(Field):
Field.__init__(self, required, widget)
self.max_length, self.min_length = max_length, min_length
- def to_python(self, value):
+ def clean(self, value):
"Validates max_length and min_length. Returns a Unicode object."
- Field.to_python(self, value)
+ Field.clean(self, value)
if value in EMPTY_VALUES: value = u''
if not isinstance(value, basestring):
value = unicode(str(value), DEFAULT_ENCODING)
@@ -59,12 +66,12 @@ class CharField(Field):
return value
class IntegerField(Field):
- def to_python(self, value):
+ def clean(self, value):
"""
Validates that int() can be called on the input. Returns the result
of int().
"""
- super(IntegerField, self).to_python(value)
+ super(IntegerField, self).clean(value)
try:
return int(value)
except (ValueError, TypeError):
@@ -83,12 +90,12 @@ class DateField(Field):
Field.__init__(self, required, widget)
self.input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
- def to_python(self, value):
+ def clean(self, value):
"""
Validates that the input can be converted to a date. Returns a Python
datetime.date object.
"""
- Field.to_python(self, value)
+ Field.clean(self, value)
if value in EMPTY_VALUES:
return None
if isinstance(value, datetime.datetime):
@@ -119,12 +126,12 @@ class DateTimeField(Field):
Field.__init__(self, required, widget)
self.input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
- def to_python(self, value):
+ def clean(self, value):
"""
Validates that the input can be converted to a datetime. Returns a
Python datetime.datetime object.
"""
- Field.to_python(self, value)
+ Field.clean(self, value)
if value in EMPTY_VALUES:
return None
if isinstance(value, datetime.datetime):
@@ -151,12 +158,12 @@ class RegexField(Field):
self.regex = regex
self.error_message = error_message or u'Enter a valid value.'
- def to_python(self, value):
+ def clean(self, value):
"""
Validates that the input matches the regular expression. Returns a
Unicode object.
"""
- Field.to_python(self, value)
+ Field.clean(self, value)
if value in EMPTY_VALUES: value = u''
if not isinstance(value, basestring):
value = unicode(str(value), DEFAULT_ENCODING)
@@ -175,10 +182,96 @@ class EmailField(RegexField):
def __init__(self, required=True, widget=None):
RegexField.__init__(self, email_re, u'Enter a valid e-mail address.', required, widget)
+url_re = re.compile(
+ r'^https?://' # http:// or https://
+ r'(?:[A-Z0-9-]+\.)+[A-Z]{2,6}' # domain
+ r'(?::\d+)?' # optional port
+ r'(?:/?|/\S+)$', re.IGNORECASE)
+
+class URLField(RegexField):
+ def __init__(self, required=True, verify_exists=False, widget=None):
+ RegexField.__init__(self, url_re, u'Enter a valid URL.', required, widget)
+ self.verify_exists = verify_exists
+
+ def clean(self, value):
+ value = RegexField.clean(self, value)
+ if self.verify_exists:
+ import urllib2
+ try:
+ u = urllib2.urlopen(value)
+ except ValueError:
+ raise ValidationError(u'Enter a valid URL.')
+ except: # urllib2.URLError, httplib.InvalidURL, etc.
+ raise ValidationError(u'This URL appears to be a broken link.')
+ return value
+
class BooleanField(Field):
widget = CheckboxInput
- def to_python(self, value):
+ def clean(self, value):
"Returns a Python boolean object."
- Field.to_python(self, value)
+ Field.clean(self, value)
return bool(value)
+
+class ChoiceField(Field):
+ def __init__(self, choices=(), required=True, widget=Select):
+ if isinstance(widget, type):
+ widget = widget(choices=choices)
+ Field.__init__(self, required, widget)
+ self.choices = choices
+
+ def clean(self, value):
+ """
+ Validates that the input is in self.choices.
+ """
+ value = Field.clean(self, value)
+ if value in EMPTY_VALUES: value = u''
+ if not isinstance(value, basestring):
+ value = unicode(str(value), DEFAULT_ENCODING)
+ elif not isinstance(value, unicode):
+ value = unicode(value, DEFAULT_ENCODING)
+ valid_values = set([str(k) for k, v in self.choices])
+ if value not in valid_values:
+ raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % value)
+ return value
+
+class MultipleChoiceField(ChoiceField):
+ def __init__(self, choices=(), required=True, widget=SelectMultiple):
+ ChoiceField.__init__(self, choices, required, widget)
+
+ def clean(self, value):
+ """
+ Validates that the input is a list or tuple.
+ """
+ if not isinstance(value, (list, tuple)):
+ raise ValidationError(u'Enter a list of values.')
+ if self.required and not value:
+ raise ValidationError(u'This field is required.')
+ new_value = []
+ for val in value:
+ if not isinstance(val, basestring):
+ value = unicode(str(val), DEFAULT_ENCODING)
+ elif not isinstance(val, unicode):
+ value = unicode(val, DEFAULT_ENCODING)
+ new_value.append(value)
+ # Validate that each value in the value list is in self.choices.
+ valid_values = set([k for k, v in self.choices])
+ for val in new_value:
+ if val not in valid_values:
+ raise ValidationError(u'Select a valid choice. %s is not one of the available choices.' % val)
+ return new_value
+
+class ComboField(Field):
+ def __init__(self, fields=(), required=True, widget=None):
+ Field.__init__(self, required, widget)
+ self.fields = fields
+
+ def clean(self, value):
+ """
+ Validates the given value against all of self.fields, which is a
+ list of Field instances.
+ """
+ Field.clean(self, value)
+ for field in self.fields:
+ value = field.clean(value)
+ return value