2006-10-29 04:34:37 +08:00
"""
Field classes
"""
2007-05-17 05:20:35 +08:00
import datetime
import re
import time
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
from django . utils . translation import ugettext
2007-08-06 21:58:56 +08:00
from django . utils . encoding import StrAndUnicode , smart_unicode
2007-05-17 05:20:35 +08:00
2007-04-04 14:34:19 +08:00
from util import ErrorList , ValidationError
2007-08-06 21:58:56 +08:00
from widgets import TextInput , PasswordInput , HiddenInput , MultipleHiddenInput , FileInput , CheckboxInput , Select , NullBooleanSelect , SelectMultiple
2006-10-29 04:34:37 +08:00
2007-07-13 17:09:59 +08:00
try :
from decimal import Decimal , DecimalException
except ImportError :
from django . utils . _decimal import Decimal , DecimalException
2006-10-29 04:34:37 +08:00
__all__ = (
' Field ' , ' CharField ' , ' IntegerField ' ,
' DEFAULT_DATE_INPUT_FORMATS ' , ' DateField ' ,
2006-12-15 04:35:32 +08:00
' DEFAULT_TIME_INPUT_FORMATS ' , ' TimeField ' ,
2006-10-29 04:34:37 +08:00
' DEFAULT_DATETIME_INPUT_FORMATS ' , ' DateTimeField ' ,
2007-08-06 21:58:56 +08:00
' RegexField ' , ' EmailField ' , ' FileField ' , ' ImageField ' , ' URLField ' , ' BooleanField ' ,
2007-01-24 13:23:19 +08:00
' ChoiceField ' , ' NullBooleanField ' , ' MultipleChoiceField ' ,
2007-05-21 09:29:58 +08:00
' ComboField ' , ' MultiValueField ' , ' FloatField ' , ' DecimalField ' ,
2007-01-24 04:23:07 +08:00
' SplitDateTimeField ' ,
2006-10-29 04:34:37 +08:00
)
# These values, if given to to_python(), will trigger the self.required check.
EMPTY_VALUES = ( None , ' ' )
2006-11-02 11:16:12 +08:00
try :
2007-06-23 11:18:22 +08:00
set
2006-11-02 11:16:12 +08:00
except NameError :
2007-06-23 11:18:22 +08:00
from sets import Set as set # Python 2.3 fallback
2006-11-02 11:16:12 +08:00
2007-05-21 09:29:58 +08:00
try :
from decimal import Decimal
except ImportError :
from django . utils . _decimal import Decimal # Python 2.3 fallback
2006-10-29 04:34:37 +08:00
class Field ( object ) :
widget = TextInput # Default widget to use when rendering this type of Field.
2007-01-09 13:12:25 +08:00
hidden_widget = HiddenInput # Default widget to use when rendering this as "hidden".
2006-10-29 04:34:37 +08:00
2006-11-24 01:40:33 +08:00
# Tracks each time a Field instance is created. Used to retain order.
creation_counter = 0
2007-01-29 06:10:04 +08:00
def __init__ ( self , required = True , widget = None , label = None , initial = None , help_text = None ) :
2006-12-28 08:01:52 +08:00
# required -- Boolean that specifies whether the field is required.
# True by default.
2007-04-01 13:05:59 +08:00
# widget -- A Widget class, or instance of a Widget class, that should
# be used for this Field when displaying it. Each Field has a
# default Widget that it'll use if you don't specify this. In
# most cases, the default widget is TextInput.
# label -- A verbose name for this field, for use in displaying this
# field in a form. By default, Django will use a "pretty"
# version of the form field name, if the Field is part of a
# Form.
# initial -- A value to use in this Field's initial display. This value
# is *not* used as a fallback if data isn't given.
2007-01-29 06:10:04 +08:00
# help_text -- An optional string to use as "help text" for this Field.
2006-12-18 03:04:03 +08:00
if label is not None :
label = smart_unicode ( label )
2006-12-28 08:01:52 +08:00
self . required , self . label , self . initial = required , label , initial
2007-02-20 07:43:14 +08:00
self . help_text = smart_unicode ( help_text or ' ' )
2006-10-29 04:34:37 +08:00
widget = widget or self . widget
if isinstance ( widget , type ) :
widget = widget ( )
2006-12-09 02:54:53 +08:00
# Hook into self.widget_attrs() for any Field-specific HTML attributes.
extra_attrs = self . widget_attrs ( widget )
if extra_attrs :
widget . attrs . update ( extra_attrs )
2006-10-29 04:34:37 +08:00
self . widget = widget
2006-11-24 01:40:33 +08:00
# Increase the creation counter, and save our local copy.
self . creation_counter = Field . creation_counter
Field . creation_counter + = 1
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-10-29 04:34:37 +08:00
"""
2006-11-05 04:49:59 +08:00
Validates the given value and returns its " cleaned " value as an
2006-10-29 04:34:37 +08:00
appropriate Python object .
Raises ValidationError for any errors .
"""
if self . required and value in EMPTY_VALUES :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' This field is required. ' ) )
2006-10-29 04:34:37 +08:00
return value
2006-12-09 02:54:53 +08:00
def widget_attrs ( self , widget ) :
"""
Given a Widget instance ( * not * a Widget class ) , returns a dictionary of
any HTML attributes that should be added to the Widget , based on this
Field .
"""
return { }
2006-10-29 04:34:37 +08:00
class CharField ( Field ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , max_length = None , min_length = None , * args , * * kwargs ) :
2006-10-29 04:34:37 +08:00
self . max_length , self . min_length = max_length , min_length
2007-01-29 06:10:04 +08:00
super ( CharField , self ) . __init__ ( * args , * * kwargs )
2006-10-29 04:34:37 +08:00
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-10-29 04:34:37 +08:00
" Validates max_length and min_length. Returns a Unicode object. "
2007-01-21 01:25:42 +08:00
super ( CharField , self ) . clean ( value )
2006-12-16 07:07:41 +08:00
if value in EMPTY_VALUES :
2007-01-21 01:31:45 +08:00
return u ' '
2006-11-16 14:45:29 +08:00
value = smart_unicode ( value )
2007-07-13 22:13:35 +08:00
value_length = len ( value )
if self . max_length is not None and value_length > self . max_length :
2007-07-14 21:39:41 +08:00
raise ValidationError ( ugettext ( u ' Ensure this value has at most %(max)d characters (it has %(length)d ). ' ) % { ' max ' : self . max_length , ' length ' : value_length } )
2007-07-13 22:13:35 +08:00
if self . min_length is not None and value_length < self . min_length :
2007-07-14 21:39:41 +08:00
raise ValidationError ( ugettext ( u ' Ensure this value has at least %(min)d characters (it has %(length)d ). ' ) % { ' min ' : self . min_length , ' length ' : value_length } )
2006-10-29 04:34:37 +08:00
return value
2006-12-09 02:54:53 +08:00
def widget_attrs ( self , widget ) :
if self . max_length is not None and isinstance ( widget , ( TextInput , PasswordInput ) ) :
2007-08-05 13:14:46 +08:00
# The HTML attribute is maxlength, not max_length.
2006-12-09 02:54:53 +08:00
return { ' maxlength ' : str ( self . max_length ) }
2006-10-29 04:34:37 +08:00
class IntegerField ( Field ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , max_value = None , min_value = None , * args , * * kwargs ) :
2006-12-16 07:18:47 +08:00
self . max_value , self . min_value = max_value , min_value
2007-01-29 06:10:04 +08:00
super ( IntegerField , self ) . __init__ ( * args , * * kwargs )
2006-12-16 07:18:47 +08:00
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-10-29 04:34:37 +08:00
"""
Validates that int ( ) can be called on the input . Returns the result
2007-01-13 13:08:07 +08:00
of int ( ) . Returns None for empty values .
2006-10-29 04:34:37 +08:00
"""
2006-11-05 04:49:59 +08:00
super ( IntegerField , self ) . clean ( value )
2007-01-21 01:31:45 +08:00
if value in EMPTY_VALUES :
2007-01-13 13:08:07 +08:00
return None
2006-10-29 04:34:37 +08:00
try :
2006-12-16 07:18:47 +08:00
value = int ( value )
2006-10-29 04:34:37 +08:00
except ( ValueError , TypeError ) :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a whole number. ' ) )
2006-12-16 07:18:47 +08:00
if self . max_value is not None and value > self . max_value :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Ensure this value is less than or equal to %s . ' ) % self . max_value )
2006-12-16 07:18:47 +08:00
if self . min_value is not None and value < self . min_value :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Ensure this value is greater than or equal to %s . ' ) % self . min_value )
2006-12-16 07:18:47 +08:00
return value
2006-10-29 04:34:37 +08:00
2007-05-21 09:29:58 +08:00
class FloatField ( Field ) :
def __init__ ( self , max_value = None , min_value = None , * args , * * kwargs ) :
self . max_value , self . min_value = max_value , min_value
Field . __init__ ( self , * args , * * kwargs )
def clean ( self , value ) :
"""
Validates that float ( ) can be called on the input . Returns a float .
Returns None for empty values .
"""
super ( FloatField , self ) . clean ( value )
if not self . required and value in EMPTY_VALUES :
return None
try :
value = float ( value )
except ( ValueError , TypeError ) :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( ' Enter a number. ' ) )
2007-05-21 09:29:58 +08:00
if self . max_value is not None and value > self . max_value :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( ' Ensure this value is less than or equal to %s . ' ) % self . max_value )
2007-05-21 09:29:58 +08:00
if self . min_value is not None and value < self . min_value :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( ' Ensure this value is greater than or equal to %s . ' ) % self . min_value )
2007-05-21 09:29:58 +08:00
return value
class DecimalField ( Field ) :
def __init__ ( self , max_value = None , min_value = None , max_digits = None , decimal_places = None , * args , * * kwargs ) :
self . max_value , self . min_value = max_value , min_value
self . max_digits , self . decimal_places = max_digits , decimal_places
Field . __init__ ( self , * args , * * kwargs )
def clean ( self , value ) :
"""
Validates that the input is a decimal number . Returns a Decimal
instance . Returns None for empty values . Ensures that there are no more
than max_digits in the number , and no more than decimal_places digits
after the decimal point .
"""
super ( DecimalField , self ) . clean ( value )
if not self . required and value in EMPTY_VALUES :
return None
value = value . strip ( )
2007-07-13 17:09:59 +08:00
try :
2007-05-21 09:29:58 +08:00
value = Decimal ( value )
2007-07-13 17:09:59 +08:00
except DecimalException :
raise ValidationError ( ugettext ( ' Enter a number. ' ) )
pieces = str ( value ) . split ( ' . ' )
decimals = ( len ( pieces ) == 2 ) and len ( pieces [ 1 ] ) or 0
digits = len ( pieces [ 0 ] )
2007-05-21 09:29:58 +08:00
if self . max_value is not None and value > self . max_value :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( ' Ensure this value is less than or equal to %s . ' ) % self . max_value )
2007-05-21 09:29:58 +08:00
if self . min_value is not None and value < self . min_value :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( ' Ensure this value is greater than or equal to %s . ' ) % self . min_value )
2007-05-21 09:29:58 +08:00
if self . max_digits is not None and ( digits + decimals ) > self . max_digits :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( ' Ensure that there are no more than %s digits in total. ' ) % self . max_digits )
2007-05-21 09:29:58 +08:00
if self . decimal_places is not None and decimals > self . decimal_places :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( ' Ensure that there are no more than %s decimal places. ' ) % self . decimal_places )
2007-05-21 09:29:58 +08:00
if self . max_digits is not None and self . decimal_places is not None and digits > ( self . max_digits - self . decimal_places ) :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( ' Ensure that there are no more than %s digits before the decimal point. ' ) % ( self . max_digits - self . decimal_places ) )
2007-05-21 09:29:58 +08:00
return value
2006-10-29 04:34:37 +08:00
DEFAULT_DATE_INPUT_FORMATS = (
' % Y- % m- %d ' , ' % m/ %d / % Y ' , ' % m/ %d / % y ' , # '2006-10-25', '10/25/2006', '10/25/06'
' % b %d % Y ' , ' % b %d , % Y ' , # 'Oct 25 2006', 'Oct 25, 2006'
' %d % b % Y ' , ' %d % b, % Y ' , # '25 Oct 2006', '25 Oct, 2006'
' % B %d % Y ' , ' % B %d , % Y ' , # 'October 25 2006', 'October 25, 2006'
' %d % B % Y ' , ' %d % B, % Y ' , # '25 October 2006', '25 October, 2006'
)
class DateField ( Field ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , input_formats = None , * args , * * kwargs ) :
super ( DateField , self ) . __init__ ( * args , * * kwargs )
2006-10-29 04:34:37 +08:00
self . input_formats = input_formats or DEFAULT_DATE_INPUT_FORMATS
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-10-29 04:34:37 +08:00
"""
Validates that the input can be converted to a date . Returns a Python
datetime . date object .
"""
2007-01-21 01:25:42 +08:00
super ( DateField , self ) . clean ( value )
2006-10-29 04:34:37 +08:00
if value in EMPTY_VALUES :
return None
if isinstance ( value , datetime . datetime ) :
return value . date ( )
if isinstance ( value , datetime . date ) :
return value
for format in self . input_formats :
try :
return datetime . date ( * time . strptime ( value , format ) [ : 3 ] )
except ValueError :
continue
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a valid date. ' ) )
2006-10-29 04:34:37 +08:00
2006-12-15 04:35:32 +08:00
DEFAULT_TIME_INPUT_FORMATS = (
' % H: % M: % S ' , # '14:30:59'
' % H: % M ' , # '14:30'
)
class TimeField ( Field ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , input_formats = None , * args , * * kwargs ) :
super ( TimeField , self ) . __init__ ( * args , * * kwargs )
2006-12-15 04:35:32 +08:00
self . input_formats = input_formats or DEFAULT_TIME_INPUT_FORMATS
def clean ( self , value ) :
"""
Validates that the input can be converted to a time . Returns a Python
datetime . time object .
"""
2007-01-21 01:25:42 +08:00
super ( TimeField , self ) . clean ( value )
2006-12-15 04:35:32 +08:00
if value in EMPTY_VALUES :
return None
if isinstance ( value , datetime . time ) :
return value
for format in self . input_formats :
try :
return datetime . time ( * time . strptime ( value , format ) [ 3 : 6 ] )
except ValueError :
continue
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a valid time. ' ) )
2006-12-15 04:35:32 +08:00
2006-10-29 04:34:37 +08:00
DEFAULT_DATETIME_INPUT_FORMATS = (
' % Y- % m- %d % H: % M: % S ' , # '2006-10-25 14:30:59'
' % Y- % m- %d % H: % M ' , # '2006-10-25 14:30'
' % Y- % m- %d ' , # '2006-10-25'
' % m/ %d / % Y % H: % M: % S ' , # '10/25/2006 14:30:59'
' % m/ %d / % Y % H: % M ' , # '10/25/2006 14:30'
' % m/ %d / % Y ' , # '10/25/2006'
' % m/ %d / % y % H: % M: % S ' , # '10/25/06 14:30:59'
' % m/ %d / % y % H: % M ' , # '10/25/06 14:30'
' % m/ %d / % y ' , # '10/25/06'
)
class DateTimeField ( Field ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , input_formats = None , * args , * * kwargs ) :
super ( DateTimeField , self ) . __init__ ( * args , * * kwargs )
2006-10-29 04:34:37 +08:00
self . input_formats = input_formats or DEFAULT_DATETIME_INPUT_FORMATS
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-10-29 04:34:37 +08:00
"""
Validates that the input can be converted to a datetime . Returns a
Python datetime . datetime object .
"""
2007-01-21 01:25:42 +08:00
super ( DateTimeField , self ) . clean ( value )
2006-10-29 04:34:37 +08:00
if value in EMPTY_VALUES :
return None
if isinstance ( value , datetime . datetime ) :
return value
if isinstance ( value , datetime . date ) :
return datetime . datetime ( value . year , value . month , value . day )
for format in self . input_formats :
try :
return datetime . datetime ( * time . strptime ( value , format ) [ : 6 ] )
except ValueError :
continue
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a valid date/time. ' ) )
2006-10-29 04:34:37 +08:00
2007-07-13 20:03:20 +08:00
class RegexField ( CharField ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , regex , max_length = None , min_length = None , error_message = None , * args , * * kwargs ) :
2006-10-29 04:34:37 +08:00
"""
regex can be either a string or a compiled regular expression object .
error_message is an optional error message to use , if
' Enter a valid value ' is too generic for you .
"""
2007-07-13 20:03:20 +08:00
super ( RegexField , self ) . __init__ ( max_length , min_length , * args , * * kwargs )
2006-10-29 04:34:37 +08:00
if isinstance ( regex , basestring ) :
regex = re . compile ( regex )
self . regex = regex
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
self . error_message = error_message or ugettext ( u ' Enter a valid value. ' )
2006-10-29 04:34:37 +08:00
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-10-29 04:34:37 +08:00
"""
Validates that the input matches the regular expression . Returns a
Unicode object .
"""
2007-07-13 20:03:20 +08:00
value = super ( RegexField , self ) . clean ( value )
2007-01-21 01:31:45 +08:00
if value == u ' ' :
2006-11-27 08:49:26 +08:00
return value
if not self . regex . search ( value ) :
2006-10-29 04:34:37 +08:00
raise ValidationError ( self . error_message )
return value
email_re = re . compile (
r " (^[-!#$ % & ' *+/=?^_` {} |~0-9A-Z]+( \ .[-!#$ % & ' *+/=?^_` {} |~0-9A-Z]+)* " # dot-atom
r ' |^ " ([ \ 001- \ 010 \ 013 \ 014 \ 016- \ 037!#- \ [ \ ]- \ 177]| \\ [ \ 001-011 \ 013 \ 014 \ 016- \ 177])* " ' # quoted-string
r ' )@(?:[A-Z0-9-]+ \ .)+[A-Z] { 2,6}$ ' , re . IGNORECASE ) # domain
class EmailField ( RegexField ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , max_length = None , min_length = None , * args , * * kwargs ) :
RegexField . __init__ ( self , email_re , max_length , min_length ,
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
ugettext ( u ' Enter a valid e-mail address. ' ) , * args , * * kwargs )
2006-10-29 04:34:37 +08:00
2006-11-02 07:52:43 +08:00
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 )
2006-11-07 10:32:33 +08:00
try :
from django . conf import settings
URL_VALIDATOR_USER_AGENT = settings . URL_VALIDATOR_USER_AGENT
except ImportError :
# It's OK if Django settings aren't configured.
URL_VALIDATOR_USER_AGENT = ' Django (http://www.djangoproject.com/) '
2007-08-06 21:58:56 +08:00
class UploadedFile ( StrAndUnicode ) :
" A wrapper for files uploaded in a FileField "
def __init__ ( self , filename , content ) :
self . filename = filename
self . content = content
def __unicode__ ( self ) :
"""
The unicode representation is the filename , so that the pre - database - insertion
logic can use UploadedFile objects
"""
return self . filename
class FileField ( Field ) :
widget = FileInput
def __init__ ( self , * args , * * kwargs ) :
super ( FileField , self ) . __init__ ( * args , * * kwargs )
def clean ( self , data ) :
super ( FileField , self ) . clean ( data )
if not self . required and data in EMPTY_VALUES :
return None
try :
f = UploadedFile ( data [ ' filename ' ] , data [ ' content ' ] )
except TypeError :
raise ValidationError ( ugettext ( u " No file was submitted. Check the encoding type on the form. " ) )
except KeyError :
raise ValidationError ( ugettext ( u " No file was submitted. " ) )
if not f . content :
raise ValidationError ( ugettext ( u " The submitted file is empty. " ) )
return f
class ImageField ( FileField ) :
def clean ( self , data ) :
"""
Checks that the file - upload field data contains a valid image ( GIF , JPG ,
PNG , possibly others - - whatever the Python Imaging Library supports ) .
"""
f = super ( ImageField , self ) . clean ( data )
if f is None :
return None
from PIL import Image
from cStringIO import StringIO
try :
Image . open ( StringIO ( f . content ) )
except IOError : # Python Imaging Library doesn't recognize it as an image
raise ValidationError ( ugettext ( u " Upload a valid image. The file you uploaded was either not an image or a corrupted image. " ) )
return f
2006-11-02 07:52:43 +08:00
class URLField ( RegexField ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , max_length = None , min_length = None , verify_exists = False ,
validator_user_agent = URL_VALIDATOR_USER_AGENT , * args , * * kwargs ) :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
super ( URLField , self ) . __init__ ( url_re , max_length , min_length , ugettext ( u ' Enter a valid URL. ' ) , * args , * * kwargs )
2006-11-02 07:52:43 +08:00
self . verify_exists = verify_exists
2006-11-07 10:32:33 +08:00
self . user_agent = validator_user_agent
2006-11-02 07:52:43 +08:00
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2007-01-21 01:25:42 +08:00
value = super ( URLField , self ) . clean ( value )
2007-01-21 01:31:45 +08:00
if value == u ' ' :
2007-01-13 13:19:15 +08:00
return value
2006-11-02 07:52:43 +08:00
if self . verify_exists :
import urllib2
2006-11-07 10:32:33 +08:00
from django . conf import settings
headers = {
" Accept " : " text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 " ,
" Accept-Language " : " en-us,en;q=0.5 " ,
" Accept-Charset " : " ISO-8859-1,utf-8;q=0.7,*;q=0.7 " ,
" Connection " : " close " ,
" User-Agent " : self . user_agent ,
}
2006-11-02 07:52:43 +08:00
try :
2006-11-10 11:39:00 +08:00
req = urllib2 . Request ( value , None , headers )
2006-11-07 10:32:33 +08:00
u = urllib2 . urlopen ( req )
2006-11-02 07:52:43 +08:00
except ValueError :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a valid URL. ' ) )
2006-11-02 07:52:43 +08:00
except : # urllib2.URLError, httplib.InvalidURL, etc.
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' This URL appears to be a broken link. ' ) )
2006-11-02 07:52:43 +08:00
return value
2006-10-29 04:34:37 +08:00
class BooleanField ( Field ) :
widget = CheckboxInput
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-10-29 04:34:37 +08:00
" Returns a Python boolean object. "
2007-01-21 01:25:42 +08:00
super ( BooleanField , self ) . clean ( value )
2006-10-29 04:34:37 +08:00
return bool ( value )
2006-11-02 11:16:12 +08:00
2007-01-24 13:23:19 +08:00
class NullBooleanField ( BooleanField ) :
"""
A field whose valid values are None , True and False . Invalid values are
cleaned to None .
"""
widget = NullBooleanSelect
def clean ( self , value ) :
return { True : True , False : False } . get ( value , None )
2006-11-02 11:16:12 +08:00
class ChoiceField ( Field ) :
2007-04-21 13:43:32 +08:00
widget = Select
def __init__ ( self , choices = ( ) , required = True , widget = None , label = None , initial = None , help_text = None ) :
2007-01-29 06:10:04 +08:00
super ( ChoiceField , self ) . __init__ ( required , widget , label , initial , help_text )
2006-11-02 11:16:12 +08:00
self . choices = choices
2007-01-21 09:29:01 +08:00
def _get_choices ( self ) :
return self . _choices
def _set_choices ( self , value ) :
# Setting choices also sets the choices on the widget.
2007-02-20 11:05:09 +08:00
# choices can be any iterable, but we call list() on it because
# it will be consumed more than once.
self . _choices = self . widget . choices = list ( value )
2007-01-21 09:29:01 +08:00
choices = property ( _get_choices , _set_choices )
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-11-02 11:16:12 +08:00
"""
Validates that the input is in self . choices .
"""
2007-01-21 01:25:42 +08:00
value = super ( ChoiceField , self ) . clean ( value )
2007-01-21 01:31:45 +08:00
if value in EMPTY_VALUES :
value = u ' '
2006-11-16 14:45:29 +08:00
value = smart_unicode ( value )
2007-01-21 01:31:45 +08:00
if value == u ' ' :
2006-11-27 08:49:26 +08:00
return value
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
valid_values = set ( [ smart_unicode ( k ) for k , v in self . choices ] )
2006-11-02 11:16:12 +08:00
if value not in valid_values :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Select a valid choice. That choice is not one of the available choices. ' ) )
2006-11-02 11:16:12 +08:00
return value
class MultipleChoiceField ( ChoiceField ) :
2007-01-09 13:12:25 +08:00
hidden_widget = MultipleHiddenInput
2007-04-21 13:43:32 +08:00
widget = SelectMultiple
2006-11-02 11:16:12 +08:00
2006-11-05 04:49:59 +08:00
def clean ( self , value ) :
2006-11-02 11:16:12 +08:00
"""
Validates that the input is a list or tuple .
"""
if self . required and not value :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' This field is required. ' ) )
2006-11-27 08:49:26 +08:00
elif not self . required and not value :
return [ ]
if not isinstance ( value , ( list , tuple ) ) :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a list of values. ' ) )
2007-07-12 21:37:59 +08:00
new_value = [ smart_unicode ( val ) for val in value ]
2006-11-02 11:16:12 +08:00
# Validate that each value in the value list is in self.choices.
2006-12-08 13:54:14 +08:00
valid_values = set ( [ smart_unicode ( k ) for k , v in self . choices ] )
2006-11-02 11:16:12 +08:00
for val in new_value :
if val not in valid_values :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Select a valid choice. %s is not one of the available choices. ' ) % val )
2006-11-02 11:16:12 +08:00
return new_value
2006-11-05 04:49:59 +08:00
class ComboField ( Field ) :
2007-01-24 04:23:07 +08:00
"""
A Field whose clean ( ) method calls multiple Field clean ( ) methods .
"""
2007-01-29 06:10:04 +08:00
def __init__ ( self , fields = ( ) , * args , * * kwargs ) :
super ( ComboField , self ) . __init__ ( * args , * * kwargs )
2006-11-27 08:49:26 +08:00
# Set 'required' to False on the individual fields, because the
# required validation will be handled by ComboField, not by those
# individual fields.
for f in fields :
f . required = False
2006-11-05 04:49:59 +08:00
self . fields = fields
def clean ( self , value ) :
"""
Validates the given value against all of self . fields , which is a
list of Field instances .
"""
2007-01-21 01:25:42 +08:00
super ( ComboField , self ) . clean ( value )
2006-11-05 04:49:59 +08:00
for field in self . fields :
value = field . clean ( value )
return value
2007-01-24 04:23:07 +08:00
class MultiValueField ( Field ) :
"""
2007-07-01 12:24:20 +08:00
A Field that aggregates the logic of multiple Fields .
Its clean ( ) method takes a " decompressed " list of values , which are then
cleaned into a single value according to self . fields . Each value in
2007-01-24 04:23:07 +08:00
this list is cleaned by the corresponding field - - the first value is
cleaned by the first field , the second value is cleaned by the second
field , etc . Once all fields are cleaned , the list of clean values is
" compressed " into a single value .
2007-07-01 12:24:20 +08:00
Subclasses should not have to implement clean ( ) . Instead , they must
implement compress ( ) , which takes a list of valid values and returns a
" compressed " version of those values - - a single value .
2007-01-24 04:23:07 +08:00
You ' ll probably want to use this with MultiWidget.
"""
2007-01-29 06:10:04 +08:00
def __init__ ( self , fields = ( ) , * args , * * kwargs ) :
super ( MultiValueField , self ) . __init__ ( * args , * * kwargs )
2007-01-24 04:23:07 +08:00
# Set 'required' to False on the individual fields, because the
# required validation will be handled by MultiValueField, not by those
# individual fields.
for f in fields :
f . required = False
self . fields = fields
def clean ( self , value ) :
"""
Validates every value in the given list . A value is validated against
the corresponding Field in self . fields .
For example , if this MultiValueField was instantiated with
fields = ( DateField ( ) , TimeField ( ) ) , clean ( ) would call
DateField . clean ( value [ 0 ] ) and TimeField . clean ( value [ 1 ] ) .
"""
clean_data = [ ]
errors = ErrorList ( )
2007-06-23 11:32:59 +08:00
if not value or isinstance ( value , ( list , tuple ) ) :
if not value or not [ v for v in value if v not in EMPTY_VALUES ] :
if self . required :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' This field is required. ' ) )
2007-06-23 11:32:59 +08:00
else :
return self . compress ( [ ] )
else :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a list of values. ' ) )
2007-01-24 04:23:07 +08:00
for i , field in enumerate ( self . fields ) :
try :
field_value = value [ i ]
2007-04-26 20:46:04 +08:00
except IndexError :
2007-01-24 04:23:07 +08:00
field_value = None
if self . required and field_value in EMPTY_VALUES :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' This field is required. ' ) )
2007-01-24 04:23:07 +08:00
try :
clean_data . append ( field . clean ( field_value ) )
except ValidationError , e :
# Collect all validation errors in a single list, which we'll
# raise at the end of clean(), rather than raising a single
# exception for the first error we encounter.
errors . extend ( e . messages )
if errors :
raise ValidationError ( errors )
return self . compress ( clean_data )
def compress ( self , data_list ) :
"""
Returns a single value for the given list of values . The values can be
assumed to be valid .
For example , if this MultiValueField was instantiated with
fields = ( DateField ( ) , TimeField ( ) ) , this might return a datetime
object created by combining the date and time in data_list .
"""
raise NotImplementedError ( ' Subclasses must implement this method. ' )
class SplitDateTimeField ( MultiValueField ) :
2007-01-29 06:10:04 +08:00
def __init__ ( self , * args , * * kwargs ) :
2007-01-24 04:23:07 +08:00
fields = ( DateField ( ) , TimeField ( ) )
2007-01-29 06:10:04 +08:00
super ( SplitDateTimeField , self ) . __init__ ( fields , * args , * * kwargs )
2007-01-24 04:23:07 +08:00
def compress ( self , data_list ) :
if data_list :
2007-06-23 11:32:59 +08:00
# Raise a validation error if time or date is empty
# (possible if SplitDateTimeField has required=False).
if data_list [ 0 ] in EMPTY_VALUES :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a valid date. ' ) )
2007-06-23 11:32:59 +08:00
if data_list [ 1 ] in EMPTY_VALUES :
Merged Unicode branch into trunk (r4952:5608). This should be fully
backwards compatible for all practical purposes.
Fixed #2391, #2489, #2996, #3322, #3344, #3370, #3406, #3432, #3454, #3492, #3582, #3690, #3878, #3891, #3937, #4039, #4141, #4227, #4286, #4291, #4300, #4452, #4702
git-svn-id: http://code.djangoproject.com/svn/django/trunk@5609 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2007-07-04 20:11:04 +08:00
raise ValidationError ( ugettext ( u ' Enter a valid time. ' ) )
2007-01-24 04:23:07 +08:00
return datetime . datetime . combine ( * data_list )
return None