diff --git a/tests/regressiontests/forms/extra.py b/tests/regressiontests/forms/extra.py
new file mode 100644
index 0000000000..7f6175f649
--- /dev/null
+++ b/tests/regressiontests/forms/extra.py
@@ -0,0 +1,398 @@
+# -*- coding: utf-8 -*-
+tests = r"""
+>>> from django.newforms import *
+>>> import datetime
+>>> import time
+>>> import re
+>>> try:
+... from decimal import Decimal
+... except ImportError:
+... from django.utils._decimal import Decimal
+
+###############
+# Extra stuff #
+###############
+
+The newforms library comes with some extra, higher-level Field and Widget
+classes that demonstrate some of the library's abilities.
+
+# SelectDateWidget ############################################################
+
+>>> from django.newforms.extras import SelectDateWidget
+>>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'))
+>>> print w.render('mydate', '')
+
+January
+February
+March
+April
+May
+June
+July
+August
+September
+October
+November
+December
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+
+
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+
+>>> w.render('mydate', None) == w.render('mydate', '')
+True
+>>> print w.render('mydate', '2010-04-15')
+
+January
+February
+March
+April
+May
+June
+July
+August
+September
+October
+November
+December
+
+
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+
+
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+
+
+Using a SelectDateWidget in a form:
+
+>>> class GetDate(Form):
+... mydate = DateField(widget=SelectDateWidget)
+>>> a = GetDate({'mydate_month':'4', 'mydate_day':'1', 'mydate_year':'2008'})
+>>> print a.is_valid()
+True
+>>> print a.cleaned_data['mydate']
+2008-04-01
+
+As with any widget that implements get_value_from_datadict,
+we must be prepared to accept the input from the "as_hidden"
+rendering as well.
+
+>>> print a['mydate'].as_hidden()
+
+>>> b=GetDate({'mydate':'2008-4-1'})
+>>> print b.is_valid()
+True
+>>> print b.cleaned_data['mydate']
+2008-04-01
+
+
+# MultiWidget and MultiValueField #############################################
+# MultiWidgets are widgets composed of other widgets. They are usually
+# combined with MultiValueFields - a field that is composed of other fields.
+# MulitWidgets can themselved be composed of other MultiWidgets.
+# SplitDateTimeWidget is one example of a MultiWidget.
+
+>>> class ComplexMultiWidget(MultiWidget):
+... def __init__(self, attrs=None):
+... widgets = (
+... TextInput(),
+... SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
+... SplitDateTimeWidget(),
+... )
+... super(ComplexMultiWidget, self).__init__(widgets, attrs)
+...
+... def decompress(self, value):
+... if value:
+... data = value.split(',')
+... return [data[0], data[1], datetime.datetime(*time.strptime(data[2], "%Y-%m-%d %H:%M:%S")[0:6])]
+... return [None, None, None]
+... def format_output(self, rendered_widgets):
+... return u'\n'.join(rendered_widgets)
+>>> w = ComplexMultiWidget()
+>>> print w.render('name', 'some text,JP,2007-04-25 06:24:00')
+
+
+John
+Paul
+George
+Ringo
+
+
+
+>>> class ComplexField(MultiValueField):
+... def __init__(self, required=True, widget=None, label=None, initial=None):
+... fields = (
+... CharField(),
+... MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
+... SplitDateTimeField()
+... )
+... super(ComplexField, self).__init__(fields, required, widget, label, initial)
+...
+... def compress(self, data_list):
+... if data_list:
+... return '%s,%s,%s' % (data_list[0],''.join(data_list[1]),data_list[2])
+... return None
+
+>>> f = ComplexField(widget=w)
+>>> f.clean(['some text', ['J','P'], ['2007-04-25','6:24:00']])
+u'some text,JP,2007-04-25 06:24:00'
+>>> f.clean(['some text',['X'], ['2007-04-25','6:24:00']])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. X is not one of the available choices.']
+
+# If insufficient data is provided, None is substituted
+>>> f.clean(['some text',['JP']])
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> class ComplexFieldForm(Form):
+... field1 = ComplexField(widget=w)
+>>> f = ComplexFieldForm()
+>>> print f
+
Field1:
+
+John
+Paul
+George
+Ringo
+
+
+
+>>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'})
+>>> print f
+Field1:
+
+John
+Paul
+George
+Ringo
+
+
+
+>>> f.cleaned_data
+{'field1': u'some text,JP,2007-04-25 06:24:00'}
+
+
+# IPAddressField ##################################################################
+
+>>> f = IPAddressField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('127.0.0.1')
+u'127.0.0.1'
+>>> f.clean('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IPv4 address.']
+>>> f.clean('127.0.0.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IPv4 address.']
+>>> f.clean('1.2.3.4.5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IPv4 address.']
+>>> f.clean('256.125.1.5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IPv4 address.']
+
+>>> f = IPAddressField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+>>> f.clean('127.0.0.1')
+u'127.0.0.1'
+>>> f.clean('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IPv4 address.']
+>>> f.clean('127.0.0.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IPv4 address.']
+>>> f.clean('1.2.3.4.5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IPv4 address.']
+>>> f.clean('256.125.1.5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid IPv4 address.']
+
+#################################
+# Tests of underlying functions #
+#################################
+
+# smart_unicode tests
+>>> from django.utils.encoding import smart_unicode
+>>> class Test:
+... def __str__(self):
+... return 'ŠĐĆŽćžšđ'
+>>> class TestU:
+... def __str__(self):
+... return 'Foo'
+... def __unicode__(self):
+... return u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
+>>> smart_unicode(Test())
+u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
+>>> smart_unicode(TestU())
+u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
+>>> smart_unicode(1)
+u'1'
+>>> smart_unicode('foo')
+u'foo'
+
+
+####################################
+# Test accessing errors in clean() #
+####################################
+
+>>> class UserForm(Form):
+... username = CharField(max_length=10)
+... password = CharField(widget=PasswordInput)
+... def clean(self):
+... data = self.cleaned_data
+... if not self.errors:
+... data['username'] = data['username'].lower()
+... return data
+
+>>> f = UserForm({'username': 'SirRobin', 'password': 'blue'})
+>>> f.is_valid()
+True
+>>> f.cleaned_data['username']
+u'sirrobin'
+
+#######################################
+# Test overriding ErrorList in a form #
+#######################################
+
+>>> from django.newforms.util import ErrorList
+>>> class DivErrorList(ErrorList):
+... def __unicode__(self):
+... return self.as_divs()
+... def as_divs(self):
+... if not self: return u''
+... return u'%s
' % ''.join([u'%s
' % e for e in self])
+>>> class CommentForm(Form):
+... name = CharField(max_length=50, required=False)
+... email = EmailField()
+... comment = CharField()
+>>> data = dict(email='invalid')
+>>> f = CommentForm(data, auto_id=False, error_class=DivErrorList)
+>>> print f.as_p()
+Name:
+Enter a valid e-mail address.
+Email:
+
+Comment:
+
+#################################
+# Test multipart-encoded form #
+#################################
+
+>>> class FormWithoutFile(Form):
+... username = CharField()
+>>> class FormWithFile(Form):
+... username = CharField()
+... file = FileField()
+>>> class FormWithImage(Form):
+... image = ImageField()
+
+>>> FormWithoutFile().is_multipart()
+False
+>>> FormWithFile().is_multipart()
+True
+>>> FormWithImage().is_multipart()
+True
+
+"""
diff --git a/tests/regressiontests/forms/fields.py b/tests/regressiontests/forms/fields.py
new file mode 100644
index 0000000000..3b93d70338
--- /dev/null
+++ b/tests/regressiontests/forms/fields.py
@@ -0,0 +1,1162 @@
+# -*- coding: utf-8 -*-
+tests = r"""
+>>> from django.newforms import *
+>>> from django.newforms.widgets import RadioFieldRenderer
+>>> import datetime
+>>> import time
+>>> import re
+>>> try:
+... from decimal import Decimal
+... except ImportError:
+... from django.utils._decimal import Decimal
+
+
+##########
+# Fields #
+##########
+
+Each Field class does some sort of validation. Each Field has a clean() method,
+which either raises django.newforms.ValidationError or returns the "clean"
+data -- usually a Unicode object, but, in some rare cases, a list.
+
+Each Field's __init__() takes at least these parameters:
+ required -- Boolean that specifies whether the field is required.
+ True by default.
+ 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.
+
+Other than that, the Field subclasses have class-specific options for
+__init__(). For example, CharField has a max_length option.
+
+# CharField ###################################################################
+
+>>> f = CharField()
+>>> f.clean(1)
+u'1'
+>>> f.clean('hello')
+u'hello'
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean([1, 2, 3])
+u'[1, 2, 3]'
+
+>>> f = CharField(required=False)
+>>> f.clean(1)
+u'1'
+>>> f.clean('hello')
+u'hello'
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+>>> f.clean([1, 2, 3])
+u'[1, 2, 3]'
+
+CharField accepts an optional max_length parameter:
+>>> f = CharField(max_length=10, required=False)
+>>> f.clean('12345')
+u'12345'
+>>> f.clean('1234567890')
+u'1234567890'
+>>> f.clean('1234567890a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 10 characters (it has 11).']
+
+CharField accepts an optional min_length parameter:
+>>> f = CharField(min_length=10, required=False)
+>>> f.clean('')
+u''
+>>> f.clean('12345')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 10 characters (it has 5).']
+>>> f.clean('1234567890')
+u'1234567890'
+>>> f.clean('1234567890a')
+u'1234567890a'
+
+>>> f = CharField(min_length=10, required=True)
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('12345')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 10 characters (it has 5).']
+>>> f.clean('1234567890')
+u'1234567890'
+>>> f.clean('1234567890a')
+u'1234567890a'
+
+# IntegerField ################################################################
+
+>>> f = IntegerField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('1')
+1
+>>> isinstance(f.clean('1'), int)
+True
+>>> f.clean('23')
+23
+>>> f.clean('a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a whole number.']
+>>> f.clean(42)
+42
+>>> f.clean(3.14)
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a whole number.']
+>>> f.clean('1 ')
+1
+>>> f.clean(' 1')
+1
+>>> f.clean(' 1 ')
+1
+>>> f.clean('1a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a whole number.']
+
+>>> f = IntegerField(required=False)
+>>> f.clean('')
+>>> repr(f.clean(''))
+'None'
+>>> f.clean(None)
+>>> repr(f.clean(None))
+'None'
+>>> f.clean('1')
+1
+>>> isinstance(f.clean('1'), int)
+True
+>>> f.clean('23')
+23
+>>> f.clean('a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a whole number.']
+>>> f.clean('1 ')
+1
+>>> f.clean(' 1')
+1
+>>> f.clean(' 1 ')
+1
+>>> f.clean('1a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a whole number.']
+
+IntegerField accepts an optional max_value parameter:
+>>> f = IntegerField(max_value=10)
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(1)
+1
+>>> f.clean(10)
+10
+>>> f.clean(11)
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 10.']
+>>> f.clean('10')
+10
+>>> f.clean('11')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 10.']
+
+IntegerField accepts an optional min_value parameter:
+>>> f = IntegerField(min_value=10)
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(1)
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is greater than or equal to 10.']
+>>> f.clean(10)
+10
+>>> f.clean(11)
+11
+>>> f.clean('10')
+10
+>>> f.clean('11')
+11
+
+min_value and max_value can be used together:
+>>> f = IntegerField(min_value=10, max_value=20)
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(1)
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is greater than or equal to 10.']
+>>> f.clean(10)
+10
+>>> f.clean(11)
+11
+>>> f.clean('10')
+10
+>>> f.clean('11')
+11
+>>> f.clean(20)
+20
+>>> f.clean(21)
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 20.']
+
+# FloatField ##################################################################
+
+>>> f = FloatField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('1')
+1.0
+>>> isinstance(f.clean('1'), float)
+True
+>>> f.clean('23')
+23.0
+>>> f.clean('3.14')
+3.1400000000000001
+>>> f.clean(3.14)
+3.1400000000000001
+>>> f.clean(42)
+42.0
+>>> f.clean('a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+>>> f.clean('1.0 ')
+1.0
+>>> f.clean(' 1.0')
+1.0
+>>> f.clean(' 1.0 ')
+1.0
+>>> f.clean('1.0a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+
+>>> f = FloatField(required=False)
+>>> f.clean('')
+
+>>> f.clean(None)
+
+>>> f.clean('1')
+1.0
+
+FloatField accepts min_value and max_value just like IntegerField:
+>>> f = FloatField(max_value=1.5, min_value=0.5)
+
+>>> f.clean('1.6')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 1.5.']
+>>> f.clean('0.4')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
+>>> f.clean('1.5')
+1.5
+>>> f.clean('0.5')
+0.5
+
+# DecimalField ################################################################
+
+>>> f = DecimalField(max_digits=4, decimal_places=2)
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('1')
+Decimal("1")
+>>> isinstance(f.clean('1'), Decimal)
+True
+>>> f.clean('23')
+Decimal("23")
+>>> f.clean('3.14')
+Decimal("3.14")
+>>> f.clean(3.14)
+Decimal("3.14")
+>>> f.clean(Decimal('3.14'))
+Decimal("3.14")
+>>> f.clean('a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+>>> f.clean('1.0 ')
+Decimal("1.0")
+>>> f.clean(' 1.0')
+Decimal("1.0")
+>>> f.clean(' 1.0 ')
+Decimal("1.0")
+>>> f.clean('1.0a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+>>> f.clean('123.45')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 4 digits in total.']
+>>> f.clean('1.234')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 2 decimal places.']
+>>> f.clean('123.4')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 2 digits before the decimal point.']
+>>> f.clean('-12.34')
+Decimal("-12.34")
+>>> f.clean('-123.45')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 4 digits in total.']
+>>> f.clean('-.12')
+Decimal("-0.12")
+>>> f.clean('-00.12')
+Decimal("-0.12")
+>>> f.clean('-000.12')
+Decimal("-0.12")
+>>> f.clean('-000.123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 2 decimal places.']
+>>> f.clean('-000.1234')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure that there are no more than 4 digits in total.']
+>>> f.clean('--0.12')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a number.']
+
+>>> f = DecimalField(max_digits=4, decimal_places=2, required=False)
+>>> f.clean('')
+
+>>> f.clean(None)
+
+>>> f.clean('1')
+Decimal("1")
+
+DecimalField accepts min_value and max_value just like IntegerField:
+>>> f = DecimalField(max_digits=4, decimal_places=2, max_value=Decimal('1.5'), min_value=Decimal('0.5'))
+
+>>> f.clean('1.6')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is less than or equal to 1.5.']
+>>> f.clean('0.4')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
+>>> f.clean('1.5')
+Decimal("1.5")
+>>> f.clean('0.5')
+Decimal("0.5")
+>>> f.clean('.5')
+Decimal("0.5")
+>>> f.clean('00.50')
+Decimal("0.50")
+
+# DateField ###################################################################
+
+>>> import datetime
+>>> f = DateField()
+>>> f.clean(datetime.date(2006, 10, 25))
+datetime.date(2006, 10, 25)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
+datetime.date(2006, 10, 25)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
+datetime.date(2006, 10, 25)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
+datetime.date(2006, 10, 25)
+>>> f.clean('2006-10-25')
+datetime.date(2006, 10, 25)
+>>> f.clean('10/25/2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('10/25/06')
+datetime.date(2006, 10, 25)
+>>> f.clean('Oct 25 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('October 25 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('October 25, 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('25 October 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('25 October, 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('2006-4-31')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean('200a-10-25')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean('25/10/06')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = DateField(required=False)
+>>> f.clean(None)
+>>> repr(f.clean(None))
+'None'
+>>> f.clean('')
+>>> repr(f.clean(''))
+'None'
+
+DateField accepts an optional input_formats parameter:
+>>> f = DateField(input_formats=['%Y %m %d'])
+>>> f.clean(datetime.date(2006, 10, 25))
+datetime.date(2006, 10, 25)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
+datetime.date(2006, 10, 25)
+>>> f.clean('2006 10 25')
+datetime.date(2006, 10, 25)
+
+The input_formats parameter overrides all default input formats,
+so the default formats won't work unless you specify them:
+>>> f.clean('2006-10-25')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean('10/25/2006')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean('10/25/06')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+
+# TimeField ###################################################################
+
+>>> import datetime
+>>> f = TimeField()
+>>> f.clean(datetime.time(14, 25))
+datetime.time(14, 25)
+>>> f.clean(datetime.time(14, 25, 59))
+datetime.time(14, 25, 59)
+>>> f.clean('14:25')
+datetime.time(14, 25)
+>>> f.clean('14:25:59')
+datetime.time(14, 25, 59)
+>>> f.clean('hello')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid time.']
+>>> f.clean('1:24 p.m.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid time.']
+
+TimeField accepts an optional input_formats parameter:
+>>> f = TimeField(input_formats=['%I:%M %p'])
+>>> f.clean(datetime.time(14, 25))
+datetime.time(14, 25)
+>>> f.clean(datetime.time(14, 25, 59))
+datetime.time(14, 25, 59)
+>>> f.clean('4:25 AM')
+datetime.time(4, 25)
+>>> f.clean('4:25 PM')
+datetime.time(16, 25)
+
+The input_formats parameter overrides all default input formats,
+so the default formats won't work unless you specify them:
+>>> f.clean('14:30:45')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid time.']
+
+# DateTimeField ###############################################################
+
+>>> import datetime
+>>> f = DateTimeField()
+>>> f.clean(datetime.date(2006, 10, 25))
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
+datetime.datetime(2006, 10, 25, 14, 30, 59)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
+datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
+>>> f.clean('2006-10-25 14:30:45')
+datetime.datetime(2006, 10, 25, 14, 30, 45)
+>>> f.clean('2006-10-25 14:30:00')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('2006-10-25 14:30')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('2006-10-25')
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean('10/25/2006 14:30:45')
+datetime.datetime(2006, 10, 25, 14, 30, 45)
+>>> f.clean('10/25/2006 14:30:00')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('10/25/2006 14:30')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('10/25/2006')
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean('10/25/06 14:30:45')
+datetime.datetime(2006, 10, 25, 14, 30, 45)
+>>> f.clean('10/25/06 14:30:00')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('10/25/06 14:30')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('10/25/06')
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean('hello')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date/time.']
+>>> f.clean('2006-10-25 4:30 p.m.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date/time.']
+
+DateField accepts an optional input_formats parameter:
+>>> f = DateTimeField(input_formats=['%Y %m %d %I:%M %p'])
+>>> f.clean(datetime.date(2006, 10, 25))
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
+datetime.datetime(2006, 10, 25, 14, 30, 59)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
+datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
+>>> f.clean('2006 10 25 2:30 PM')
+datetime.datetime(2006, 10, 25, 14, 30)
+
+The input_formats parameter overrides all default input formats,
+so the default formats won't work unless you specify them:
+>>> f.clean('2006-10-25 14:30:45')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date/time.']
+
+>>> f = DateTimeField(required=False)
+>>> f.clean(None)
+>>> repr(f.clean(None))
+'None'
+>>> f.clean('')
+>>> repr(f.clean(''))
+'None'
+
+# RegexField ##################################################################
+
+>>> f = RegexField('^\d[A-F]\d$')
+>>> f.clean('2A2')
+u'2A2'
+>>> f.clean('3F3')
+u'3F3'
+>>> f.clean('3G3')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+>>> f.clean(' 2A2')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+>>> f.clean('2A2 ')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = RegexField('^\d[A-F]\d$', required=False)
+>>> f.clean('2A2')
+u'2A2'
+>>> f.clean('3F3')
+u'3F3'
+>>> f.clean('3G3')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+>>> f.clean('')
+u''
+
+Alternatively, RegexField can take a compiled regular expression:
+>>> f = RegexField(re.compile('^\d[A-F]\d$'))
+>>> f.clean('2A2')
+u'2A2'
+>>> f.clean('3F3')
+u'3F3'
+>>> f.clean('3G3')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+>>> f.clean(' 2A2')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+>>> f.clean('2A2 ')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+
+RegexField takes an optional error_message argument:
+>>> f = RegexField('^\d\d\d\d$', error_message='Enter a four-digit number.')
+>>> f.clean('1234')
+u'1234'
+>>> f.clean('123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a four-digit number.']
+>>> f.clean('abcd')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a four-digit number.']
+
+RegexField also access min_length and max_length parameters, for convenience.
+>>> f = RegexField('^\d+$', min_length=5, max_length=10)
+>>> f.clean('123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 5 characters (it has 3).']
+>>> f.clean('abc')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 5 characters (it has 3).']
+>>> f.clean('12345')
+u'12345'
+>>> f.clean('1234567890')
+u'1234567890'
+>>> f.clean('12345678901')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 10 characters (it has 11).']
+>>> f.clean('12345a')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+
+# EmailField ##################################################################
+
+>>> f = EmailField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('person@example.com')
+u'person@example.com'
+>>> f.clean('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid e-mail address.']
+>>> f.clean('foo@')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid e-mail address.']
+>>> f.clean('foo@bar')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid e-mail address.']
+
+>>> f = EmailField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+>>> f.clean('person@example.com')
+u'person@example.com'
+>>> f.clean('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid e-mail address.']
+>>> f.clean('foo@')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid e-mail address.']
+>>> f.clean('foo@bar')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid e-mail address.']
+
+EmailField also access min_length and max_length parameters, for convenience.
+>>> f = EmailField(min_length=10, max_length=15)
+>>> f.clean('a@foo.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 10 characters (it has 9).']
+>>> f.clean('alf@foo.com')
+u'alf@foo.com'
+>>> f.clean('alf123456788@foo.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 15 characters (it has 20).']
+
+# FileField ##################################################################
+
+>>> f = FileField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f.clean({})
+Traceback (most recent call last):
+...
+ValidationError: [u'No file was submitted.']
+
+>>> f.clean('some content that is not a file')
+Traceback (most recent call last):
+...
+ValidationError: [u'No file was submitted. Check the encoding type on the form.']
+
+>>> f.clean({'filename': 'name', 'content':None})
+Traceback (most recent call last):
+...
+ValidationError: [u'The submitted file is empty.']
+
+>>> f.clean({'filename': 'name', 'content':''})
+Traceback (most recent call last):
+...
+ValidationError: [u'The submitted file is empty.']
+
+>>> type(f.clean({'filename': 'name', 'content':'Some File Content'}))
+
+
+# URLField ##################################################################
+
+>>> f = URLField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('http://localhost')
+u'http://localhost'
+>>> f.clean('http://example.com')
+u'http://example.com'
+>>> f.clean('http://www.example.com')
+u'http://www.example.com'
+>>> f.clean('http://www.example.com:8000/test')
+u'http://www.example.com:8000/test'
+>>> f.clean('http://200.8.9.10')
+u'http://200.8.9.10'
+>>> f.clean('http://200.8.9.10:8000/test')
+u'http://200.8.9.10:8000/test'
+>>> f.clean('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://example')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://example.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+
+>>> f = URLField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+>>> f.clean('http://example.com')
+u'http://example.com'
+>>> f.clean('http://www.example.com')
+u'http://www.example.com'
+>>> f.clean('foo')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://example')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://example.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+
+URLField takes an optional verify_exists parameter, which is False by default.
+This verifies that the URL is live on the Internet and doesn't return a 404 or 500:
+>>> f = URLField(verify_exists=True)
+>>> f.clean('http://www.google.com') # This will fail if there's no Internet connection
+u'http://www.google.com'
+>>> f.clean('http://example')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid URL.']
+>>> f.clean('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com') # bad domain
+Traceback (most recent call last):
+...
+ValidationError: [u'This URL appears to be a broken link.']
+>>> f.clean('http://google.com/we-love-microsoft.html') # good domain, bad page
+Traceback (most recent call last):
+...
+ValidationError: [u'This URL appears to be a broken link.']
+>>> f = URLField(verify_exists=True, required=False)
+>>> f.clean('')
+u''
+>>> f.clean('http://www.google.com') # This will fail if there's no Internet connection
+u'http://www.google.com'
+
+URLField also access min_length and max_length parameters, for convenience.
+>>> f = URLField(min_length=15, max_length=20)
+>>> f.clean('http://f.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 15 characters (it has 12).']
+>>> f.clean('http://example.com')
+u'http://example.com'
+>>> f.clean('http://abcdefghijklmnopqrstuvwxyz.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 20 characters (it has 37).']
+
+URLField should prepend 'http://' if no scheme was given
+>>> f = URLField(required=False)
+>>> f.clean('example.com')
+u'http://example.com'
+>>> f.clean('')
+u''
+>>> f.clean('https://example.com')
+u'https://example.com'
+
+# BooleanField ################################################################
+
+>>> f = BooleanField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(True)
+True
+>>> f.clean(False)
+False
+>>> f.clean(1)
+True
+>>> f.clean(0)
+False
+>>> f.clean('Django rocks')
+True
+
+>>> f = BooleanField(required=False)
+>>> f.clean('')
+False
+>>> f.clean(None)
+False
+>>> f.clean(True)
+True
+>>> f.clean(False)
+False
+>>> f.clean(1)
+True
+>>> f.clean(0)
+False
+>>> f.clean('Django rocks')
+True
+
+# ChoiceField #################################################################
+
+>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(1)
+u'1'
+>>> f.clean('1')
+u'1'
+>>> f.clean('3')
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+
+>>> f = ChoiceField(choices=[('1', '1'), ('2', '2')], required=False)
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+>>> f.clean(1)
+u'1'
+>>> f.clean('1')
+u'1'
+>>> f.clean('3')
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+
+>>> f = ChoiceField(choices=[('J', 'John'), ('P', 'Paul')])
+>>> f.clean('J')
+u'J'
+>>> f.clean('John')
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
+
+# NullBooleanField ############################################################
+
+>>> f = NullBooleanField()
+>>> f.clean('')
+>>> f.clean(True)
+True
+>>> f.clean(False)
+False
+>>> f.clean(None)
+>>> f.clean('1')
+>>> f.clean('2')
+>>> f.clean('3')
+>>> f.clean('hello')
+
+# MultipleChoiceField #########################################################
+
+>>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')])
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean([1])
+[u'1']
+>>> f.clean(['1'])
+[u'1']
+>>> f.clean(['1', '2'])
+[u'1', u'2']
+>>> f.clean([1, '2'])
+[u'1', u'2']
+>>> f.clean((1, '2'))
+[u'1', u'2']
+>>> f.clean('hello')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a list of values.']
+>>> f.clean([])
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(())
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(['3'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
+
+>>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')], required=False)
+>>> f.clean('')
+[]
+>>> f.clean(None)
+[]
+>>> f.clean([1])
+[u'1']
+>>> f.clean(['1'])
+[u'1']
+>>> f.clean(['1', '2'])
+[u'1', u'2']
+>>> f.clean([1, '2'])
+[u'1', u'2']
+>>> f.clean((1, '2'))
+[u'1', u'2']
+>>> f.clean('hello')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a list of values.']
+>>> f.clean([])
+[]
+>>> f.clean(())
+[]
+>>> f.clean(['3'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
+
+# ComboField ##################################################################
+
+ComboField takes a list of fields that should be used to validate a value,
+in that order.
+>>> f = ComboField(fields=[CharField(max_length=20), EmailField()])
+>>> f.clean('test@example.com')
+u'test@example.com'
+>>> f.clean('longemailaddress@example.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 20 characters (it has 28).']
+>>> f.clean('not an e-mail')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid e-mail address.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = ComboField(fields=[CharField(max_length=20), EmailField()], required=False)
+>>> f.clean('test@example.com')
+u'test@example.com'
+>>> f.clean('longemailaddress@example.com')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 20 characters (it has 28).']
+>>> f.clean('not an e-mail')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid e-mail address.']
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+
+# SplitDateTimeField ##########################################################
+
+>>> f = SplitDateTimeField()
+>>> f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)])
+datetime.datetime(2006, 1, 10, 7, 30)
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('hello')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a list of values.']
+>>> f.clean(['hello', 'there'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.', u'Enter a valid time.']
+>>> f.clean(['2006-01-10', 'there'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid time.']
+>>> f.clean(['hello', '07:30'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+
+>>> f = SplitDateTimeField(required=False)
+>>> f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)])
+datetime.datetime(2006, 1, 10, 7, 30)
+>>> f.clean(['2006-01-10', '07:30'])
+datetime.datetime(2006, 1, 10, 7, 30)
+>>> f.clean(None)
+>>> f.clean('')
+>>> f.clean([''])
+>>> f.clean(['', ''])
+>>> f.clean('hello')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a list of values.']
+>>> f.clean(['hello', 'there'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.', u'Enter a valid time.']
+>>> f.clean(['2006-01-10', 'there'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid time.']
+>>> f.clean(['hello', '07:30'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean(['2006-01-10', ''])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid time.']
+>>> f.clean(['2006-01-10'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid time.']
+>>> f.clean(['', '07:30'])
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+"""
diff --git a/tests/regressiontests/forms/forms.py b/tests/regressiontests/forms/forms.py
new file mode 100644
index 0000000000..ed88e3a6bb
--- /dev/null
+++ b/tests/regressiontests/forms/forms.py
@@ -0,0 +1,1606 @@
+# -*- coding: utf-8 -*-
+tests = r"""
+>>> from django.newforms import *
+>>> import datetime
+>>> import time
+>>> import re
+>>> try:
+... from decimal import Decimal
+... except ImportError:
+... from django.utils._decimal import Decimal
+
+#########
+# Forms #
+#########
+
+A Form is a collection of Fields. It knows how to validate a set of data and it
+knows how to render itself in a couple of default ways (e.g., an HTML table).
+You can pass it data in __init__(), as a dictionary.
+
+# Form ########################################################################
+
+>>> class Person(Form):
+... first_name = CharField()
+... last_name = CharField()
+... birthday = DateField()
+
+Pass a dictionary to a Form's __init__().
+>>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'})
+>>> p.is_bound
+True
+>>> p.errors
+{}
+>>> p.is_valid()
+True
+>>> p.errors.as_ul()
+u''
+>>> p.errors.as_text()
+u''
+>>> p.cleaned_data
+{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+>>> print p['first_name']
+
+>>> print p['last_name']
+
+>>> print p['birthday']
+
+>>> print p['nonexistentfield']
+Traceback (most recent call last):
+...
+KeyError: "Key 'nonexistentfield' not found in Form"
+
+>>> for boundfield in p:
+... print boundfield
+
+
+
+>>> for boundfield in p:
+... print boundfield.label, boundfield.data
+First name John
+Last name Lennon
+Birthday 1940-10-9
+>>> print p
+First name:
+Last name:
+Birthday:
+
+Empty dictionaries are valid, too.
+>>> p = Person({})
+>>> p.is_bound
+True
+>>> p.errors
+{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
+>>> p.is_valid()
+False
+>>> p.cleaned_data
+Traceback (most recent call last):
+...
+AttributeError: 'Person' object has no attribute 'cleaned_data'
+>>> print p
+First name:
+Last name:
+Birthday:
+>>> print p.as_table()
+First name:
+Last name:
+Birthday:
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+>>> print p.as_p()
+
+First name:
+
+Last name:
+
+Birthday:
+
+If you don't pass any values to the Form's __init__(), or if you pass None,
+the Form will be considered unbound and won't do any validation. Form.errors
+will be an empty dictionary *but* Form.is_valid() will return False.
+>>> p = Person()
+>>> p.is_bound
+False
+>>> p.errors
+{}
+>>> p.is_valid()
+False
+>>> p.cleaned_data
+Traceback (most recent call last):
+...
+AttributeError: 'Person' object has no attribute 'cleaned_data'
+>>> print p
+First name:
+Last name:
+Birthday:
+>>> print p.as_table()
+First name:
+Last name:
+Birthday:
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+>>> print p.as_p()
+First name:
+Last name:
+Birthday:
+
+Unicode values are handled properly.
+>>> p = Person({'first_name': u'John', 'last_name': u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111', 'birthday': '1940-10-9'})
+>>> p.as_table()
+u'First name: \nLast name: \nBirthday: '
+>>> p.as_ul()
+u'First name: \nLast name: \nBirthday: '
+>>> p.as_p()
+u'First name:
\nLast name:
\nBirthday:
'
+
+>>> p = Person({'last_name': u'Lennon'})
+>>> p.errors
+{'first_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
+>>> p.is_valid()
+False
+>>> p.errors.as_ul()
+u''
+>>> print p.errors.as_text()
+* first_name
+ * This field is required.
+* birthday
+ * This field is required.
+>>> p.cleaned_data
+Traceback (most recent call last):
+...
+AttributeError: 'Person' object has no attribute 'cleaned_data'
+>>> p['first_name'].errors
+[u'This field is required.']
+>>> p['first_name'].errors.as_ul()
+u''
+>>> p['first_name'].errors.as_text()
+u'* This field is required.'
+
+>>> p = Person()
+>>> print p['first_name']
+
+>>> print p['last_name']
+
+>>> print p['birthday']
+
+
+cleaned_data will always *only* contain a key for fields defined in the
+Form, even if you pass extra data when you define the Form. In this
+example, we pass a bunch of extra fields to the form constructor,
+but cleaned_data contains only the form's fields.
+>>> data = {'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9', 'extra1': 'hello', 'extra2': 'hello'}
+>>> p = Person(data)
+>>> p.is_valid()
+True
+>>> p.cleaned_data
+{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+
+cleaned_data will include a key and value for *all* fields defined in the Form,
+even if the Form's data didn't include a value for fields that are not
+required. In this example, the data dictionary doesn't include a value for the
+"nick_name" field, but cleaned_data includes it. For CharFields, it's set to the
+empty string.
+>>> class OptionalPersonForm(Form):
+... first_name = CharField()
+... last_name = CharField()
+... nick_name = CharField(required=False)
+>>> data = {'first_name': u'John', 'last_name': u'Lennon'}
+>>> f = OptionalPersonForm(data)
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}
+
+For DateFields, it's set to None.
+>>> class OptionalPersonForm(Form):
+... first_name = CharField()
+... last_name = CharField()
+... birth_date = DateField(required=False)
+>>> data = {'first_name': u'John', 'last_name': u'Lennon'}
+>>> f = OptionalPersonForm(data)
+>>> f.is_valid()
+True
+>>> f.cleaned_data
+{'birth_date': None, 'first_name': u'John', 'last_name': u'Lennon'}
+
+"auto_id" tells the Form to add an "id" attribute to each form element.
+If it's a string that contains '%s', Django will use that as a format string
+into which the field's name will be inserted. It will also put a around
+the human-readable labels for a field.
+>>> p = Person(auto_id='%s_id')
+>>> print p.as_table()
+First name:
+Last name:
+Birthday:
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+>>> print p.as_p()
+First name:
+Last name:
+Birthday:
+
+If auto_id is any True value whose str() does not contain '%s', the "id"
+attribute will be the name of the field.
+>>> p = Person(auto_id=True)
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+
+If auto_id is any False value, an "id" attribute won't be output unless it
+was manually entered.
+>>> p = Person(auto_id=False)
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+
+In this example, auto_id is False, but the "id" attribute for the "first_name"
+field is given. Also note that field gets a , while the others don't.
+>>> class PersonNew(Form):
+... first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'}))
+... last_name = CharField()
+... birthday = DateField()
+>>> p = PersonNew(auto_id=False)
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+
+If the "id" attribute is specified in the Form and auto_id is True, the "id"
+attribute in the Form gets precedence.
+>>> p = PersonNew(auto_id=True)
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+
+>>> class SignupForm(Form):
+... email = EmailField()
+... get_spam = BooleanField()
+>>> f = SignupForm(auto_id=False)
+>>> print f['email']
+
+>>> print f['get_spam']
+
+
+>>> f = SignupForm({'email': 'test@example.com', 'get_spam': True}, auto_id=False)
+>>> print f['email']
+
+>>> print f['get_spam']
+
+
+Any Field can have a Widget class passed to its constructor:
+>>> class ContactForm(Form):
+... subject = CharField()
+... message = CharField(widget=Textarea)
+>>> f = ContactForm(auto_id=False)
+>>> print f['subject']
+
+>>> print f['message']
+
+
+as_textarea(), as_text() and as_hidden() are shortcuts for changing the output
+widget type:
+>>> f['subject'].as_textarea()
+u''
+>>> f['message'].as_text()
+u' '
+>>> f['message'].as_hidden()
+u' '
+
+The 'widget' parameter to a Field can also be an instance:
+>>> class ContactForm(Form):
+... subject = CharField()
+... message = CharField(widget=Textarea(attrs={'rows': 80, 'cols': 20}))
+>>> f = ContactForm(auto_id=False)
+>>> print f['message']
+
+
+Instance-level attrs are *not* carried over to as_textarea(), as_text() and
+as_hidden():
+>>> f['message'].as_text()
+u' '
+>>> f = ContactForm({'subject': 'Hello', 'message': 'I love you.'}, auto_id=False)
+>>> f['subject'].as_textarea()
+u''
+>>> f['message'].as_text()
+u' '
+>>> f['message'].as_hidden()
+u' '
+
+For a form with a , use ChoiceField:
+>>> class FrameworkForm(Form):
+... name = CharField()
+... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')])
+>>> f = FrameworkForm(auto_id=False)
+>>> print f['language']
+
+Python
+Java
+
+>>> f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
+>>> print f['language']
+
+Python
+Java
+
+
+A subtlety: If one of the choices' value is the empty string and the form is
+unbound, then the for the empty-string choice will get selected="selected".
+>>> class FrameworkForm(Form):
+... name = CharField()
+... language = ChoiceField(choices=[('', '------'), ('P', 'Python'), ('J', 'Java')])
+>>> f = FrameworkForm(auto_id=False)
+>>> print f['language']
+
+------
+Python
+Java
+
+
+You can specify widget attributes in the Widget constructor.
+>>> class FrameworkForm(Form):
+... name = CharField()
+... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=Select(attrs={'class': 'foo'}))
+>>> f = FrameworkForm(auto_id=False)
+>>> print f['language']
+
+Python
+Java
+
+>>> f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
+>>> print f['language']
+
+Python
+Java
+
+
+When passing a custom widget instance to ChoiceField, note that setting
+'choices' on the widget is meaningless. The widget will use the choices
+defined on the Field, not the ones defined on the Widget.
+>>> class FrameworkForm(Form):
+... name = CharField()
+... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=Select(choices=[('R', 'Ruby'), ('P', 'Perl')], attrs={'class': 'foo'}))
+>>> f = FrameworkForm(auto_id=False)
+>>> print f['language']
+
+Python
+Java
+
+>>> f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
+>>> print f['language']
+
+Python
+Java
+
+
+You can set a ChoiceField's choices after the fact.
+>>> class FrameworkForm(Form):
+... name = CharField()
+... language = ChoiceField()
+>>> f = FrameworkForm(auto_id=False)
+>>> print f['language']
+
+
+>>> f.fields['language'].choices = [('P', 'Python'), ('J', 'Java')]
+>>> print f['language']
+
+Python
+Java
+
+
+Add widget=RadioSelect to use that widget with a ChoiceField.
+>>> class FrameworkForm(Form):
+... name = CharField()
+... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=RadioSelect)
+>>> f = FrameworkForm(auto_id=False)
+>>> print f['language']
+
+>>> print f
+Name:
+Language:
+>>> print f.as_ul()
+Name:
+Language:
+
+Regarding auto_id and , RadioSelect is a special case. Each radio button
+gets a distinct ID, formed by appending an underscore plus the button's
+zero-based index.
+>>> f = FrameworkForm(auto_id='id_%s')
+>>> print f['language']
+
+
+When RadioSelect is used with auto_id, and the whole form is printed using
+either as_table() or as_ul(), the label for the RadioSelect will point to the
+ID of the *first* radio button.
+>>> print f
+Name:
+Language:
+>>> print f.as_ul()
+Name:
+Language:
+>>> print f.as_p()
+Name:
+Language:
+
+MultipleChoiceField is a special case, as its data is required to be a list:
+>>> class SongForm(Form):
+... name = CharField()
+... composers = MultipleChoiceField()
+>>> f = SongForm(auto_id=False)
+>>> print f['composers']
+
+
+>>> class SongForm(Form):
+... name = CharField()
+... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')])
+>>> f = SongForm(auto_id=False)
+>>> print f['composers']
+
+John Lennon
+Paul McCartney
+
+>>> f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False)
+>>> print f['name']
+
+>>> print f['composers']
+
+John Lennon
+Paul McCartney
+
+
+MultipleChoiceField rendered as_hidden() is a special case. Because it can
+have multiple values, its as_hidden() renders multiple
+tags.
+>>> f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False)
+>>> print f['composers'].as_hidden()
+
+>>> f = SongForm({'name': 'From Me To You', 'composers': ['P', 'J']}, auto_id=False)
+>>> print f['composers'].as_hidden()
+
+
+
+MultipleChoiceField can also be used with the CheckboxSelectMultiple widget.
+>>> class SongForm(Form):
+... name = CharField()
+... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=CheckboxSelectMultiple)
+>>> f = SongForm(auto_id=False)
+>>> print f['composers']
+
+>>> f = SongForm({'composers': ['J']}, auto_id=False)
+>>> print f['composers']
+
+>>> f = SongForm({'composers': ['J', 'P']}, auto_id=False)
+>>> print f['composers']
+
+
+Regarding auto_id, CheckboxSelectMultiple is a special case. Each checkbox
+gets a distinct ID, formed by appending an underscore plus the checkbox's
+zero-based index.
+>>> f = SongForm(auto_id='%s_id')
+>>> print f['composers']
+
+
+Data for a MultipleChoiceField should be a list. QueryDict and MultiValueDict
+conveniently work with this.
+>>> data = {'name': 'Yesterday', 'composers': ['J', 'P']}
+>>> f = SongForm(data)
+>>> f.errors
+{}
+>>> from django.http import QueryDict
+>>> data = QueryDict('name=Yesterday&composers=J&composers=P')
+>>> f = SongForm(data)
+>>> f.errors
+{}
+>>> from django.utils.datastructures import MultiValueDict
+>>> data = MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P']))
+>>> f = SongForm(data)
+>>> f.errors
+{}
+
+The MultipleHiddenInput widget renders multiple values as hidden fields.
+>>> class SongFormHidden(Form):
+... name = CharField()
+... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=MultipleHiddenInput)
+>>> f = SongFormHidden(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])), auto_id=False)
+>>> print f.as_ul()
+Name:
+
+
+When using CheckboxSelectMultiple, the framework expects a list of input and
+returns a list of input.
+>>> f = SongForm({'name': 'Yesterday'}, auto_id=False)
+>>> f.errors
+{'composers': [u'This field is required.']}
+>>> f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False)
+>>> f.errors
+{}
+>>> f.cleaned_data
+{'composers': [u'J'], 'name': u'Yesterday'}
+>>> f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False)
+>>> f.errors
+{}
+>>> f.cleaned_data
+{'composers': [u'J', u'P'], 'name': u'Yesterday'}
+
+Validation errors are HTML-escaped when output as HTML.
+>>> class EscapingForm(Form):
+... special_name = CharField()
+... def clean_special_name(self):
+... raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name'])
+
+>>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False)
+>>> print f
+Special name: Something's wrong with 'Nothing to escape'
+>>> f = EscapingForm({'special_name': "Should escape < & > and "}, auto_id=False)
+>>> print f
+Special name: Something's wrong with 'Should escape < & > and <script>alert('xss')</script>'
+
+""" + \
+r""" # [This concatenation is to keep the string below the jython's 32K limit].
+# Validating multiple fields in relation to another ###########################
+
+There are a couple of ways to do multiple-field validation. If you want the
+validation message to be associated with a particular field, implement the
+clean_XXX() method on the Form, where XXX is the field name. As in
+Field.clean(), the clean_XXX() method should return the cleaned value. In the
+clean_XXX() method, you have access to self.cleaned_data, which is a dictionary
+of all the data that has been cleaned *so far*, in order by the fields,
+including the current field (e.g., the field XXX if you're in clean_XXX()).
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10)
+... password1 = CharField(widget=PasswordInput)
+... password2 = CharField(widget=PasswordInput)
+... def clean_password2(self):
+... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
+... raise ValidationError(u'Please make sure your passwords match.')
+... return self.cleaned_data['password2']
+>>> f = UserRegistration(auto_id=False)
+>>> f.errors
+{}
+>>> f = UserRegistration({}, auto_id=False)
+>>> f.errors
+{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']}
+>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
+>>> f.errors
+{'password2': [u'Please make sure your passwords match.']}
+>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
+>>> f.errors
+{}
+>>> f.cleaned_data
+{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
+
+Another way of doing multiple-field validation is by implementing the
+Form's clean() method. If you do this, any ValidationError raised by that
+method will not be associated with a particular field; it will have a
+special-case association with the field named '__all__'.
+Note that in Form.clean(), you have access to self.cleaned_data, a dictionary of
+all the fields/values that have *not* raised a ValidationError. Also note
+Form.clean() is required to return a dictionary of all clean data.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10)
+... password1 = CharField(widget=PasswordInput)
+... password2 = CharField(widget=PasswordInput)
+... def clean(self):
+... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
+... raise ValidationError(u'Please make sure your passwords match.')
+... return self.cleaned_data
+>>> f = UserRegistration(auto_id=False)
+>>> f.errors
+{}
+>>> f = UserRegistration({}, auto_id=False)
+>>> print f.as_table()
+Username:
+Password1:
+Password2:
+>>> f.errors
+{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']}
+>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
+>>> f.errors
+{'__all__': [u'Please make sure your passwords match.']}
+>>> print f.as_table()
+Please make sure your passwords match.
+Username:
+Password1:
+Password2:
+>>> print f.as_ul()
+Please make sure your passwords match.
+Username:
+Password1:
+Password2:
+>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
+>>> f.errors
+{}
+>>> f.cleaned_data
+{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
+
+# Dynamic construction ########################################################
+
+It's possible to construct a Form dynamically by adding to the self.fields
+dictionary in __init__(). Don't forget to call Form.__init__() within the
+subclass' __init__().
+>>> class Person(Form):
+... first_name = CharField()
+... last_name = CharField()
+... def __init__(self, *args, **kwargs):
+... super(Person, self).__init__(*args, **kwargs)
+... self.fields['birthday'] = DateField()
+>>> p = Person(auto_id=False)
+>>> print p
+First name:
+Last name:
+Birthday:
+
+Instances of a dynamic Form do not persist fields from one Form instance to
+the next.
+>>> class MyForm(Form):
+... def __init__(self, data=None, auto_id=False, field_list=[]):
+... Form.__init__(self, data, auto_id=auto_id)
+... for field in field_list:
+... self.fields[field[0]] = field[1]
+>>> field_list = [('field1', CharField()), ('field2', CharField())]
+>>> my_form = MyForm(field_list=field_list)
+>>> print my_form
+Field1:
+Field2:
+>>> field_list = [('field3', CharField()), ('field4', CharField())]
+>>> my_form = MyForm(field_list=field_list)
+>>> print my_form
+Field3:
+Field4:
+
+>>> class MyForm(Form):
+... default_field_1 = CharField()
+... default_field_2 = CharField()
+... def __init__(self, data=None, auto_id=False, field_list=[]):
+... Form.__init__(self, data, auto_id=auto_id)
+... for field in field_list:
+... self.fields[field[0]] = field[1]
+>>> field_list = [('field1', CharField()), ('field2', CharField())]
+>>> my_form = MyForm(field_list=field_list)
+>>> print my_form
+Default field 1:
+Default field 2:
+Field1:
+Field2:
+>>> field_list = [('field3', CharField()), ('field4', CharField())]
+>>> my_form = MyForm(field_list=field_list)
+>>> print my_form
+Default field 1:
+Default field 2:
+Field3:
+Field4:
+
+Similarly, changes to field attributes do not persist from one Form instance
+to the next.
+>>> class Person(Form):
+... first_name = CharField(required=False)
+... last_name = CharField(required=False)
+... def __init__(self, names_required=False, *args, **kwargs):
+... super(Person, self).__init__(*args, **kwargs)
+... if names_required:
+... self.fields['first_name'].required = True
+... self.fields['first_name'].widget.attrs['class'] = 'required'
+... self.fields['last_name'].required = True
+... self.fields['last_name'].widget.attrs['class'] = 'required'
+>>> f = Person(names_required=False)
+>>> f['first_name'].field.required, f['last_name'].field.required
+(False, False)
+>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
+({}, {})
+>>> f = Person(names_required=True)
+>>> f['first_name'].field.required, f['last_name'].field.required
+(True, True)
+>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
+({'class': 'required'}, {'class': 'required'})
+>>> f = Person(names_required=False)
+>>> f['first_name'].field.required, f['last_name'].field.required
+(False, False)
+>>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
+({}, {})
+>>> class Person(Form):
+... first_name = CharField(max_length=30)
+... last_name = CharField(max_length=30)
+... def __init__(self, name_max_length=None, *args, **kwargs):
+... super(Person, self).__init__(*args, **kwargs)
+... if name_max_length:
+... self.fields['first_name'].max_length = name_max_length
+... self.fields['last_name'].max_length = name_max_length
+>>> f = Person(name_max_length=None)
+>>> f['first_name'].field.max_length, f['last_name'].field.max_length
+(30, 30)
+>>> f = Person(name_max_length=20)
+>>> f['first_name'].field.max_length, f['last_name'].field.max_length
+(20, 20)
+>>> f = Person(name_max_length=None)
+>>> f['first_name'].field.max_length, f['last_name'].field.max_length
+(30, 30)
+
+HiddenInput widgets are displayed differently in the as_table(), as_ul()
+and as_p() output of a Form -- their verbose names are not displayed, and a
+separate row is not displayed. They're displayed in the last row of the
+form, directly after that row's form element.
+>>> class Person(Form):
+... first_name = CharField()
+... last_name = CharField()
+... hidden_text = CharField(widget=HiddenInput)
+... birthday = DateField()
+>>> p = Person(auto_id=False)
+>>> print p
+First name:
+Last name:
+Birthday:
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+>>> print p.as_p()
+First name:
+Last name:
+Birthday:
+
+With auto_id set, a HiddenInput still gets an ID, but it doesn't get a label.
+>>> p = Person(auto_id='id_%s')
+>>> print p
+First name:
+Last name:
+Birthday:
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+>>> print p.as_p()
+First name:
+Last name:
+Birthday:
+
+If a field with a HiddenInput has errors, the as_table() and as_ul() output
+will include the error message(s) with the text "(Hidden field [fieldname]) "
+prepended. This message is displayed at the top of the output, regardless of
+its field's order in the form.
+>>> p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'}, auto_id=False)
+>>> print p
+(Hidden field hidden_text) This field is required.
+First name:
+Last name:
+Birthday:
+>>> print p.as_ul()
+(Hidden field hidden_text) This field is required.
+First name:
+Last name:
+Birthday:
+>>> print p.as_p()
+(Hidden field hidden_text) This field is required.
+First name:
+Last name:
+Birthday:
+
+A corner case: It's possible for a form to have only HiddenInputs.
+>>> class TestForm(Form):
+... foo = CharField(widget=HiddenInput)
+... bar = CharField(widget=HiddenInput)
+>>> p = TestForm(auto_id=False)
+>>> print p.as_table()
+
+>>> print p.as_ul()
+
+>>> print p.as_p()
+
+
+A Form's fields are displayed in the same order in which they were defined.
+>>> class TestForm(Form):
+... field1 = CharField()
+... field2 = CharField()
+... field3 = CharField()
+... field4 = CharField()
+... field5 = CharField()
+... field6 = CharField()
+... field7 = CharField()
+... field8 = CharField()
+... field9 = CharField()
+... field10 = CharField()
+... field11 = CharField()
+... field12 = CharField()
+... field13 = CharField()
+... field14 = CharField()
+>>> p = TestForm(auto_id=False)
+>>> print p
+Field1:
+Field2:
+Field3:
+Field4:
+Field5:
+Field6:
+Field7:
+Field8:
+Field9:
+Field10:
+Field11:
+Field12:
+Field13:
+Field14:
+
+Some Field classes have an effect on the HTML attributes of their associated
+Widget. If you set max_length in a CharField and its associated widget is
+either a TextInput or PasswordInput, then the widget's rendered HTML will
+include the "maxlength" attribute.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10) # uses TextInput by default
+... password = CharField(max_length=10, widget=PasswordInput)
+... realname = CharField(max_length=10, widget=TextInput) # redundantly define widget, just to test
+... address = CharField() # no max_length defined here
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+Realname:
+Address:
+
+If you specify a custom "attrs" that includes the "maxlength" attribute,
+the Field's max_length attribute will override whatever "maxlength" you specify
+in "attrs".
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, widget=TextInput(attrs={'maxlength': 20}))
+... password = CharField(max_length=10, widget=PasswordInput)
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+# Specifying labels ###########################################################
+
+You can specify the label for a field by using the 'label' argument to a Field
+class. If you don't specify 'label', Django will use the field name with
+underscores converted to spaces, and the initial letter capitalized.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, label='Your username')
+... password1 = CharField(widget=PasswordInput)
+... password2 = CharField(widget=PasswordInput, label='Password (again)')
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+Your username:
+Password1:
+Password (again):
+
+Labels for as_* methods will only end in a colon if they don't end in other
+punctuation already.
+>>> class Questions(Form):
+... q1 = CharField(label='The first question')
+... q2 = CharField(label='What is your name?')
+... q3 = CharField(label='The answer to life is:')
+... q4 = CharField(label='Answer this question!')
+... q5 = CharField(label='The last question. Period.')
+>>> print Questions(auto_id=False).as_p()
+The first question:
+What is your name?
+The answer to life is:
+Answer this question!
+The last question. Period.
+>>> print Questions().as_p()
+The first question:
+What is your name?
+The answer to life is:
+Answer this question!
+The last question. Period.
+
+A label can be a Unicode object or a bytestring with special characters.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, label='ŠĐĆŽćžšđ')
+... password = CharField(widget=PasswordInput, label=u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111')
+>>> p = UserRegistration(auto_id=False)
+>>> p.as_ul()
+u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111: \n\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111: '
+
+If a label is set to the empty string for a field, that field won't get a label.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, label='')
+... password = CharField(widget=PasswordInput)
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+
+Password:
+>>> p = UserRegistration(auto_id='id_%s')
+>>> print p.as_ul()
+
+Password:
+
+If label is None, Django will auto-create the label from the field name. This
+is default behavior.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, label=None)
+... password = CharField(widget=PasswordInput)
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration(auto_id='id_%s')
+>>> print p.as_ul()
+Username:
+Password:
+
+
+# Label Suffix ################################################################
+
+You can specify the 'label_suffix' argument to a Form class to modify the
+punctuation symbol used at the end of a label. By default, the colon (:) is
+used, and is only appended to the label if the label doesn't already end with a
+punctuation symbol: ., !, ? or :. If you specify a different suffix, it will
+be appended regardless of the last character of the label.
+
+>>> class FavoriteForm(Form):
+... color = CharField(label='Favorite color?')
+... animal = CharField(label='Favorite animal')
+...
+>>> f = FavoriteForm(auto_id=False)
+>>> print f.as_ul()
+Favorite color?
+Favorite animal:
+>>> f = FavoriteForm(auto_id=False, label_suffix='?')
+>>> print f.as_ul()
+Favorite color?
+Favorite animal?
+>>> f = FavoriteForm(auto_id=False, label_suffix='')
+>>> print f.as_ul()
+Favorite color?
+Favorite animal
+>>> f = FavoriteForm(auto_id=False, label_suffix=u'\u2192')
+>>> f.as_ul()
+u'Favorite color? \nFavorite animal\u2192 '
+
+""" + \
+r""" # [This concatenation is to keep the string below the jython's 32K limit].
+
+# Initial data ################################################################
+
+You can specify initial data for a field by using the 'initial' argument to a
+Field class. This initial data is displayed when a Form is rendered with *no*
+data. It is not displayed when a Form is rendered with any data (including an
+empty dictionary). Also, the initial value is *not* used if data for a
+particular required field isn't provided.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, initial='django')
+... password = CharField(widget=PasswordInput)
+
+Here, we're not submitting any data, so the initial value will be displayed.
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+Here, we're submitting data, so the initial value will *not* be displayed.
+>>> p = UserRegistration({}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration({'username': u''}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration({'username': u'foo'}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+An 'initial' value is *not* used as a fallback if data is not provided. In this
+example, we don't provide a value for 'username', and the form raises a
+validation error rather than using the initial value for 'username'.
+>>> p = UserRegistration({'password': 'secret'})
+>>> p.errors
+{'username': [u'This field is required.']}
+>>> p.is_valid()
+False
+
+# Dynamic initial data ########################################################
+
+The previous technique dealt with "hard-coded" initial data, but it's also
+possible to specify initial data after you've already created the Form class
+(i.e., at runtime). Use the 'initial' parameter to the Form constructor. This
+should be a dictionary containing initial values for one or more fields in the
+form, keyed by field name.
+
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10)
+... password = CharField(widget=PasswordInput)
+
+Here, we're not submitting any data, so the initial value will be displayed.
+>>> p = UserRegistration(initial={'username': 'django'}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration(initial={'username': 'stephane'}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+The 'initial' parameter is meaningless if you pass data.
+>>> p = UserRegistration({}, initial={'username': 'django'}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration({'username': u''}, initial={'username': 'django'}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration({'username': u'foo'}, initial={'username': 'django'}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+A dynamic 'initial' value is *not* used as a fallback if data is not provided.
+In this example, we don't provide a value for 'username', and the form raises a
+validation error rather than using the initial value for 'username'.
+>>> p = UserRegistration({'password': 'secret'}, initial={'username': 'django'})
+>>> p.errors
+{'username': [u'This field is required.']}
+>>> p.is_valid()
+False
+
+If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(),
+then the latter will get precedence.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, initial='django')
+... password = CharField(widget=PasswordInput)
+>>> p = UserRegistration(initial={'username': 'babik'}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+# Callable initial data ########################################################
+
+The previous technique dealt with raw values as initial data, but it's also
+possible to specify callable data.
+
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10)
+... password = CharField(widget=PasswordInput)
+
+We need to define functions that get called later.
+>>> def initial_django():
+... return 'django'
+>>> def initial_stephane():
+... return 'stephane'
+
+Here, we're not submitting any data, so the initial value will be displayed.
+>>> p = UserRegistration(initial={'username': initial_django}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+The 'initial' parameter is meaningless if you pass data.
+>>> p = UserRegistration({}, initial={'username': initial_django}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration({'username': u''}, initial={'username': initial_django}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration({'username': u'foo'}, initial={'username': initial_django}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+A callable 'initial' value is *not* used as a fallback if data is not provided.
+In this example, we don't provide a value for 'username', and the form raises a
+validation error rather than using the initial value for 'username'.
+>>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django})
+>>> p.errors
+{'username': [u'This field is required.']}
+>>> p.is_valid()
+False
+
+If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(),
+then the latter will get precedence.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, initial=initial_django)
+... password = CharField(widget=PasswordInput)
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+>>> p = UserRegistration(initial={'username': initial_stephane}, auto_id=False)
+>>> print p.as_ul()
+Username:
+Password:
+
+# Help text ###################################################################
+
+You can specify descriptive text for a field by using the 'help_text' argument
+to a Field class. This help text is displayed when a Form is rendered.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, help_text='e.g., user@example.com')
+... password = CharField(widget=PasswordInput, help_text='Choose wisely.')
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+Username: e.g., user@example.com
+Password: Choose wisely.
+>>> print p.as_p()
+Username: e.g., user@example.com
+Password: Choose wisely.
+>>> print p.as_table()
+Username: e.g., user@example.com
+Password: Choose wisely.
+
+The help text is displayed whether or not data is provided for the form.
+>>> p = UserRegistration({'username': u'foo'}, auto_id=False)
+>>> print p.as_ul()
+Username: e.g., user@example.com
+Password: Choose wisely.
+
+help_text is not displayed for hidden fields. It can be used for documentation
+purposes, though.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, help_text='e.g., user@example.com')
+... password = CharField(widget=PasswordInput)
+... next = CharField(widget=HiddenInput, initial='/', help_text='Redirect destination')
+>>> p = UserRegistration(auto_id=False)
+>>> print p.as_ul()
+Username: e.g., user@example.com
+Password:
+
+Help text can include arbitrary Unicode characters.
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, help_text='ŠĐĆŽćžšđ')
+>>> p = UserRegistration(auto_id=False)
+>>> p.as_ul()
+u'Username: \u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111 '
+
+# Subclassing forms ###########################################################
+
+You can subclass a Form to add fields. The resulting form subclass will have
+all of the fields of the parent Form, plus whichever fields you define in the
+subclass.
+>>> class Person(Form):
+... first_name = CharField()
+... last_name = CharField()
+... birthday = DateField()
+>>> class Musician(Person):
+... instrument = CharField()
+>>> p = Person(auto_id=False)
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+>>> m = Musician(auto_id=False)
+>>> print m.as_ul()
+First name:
+Last name:
+Birthday:
+Instrument:
+
+Yes, you can subclass multiple forms. The fields are added in the order in
+which the parent classes are listed.
+>>> class Person(Form):
+... first_name = CharField()
+... last_name = CharField()
+... birthday = DateField()
+>>> class Instrument(Form):
+... instrument = CharField()
+>>> class Beatle(Person, Instrument):
+... haircut_type = CharField()
+>>> b = Beatle(auto_id=False)
+>>> print b.as_ul()
+First name:
+Last name:
+Birthday:
+Instrument:
+Haircut type:
+
+# Forms with prefixes #########################################################
+
+Sometimes it's necessary to have multiple forms display on the same HTML page,
+or multiple copies of the same form. We can accomplish this with form prefixes.
+Pass the keyword argument 'prefix' to the Form constructor to use this feature.
+This value will be prepended to each HTML form field name. One way to think
+about this is "namespaces for HTML forms". Notice that in the data argument,
+each field's key has the prefix, in this case 'person1', prepended to the
+actual field name.
+>>> class Person(Form):
+... first_name = CharField()
+... last_name = CharField()
+... birthday = DateField()
+>>> data = {
+... 'person1-first_name': u'John',
+... 'person1-last_name': u'Lennon',
+... 'person1-birthday': u'1940-10-9'
+... }
+>>> p = Person(data, prefix='person1')
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+>>> print p['first_name']
+
+>>> print p['last_name']
+
+>>> print p['birthday']
+
+>>> p.errors
+{}
+>>> p.is_valid()
+True
+>>> p.cleaned_data
+{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+
+Let's try submitting some bad data to make sure form.errors and field.errors
+work as expected.
+>>> data = {
+... 'person1-first_name': u'',
+... 'person1-last_name': u'',
+... 'person1-birthday': u''
+... }
+>>> p = Person(data, prefix='person1')
+>>> p.errors
+{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
+>>> p['first_name'].errors
+[u'This field is required.']
+>>> p['person1-first_name'].errors
+Traceback (most recent call last):
+...
+KeyError: "Key 'person1-first_name' not found in Form"
+
+In this example, the data doesn't have a prefix, but the form requires it, so
+the form doesn't "see" the fields.
+>>> data = {
+... 'first_name': u'John',
+... 'last_name': u'Lennon',
+... 'birthday': u'1940-10-9'
+... }
+>>> p = Person(data, prefix='person1')
+>>> p.errors
+{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
+
+With prefixes, a single data dictionary can hold data for multiple instances
+of the same form.
+>>> data = {
+... 'person1-first_name': u'John',
+... 'person1-last_name': u'Lennon',
+... 'person1-birthday': u'1940-10-9',
+... 'person2-first_name': u'Jim',
+... 'person2-last_name': u'Morrison',
+... 'person2-birthday': u'1943-12-8'
+... }
+>>> p1 = Person(data, prefix='person1')
+>>> p1.is_valid()
+True
+>>> p1.cleaned_data
+{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+>>> p2 = Person(data, prefix='person2')
+>>> p2.is_valid()
+True
+>>> p2.cleaned_data
+{'first_name': u'Jim', 'last_name': u'Morrison', 'birthday': datetime.date(1943, 12, 8)}
+
+By default, forms append a hyphen between the prefix and the field name, but a
+form can alter that behavior by implementing the add_prefix() method. This
+method takes a field name and returns the prefixed field, according to
+self.prefix.
+>>> class Person(Form):
+... first_name = CharField()
+... last_name = CharField()
+... birthday = DateField()
+... def add_prefix(self, field_name):
+... return self.prefix and '%s-prefix-%s' % (self.prefix, field_name) or field_name
+>>> p = Person(prefix='foo')
+>>> print p.as_ul()
+First name:
+Last name:
+Birthday:
+>>> data = {
+... 'foo-prefix-first_name': u'John',
+... 'foo-prefix-last_name': u'Lennon',
+... 'foo-prefix-birthday': u'1940-10-9'
+... }
+>>> p = Person(data, prefix='foo')
+>>> p.is_valid()
+True
+>>> p.cleaned_data
+{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
+
+# Forms with NullBooleanFields ################################################
+
+NullBooleanField is a bit of a special case because its presentation (widget)
+is different than its data. This is handled transparently, though.
+
+>>> class Person(Form):
+... name = CharField()
+... is_cool = NullBooleanField()
+>>> p = Person({'name': u'Joe'}, auto_id=False)
+>>> print p['is_cool']
+
+Unknown
+Yes
+No
+
+>>> p = Person({'name': u'Joe', 'is_cool': u'1'}, auto_id=False)
+>>> print p['is_cool']
+
+Unknown
+Yes
+No
+
+>>> p = Person({'name': u'Joe', 'is_cool': u'2'}, auto_id=False)
+>>> print p['is_cool']
+
+Unknown
+Yes
+No
+
+>>> p = Person({'name': u'Joe', 'is_cool': u'3'}, auto_id=False)
+>>> print p['is_cool']
+
+Unknown
+Yes
+No
+
+>>> p = Person({'name': u'Joe', 'is_cool': True}, auto_id=False)
+>>> print p['is_cool']
+
+Unknown
+Yes
+No
+
+>>> p = Person({'name': u'Joe', 'is_cool': False}, auto_id=False)
+>>> print p['is_cool']
+
+Unknown
+Yes
+No
+
+
+# Forms with FileFields ################################################
+
+FileFields are a special case because they take their data from the request.FILES,
+not request.POST.
+
+>>> class FileForm(Form):
+... file1 = FileField()
+>>> f = FileForm(auto_id=False)
+>>> print f
+File1:
+
+>>> f = FileForm(data={}, files={}, auto_id=False)
+>>> print f
+File1:
+
+>>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':''}}, auto_id=False)
+>>> print f
+File1: The submitted file is empty.
+
+>>> f = FileForm(data={}, files={'file1': 'something that is not a file'}, auto_id=False)
+>>> print f
+File1: No file was submitted. Check the encoding type on the form.
+
+>>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':'some content'}}, auto_id=False)
+>>> print f
+File1:
+>>> f.is_valid()
+True
+
+# Basic form processing in a view #############################################
+
+>>> from django.template import Template, Context
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10)
+... password1 = CharField(widget=PasswordInput)
+... password2 = CharField(widget=PasswordInput)
+... def clean(self):
+... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
+... raise ValidationError(u'Please make sure your passwords match.')
+... return self.cleaned_data
+>>> def my_function(method, post_data):
+... if method == 'POST':
+... form = UserRegistration(post_data, auto_id=False)
+... else:
+... form = UserRegistration(auto_id=False)
+... if form.is_valid():
+... return 'VALID: %r' % form.cleaned_data
+... t = Template('')
+... return t.render(Context({'form': form}))
+
+Case 1: GET (an empty form, with no errors).
+>>> print my_function('GET', {})
+
+
+Case 2: POST with erroneous data (a redisplayed form, with errors).
+>>> print my_function('POST', {'username': 'this-is-a-long-username', 'password1': 'foo', 'password2': 'bar'})
+
+
+Case 3: POST with valid data (the success message).
+>>> print my_function('POST', {'username': 'adrian', 'password1': 'secret', 'password2': 'secret'})
+VALID: {'username': u'adrian', 'password1': u'secret', 'password2': u'secret'}
+
+# Some ideas for using templates with forms ###################################
+
+>>> class UserRegistration(Form):
+... username = CharField(max_length=10, help_text="Good luck picking a username that doesn't already exist.")
+... password1 = CharField(widget=PasswordInput)
+... password2 = CharField(widget=PasswordInput)
+... def clean(self):
+... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
+... raise ValidationError(u'Please make sure your passwords match.')
+... return self.cleaned_data
+
+You have full flexibility in displaying form fields in a template. Just pass a
+Form instance to the template, and use "dot" access to refer to individual
+fields. Note, however, that this flexibility comes with the responsibility of
+displaying all the errors, including any that might not be associated with a
+particular field.
+>>> t = Template('''''')
+>>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
+
+>>> print t.render(Context({'form': UserRegistration({'username': 'django'}, auto_id=False)}))
+
+
+Use form.[field].label to output a field's label. You can specify the label for
+a field by using the 'label' argument to a Field class. If you don't specify
+'label', Django will use the field name with underscores converted to spaces,
+and the initial letter capitalized.
+>>> t = Template('''''')
+>>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
+
+
+User form.[field].label_tag to output a field's label with a tag
+wrapped around it, but *only* if the given field has an "id" attribute.
+Recall from above that passing the "auto_id" argument to a Form gives each
+field an "id" attribute.
+>>> t = Template('''''')
+>>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
+
+>>> print t.render(Context({'form': UserRegistration(auto_id='id_%s')}))
+
+
+User form.[field].help_text to output a field's help text. If the given field
+does not have help text, nothing will be output.
+>>> t = Template('''''')
+>>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
+
+>>> Template('{{ form.password1.help_text }}').render(Context({'form': UserRegistration(auto_id=False)}))
+u''
+
+The label_tag() method takes an optional attrs argument: a dictionary of HTML
+attributes to add to the tag.
+>>> f = UserRegistration(auto_id='id_%s')
+>>> for bf in f:
+... print bf.label_tag(attrs={'class': 'pretty'})
+Username
+Password1
+Password2
+
+To display the errors that aren't associated with a particular field -- e.g.,
+the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
+template. If used on its own, it is displayed as a (or an empty string, if
+the list of errors is empty). You can also use it in {% if %} statements.
+>>> t = Template(''' ''')
+>>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)}))
+
+>>> t = Template('''''')
+>>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)}))
+
+"""
diff --git a/tests/regressiontests/forms/localflavor.py b/tests/regressiontests/forms/localflavor.py
index 2fe15847c7..e69de29bb2 100644
--- a/tests/regressiontests/forms/localflavor.py
+++ b/tests/regressiontests/forms/localflavor.py
@@ -1,2197 +0,0 @@
-# -*- coding: utf-8 -*-
-# Tests for the different contrib/localflavor/ form fields.
-
-localflavor_tests = r"""
-# USZipCodeField ##############################################################
-
-USZipCodeField validates that the data is either a five-digit U.S. zip code or
-a zip+4.
->>> from django.contrib.localflavor.us.forms import USZipCodeField
->>> f = USZipCodeField()
->>> f.clean('60606')
-u'60606'
->>> f.clean(60606)
-u'60606'
->>> f.clean('04000')
-u'04000'
->>> f.clean('4000')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
->>> f.clean('60606-1234')
-u'60606-1234'
->>> f.clean('6060-1234')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
->>> f.clean('60606-')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = USZipCodeField(required=False)
->>> f.clean('60606')
-u'60606'
->>> f.clean(60606)
-u'60606'
->>> f.clean('04000')
-u'04000'
->>> f.clean('4000')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
->>> f.clean('60606-1234')
-u'60606-1234'
->>> f.clean('6060-1234')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
->>> f.clean('60606-')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# USPhoneNumberField ##########################################################
-
-USPhoneNumberField validates that the data is a valid U.S. phone number,
-including the area code. It's normalized to XXX-XXX-XXXX format.
->>> from django.contrib.localflavor.us.forms import USPhoneNumberField
->>> f = USPhoneNumberField()
->>> f.clean('312-555-1212')
-u'312-555-1212'
->>> f.clean('3125551212')
-u'312-555-1212'
->>> f.clean('312 555-1212')
-u'312-555-1212'
->>> f.clean('(312) 555-1212')
-u'312-555-1212'
->>> f.clean('312 555 1212')
-u'312-555-1212'
->>> f.clean('312.555.1212')
-u'312-555-1212'
->>> f.clean('312.555-1212')
-u'312-555-1212'
->>> f.clean(' (312) 555.1212 ')
-u'312-555-1212'
->>> f.clean('555-1212')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
->>> f.clean('312-55-1212')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = USPhoneNumberField(required=False)
->>> f.clean('312-555-1212')
-u'312-555-1212'
->>> f.clean('3125551212')
-u'312-555-1212'
->>> f.clean('312 555-1212')
-u'312-555-1212'
->>> f.clean('(312) 555-1212')
-u'312-555-1212'
->>> f.clean('312 555 1212')
-u'312-555-1212'
->>> f.clean('312.555.1212')
-u'312-555-1212'
->>> f.clean('312.555-1212')
-u'312-555-1212'
->>> f.clean(' (312) 555.1212 ')
-u'312-555-1212'
->>> f.clean('555-1212')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
->>> f.clean('312-55-1212')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# USStateField ################################################################
-
-USStateField validates that the data is either an abbreviation or name of a
-U.S. state.
->>> from django.contrib.localflavor.us.forms import USStateField
->>> f = USStateField()
->>> f.clean('il')
-u'IL'
->>> f.clean('IL')
-u'IL'
->>> f.clean('illinois')
-u'IL'
->>> f.clean(' illinois ')
-u'IL'
->>> f.clean(60606)
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a U.S. state or territory.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = USStateField(required=False)
->>> f.clean('il')
-u'IL'
->>> f.clean('IL')
-u'IL'
->>> f.clean('illinois')
-u'IL'
->>> f.clean(' illinois ')
-u'IL'
->>> f.clean(60606)
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a U.S. state or territory.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# USStateSelect ###############################################################
-
-USStateSelect is a Select widget that uses a list of U.S. states/territories
-as its choices.
->>> from django.contrib.localflavor.us.forms import USStateSelect
->>> w = USStateSelect()
->>> print w.render('state', 'IL')
-
-Alabama
-Alaska
-American Samoa
-Arizona
-Arkansas
-California
-Colorado
-Connecticut
-Delaware
-District of Columbia
-Federated States of Micronesia
-Florida
-Georgia
-Guam
-Hawaii
-Idaho
-Illinois
-Indiana
-Iowa
-Kansas
-Kentucky
-Louisiana
-Maine
-Marshall Islands
-Maryland
-Massachusetts
-Michigan
-Minnesota
-Mississippi
-Missouri
-Montana
-Nebraska
-Nevada
-New Hampshire
-New Jersey
-New Mexico
-New York
-North Carolina
-North Dakota
-Northern Mariana Islands
-Ohio
-Oklahoma
-Oregon
-Palau
-Pennsylvania
-Puerto Rico
-Rhode Island
-South Carolina
-South Dakota
-Tennessee
-Texas
-Utah
-Vermont
-Virgin Islands
-Virginia
-Washington
-West Virginia
-Wisconsin
-Wyoming
-
-
-# USSocialSecurityNumberField #################################################
->>> from django.contrib.localflavor.us.forms import USSocialSecurityNumberField
->>> f = USSocialSecurityNumberField()
->>> f.clean('987-65-4330')
-u'987-65-4330'
->>> f.clean('987654330')
-u'987-65-4330'
->>> f.clean('078-05-1120')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid U.S. Social Security number in XXX-XX-XXXX format.']
-
-# UKPostcodeField #############################################################
-
-UKPostcodeField validates that the data is a valid UK postcode.
->>> from django.contrib.localflavor.uk.forms import UKPostcodeField
->>> f = UKPostcodeField()
->>> f.clean('BT32 4PX')
-u'BT32 4PX'
->>> f.clean('GIR 0AA')
-u'GIR 0AA'
->>> f.clean('BT324PX')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
->>> f.clean('1NV 4L1D')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = UKPostcodeField(required=False)
->>> f.clean('BT32 4PX')
-u'BT32 4PX'
->>> f.clean('GIR 0AA')
-u'GIR 0AA'
->>> f.clean('1NV 4L1D')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
->>> f.clean('BT324PX')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# FRZipCodeField #############################################################
-
-FRZipCodeField validates that the data is a valid FR zipcode.
->>> from django.contrib.localflavor.fr.forms import FRZipCodeField
->>> f = FRZipCodeField()
->>> f.clean('75001')
-u'75001'
->>> f.clean('93200')
-u'93200'
->>> f.clean('2A200')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
->>> f.clean('980001')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = FRZipCodeField(required=False)
->>> f.clean('75001')
-u'75001'
->>> f.clean('93200')
-u'93200'
->>> f.clean('2A200')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
->>> f.clean('980001')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-
-# FRPhoneNumberField ##########################################################
-
-FRPhoneNumberField validates that the data is a valid french phone number.
-It's normalized to 0X XX XX XX XX format. Dots are valid too.
->>> from django.contrib.localflavor.fr.forms import FRPhoneNumberField
->>> f = FRPhoneNumberField()
->>> f.clean('01 55 44 58 64')
-u'01 55 44 58 64'
->>> f.clean('0155445864')
-u'01 55 44 58 64'
->>> f.clean('01 5544 5864')
-u'01 55 44 58 64'
->>> f.clean('01 55.44.58.64')
-u'01 55 44 58 64'
->>> f.clean('01.55.44.58.64')
-u'01 55 44 58 64'
->>> f.clean('01,55,44,58,64')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
->>> f.clean('555 015 544')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = FRPhoneNumberField(required=False)
->>> f.clean('01 55 44 58 64')
-u'01 55 44 58 64'
->>> f.clean('0155445864')
-u'01 55 44 58 64'
->>> f.clean('01 5544 5864')
-u'01 55 44 58 64'
->>> f.clean('01 55.44.58.64')
-u'01 55 44 58 64'
->>> f.clean('01.55.44.58.64')
-u'01 55 44 58 64'
->>> f.clean('01,55,44,58,64')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
->>> f.clean('555 015 544')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# FRDepartmentSelect ###############################################################
-
-FRDepartmentSelect is a Select widget that uses a list of french departments
-including DOM TOM
->>> from django.contrib.localflavor.fr.forms import FRDepartmentSelect
->>> w = FRDepartmentSelect()
->>> print w.render('dep', 'Paris')
-
-01 - Ain
-02 - Aisne
-03 - Allier
-04 - Alpes-de-Haute-Provence
-05 - Hautes-Alpes
-06 - Alpes-Maritimes
-07 - Ardeche
-08 - Ardennes
-09 - Ariege
-10 - Aube
-11 - Aude
-12 - Aveyron
-13 - Bouches-du-Rhone
-14 - Calvados
-15 - Cantal
-16 - Charente
-17 - Charente-Maritime
-18 - Cher
-19 - Correze
-21 - Cote-d'Or
-22 - Cotes-d'Armor
-23 - Creuse
-24 - Dordogne
-25 - Doubs
-26 - Drome
-27 - Eure
-28 - Eure-et-Loire
-29 - Finistere
-2A - Corse-du-Sud
-2B - Haute-Corse
-30 - Gard
-31 - Haute-Garonne
-32 - Gers
-33 - Gironde
-34 - Herault
-35 - Ille-et-Vilaine
-36 - Indre
-37 - Indre-et-Loire
-38 - Isere
-39 - Jura
-40 - Landes
-41 - Loir-et-Cher
-42 - Loire
-43 - Haute-Loire
-44 - Loire-Atlantique
-45 - Loiret
-46 - Lot
-47 - Lot-et-Garonne
-48 - Lozere
-49 - Maine-et-Loire
-50 - Manche
-51 - Marne
-52 - Haute-Marne
-53 - Mayenne
-54 - Meurthe-et-Moselle
-55 - Meuse
-56 - Morbihan
-57 - Moselle
-58 - Nievre
-59 - Nord
-60 - Oise
-61 - Orne
-62 - Pas-de-Calais
-63 - Puy-de-Dome
-64 - Pyrenees-Atlantiques
-65 - Hautes-Pyrenees
-66 - Pyrenees-Orientales
-67 - Bas-Rhin
-68 - Haut-Rhin
-69 - Rhone
-70 - Haute-Saone
-71 - Saone-et-Loire
-72 - Sarthe
-73 - Savoie
-74 - Haute-Savoie
-75 - Paris
-76 - Seine-Maritime
-77 - Seine-et-Marne
-78 - Yvelines
-79 - Deux-Sevres
-80 - Somme
-81 - Tarn
-82 - Tarn-et-Garonne
-83 - Var
-84 - Vaucluse
-85 - Vendee
-86 - Vienne
-87 - Haute-Vienne
-88 - Vosges
-89 - Yonne
-90 - Territoire de Belfort
-91 - Essonne
-92 - Hauts-de-Seine
-93 - Seine-Saint-Denis
-94 - Val-de-Marne
-95 - Val-d'Oise
-2A - Corse du sud
-2B - Haute Corse
-971 - Guadeloupe
-972 - Martinique
-973 - Guyane
-974 - La Reunion
-975 - Saint-Pierre-et-Miquelon
-976 - Mayotte
-984 - Terres Australes et Antarctiques
-986 - Wallis et Futuna
-987 - Polynesie Francaise
-988 - Nouvelle-Caledonie
-
-
-# JPPostalCodeField ###############################################################
-
-A form field that validates its input is a Japanese postcode.
-
-Accepts 7 digits(with/out hyphen).
->>> from django.contrib.localflavor.jp.forms import JPPostalCodeField
->>> f = JPPostalCodeField()
->>> f.clean('251-0032')
-u'2510032'
->>> f.clean('2510032')
-u'2510032'
->>> f.clean('2510-032')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
->>> f.clean('251a0032')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
->>> f.clean('a51-0032')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
->>> f.clean('25100321')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = JPPostalCodeField(required=False)
->>> f.clean('251-0032')
-u'2510032'
->>> f.clean('2510032')
-u'2510032'
->>> f.clean('2510-032')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
->>> f.clean('')
-u''
->>> f.clean(None)
-u''
-
-# JPPrefectureSelect ###############################################################
-
-A Select widget that uses a list of Japanese prefectures as its choices.
->>> from django.contrib.localflavor.jp.forms import JPPrefectureSelect
->>> w = JPPrefectureSelect()
->>> print w.render('prefecture', 'kanagawa')
-
-Hokkaido
-Aomori
-Iwate
-Miyagi
-Akita
-Yamagata
-Fukushima
-Ibaraki
-Tochigi
-Gunma
-Saitama
-Chiba
-Tokyo
-Kanagawa
-Yamanashi
-Nagano
-Niigata
-Toyama
-Ishikawa
-Fukui
-Gifu
-Shizuoka
-Aichi
-Mie
-Shiga
-Kyoto
-Osaka
-Hyogo
-Nara
-Wakayama
-Tottori
-Shimane
-Okayama
-Hiroshima
-Yamaguchi
-Tokushima
-Kagawa
-Ehime
-Kochi
-Fukuoka
-Saga
-Nagasaki
-Kumamoto
-Oita
-Miyazaki
-Kagoshima
-Okinawa
-
-
-# ITZipCodeField #############################################################
-
->>> from django.contrib.localflavor.it.forms import ITZipCodeField
->>> f = ITZipCodeField()
->>> f.clean('00100')
-u'00100'
->>> f.clean(' 00100')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid zip code.']
-
-# ITRegionSelect #############################################################
-
->>> from django.contrib.localflavor.it.forms import ITRegionSelect
->>> w = ITRegionSelect()
->>> w.render('regions', 'PMN')
-u'\nAbruzzo \nBasilicata \nCalabria \nCampania \nEmilia-Romagna \nFriuli-Venezia Giulia \nLazio \nLiguria \nLombardia \nMarche \nMolise \nPiemonte \nPuglia \nSardegna \nSicilia \nToscana \nTrentino-Alto Adige \nUmbria \nValle d\u2019Aosta \nVeneto \n '
-
-# ITSocialSecurityNumberField #################################################
-
->>> from django.contrib.localflavor.it.forms import ITSocialSecurityNumberField
->>> f = ITSocialSecurityNumberField()
->>> f.clean('LVSGDU99T71H501L')
-u'LVSGDU99T71H501L'
->>> f.clean('LBRRME11A01L736W')
-u'LBRRME11A01L736W'
->>> f.clean('lbrrme11a01l736w')
-u'LBRRME11A01L736W'
->>> f.clean('LBR RME 11A01 L736W')
-u'LBRRME11A01L736W'
->>> f.clean('LBRRME11A01L736A')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Social Security number.']
->>> f.clean('%BRRME11A01L736W')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Social Security number.']
-
-# ITVatNumberField ###########################################################
-
->>> from django.contrib.localflavor.it.forms import ITVatNumberField
->>> f = ITVatNumberField()
->>> f.clean('07973780013')
-u'07973780013'
->>> f.clean('7973780013')
-u'07973780013'
->>> f.clean(7973780013)
-u'07973780013'
->>> f.clean('07973780014')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid VAT number.']
->>> f.clean('A7973780013')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid VAT number.']
-
-# FIZipCodeField #############################################################
-
-FIZipCodeField validates that the data is a valid FI zipcode.
->>> from django.contrib.localflavor.fi.forms import FIZipCodeField
->>> f = FIZipCodeField()
->>> f.clean('20540')
-u'20540'
->>> f.clean('20101')
-u'20101'
->>> f.clean('20s40')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
->>> f.clean('205401')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = FIZipCodeField(required=False)
->>> f.clean('20540')
-u'20540'
->>> f.clean('20101')
-u'20101'
->>> f.clean('20s40')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
->>> f.clean('205401')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# FIMunicipalitySelect ###############################################################
-
-A Select widget that uses a list of Finnish municipalities as its choices.
->>> from django.contrib.localflavor.fi.forms import FIMunicipalitySelect
->>> w = FIMunicipalitySelect()
->>> unicode(w.render('municipalities', 'turku'))
-u'\nAkaa \nAlah\xe4rm\xe4 \nAlaj\xe4rvi \nAlastaro \nAlavieska \nAlavus \nAnjalankoski \nArtj\xe4rvi \nAsikkala \nAskainen \nAskola \nAura \nBr\xe4nd\xf6 \nDragsfj\xe4rd \nEcker\xf6 \nElim\xe4ki \nEno \nEnonkoski \nEnonteki\xf6 \nEspoo \nEura \nEurajoki \nEvij\xe4rvi \nFinstr\xf6m \nForssa \nF\xf6gl\xf6 \nGeta \nHaapaj\xe4rvi \nHaapavesi \nHailuoto \nHalikko \nHalsua \nHamina \nHammarland \nHankasalmi \nHanko \nHarjavalta \nHartola \nHattula \nHauho \nHaukipudas \nHausj\xe4rvi \nHeinola \nHein\xe4vesi \nHelsinki \nHimanka \nHirvensalmi \nHollola \nHonkajoki \nHoutskari \nHuittinen \nHumppila \nHyrynsalmi \nHyvink\xe4\xe4 \nH\xe4meenkoski \nH\xe4meenkyr\xf6 \nH\xe4meenlinna \nIi \nIisalmi \nIitti \nIkaalinen \nIlmajoki \nIlomantsi \nImatra \nInari \nIni\xf6 \nInkoo \nIsojoki \nIsokyr\xf6 \nJaala \nJalasj\xe4rvi \nJanakkala \nJoensuu \nJokioinen \nJomala \nJoroinen \nJoutsa \nJoutseno \nJuankoski \nJurva \nJuuka \nJuupajoki \nJuva \nJyv\xe4skyl\xe4 \nJyv\xe4skyl\xe4n maalaiskunta \nJ\xe4mij\xe4rvi \nJ\xe4ms\xe4 \nJ\xe4ms\xe4nkoski \nJ\xe4rvenp\xe4\xe4 \nKaarina \nKaavi \nKajaani \nKalajoki \nKalvola \nKangasala \nKangasniemi \nKankaanp\xe4\xe4 \nKannonkoski \nKannus \nKarijoki \nKarjaa \nKarjalohja \nKarkkila \nKarstula \nKarttula \nKarvia \nKaskinen \nKauhajoki \nKauhava \nKauniainen \nKaustinen \nKeitele \nKemi \nKemij\xe4rvi \nKeminmaa \nKemi\xf6 \nKempele \nKerava \nKerim\xe4ki \nKestil\xe4 \nKes\xe4lahti \nKeuruu \nKihni\xf6 \nKiikala \nKiikoinen \nKiiminki \nKinnula \nKirkkonummi \nKisko \nKitee \nKittil\xe4 \nKiukainen \nKiuruvesi \nKivij\xe4rvi \nKokem\xe4ki \nKokkola \nKolari \nKonnevesi \nKontiolahti \nKorpilahti \nKorppoo \nKorsn\xe4s \nKortesj\xe4rvi \nKoskiTl \nKotka \nKouvola \nKristiinankaupunki \nKruunupyy \nKuhmalahti \nKuhmo \nKuhmoinen \nKumlinge \nKuopio \nKuortane \nKurikka \nKuru \nKustavi \nKuusamo \nKuusankoski \nKuusjoki \nKylm\xe4koski \nKyyj\xe4rvi \nK\xe4lvi\xe4 \nK\xe4rk\xf6l\xe4 \nK\xe4rs\xe4m\xe4ki \nK\xf6kar \nK\xf6yli\xf6 \nLahti \nLaihia \nLaitila \nLammi \nLapinj\xe4rvi \nLapinlahti \nLappaj\xe4rvi \nLappeenranta \nLappi \nLapua \nLaukaa \nLavia \nLehtim\xe4ki \nLeivonm\xe4ki \nLemi \nLemland \nLemp\xe4\xe4l\xe4 \nLemu \nLepp\xe4virta \nLestij\xe4rvi \nLieksa \nLieto \nLiljendal \nLiminka \nLiperi \nLohja \nLohtaja \nLoimaa \nLoppi \nLoviisa \nLuhanka \nLumijoki \nLumparland \nLuoto \nLuum\xe4ki \nLuvia \nMaalahti \nMaaninka \nMaarianhamina \nMarttila \nMasku \nMellil\xe4 \nMerij\xe4rvi \nMerikarvia \nMerimasku \nMiehikk\xe4l\xe4 \nMikkeli \nMouhij\xe4rvi \nMuhos \nMultia \nMuonio \nMustasaari \nMuurame \nMuurla \nMyn\xe4m\xe4ki \nMyrskyl\xe4 \nM\xe4nts\xe4l\xe4 \nM\xe4ntt\xe4 \nM\xe4ntyharju \nNaantali \nNakkila \nNastola \nNauvo \nNilsi\xe4 \nNivala \nNokia \nNoormarkku \nNousiainen \nNummi-Pusula \nNurmes \nNurmij\xe4rvi \nNurmo \nN\xe4rpi\xf6 \nOravainen \nOrimattila \nOrip\xe4\xe4 \nOrivesi \nOulainen \nOulu \nOulunsalo \nOutokumpu \nPadasjoki \nPaimio \nPaltamo \nParainen \nParikkala \nParkano \nPeders\xf6re \nPelkosenniemi \nPello \nPerho \nPernaja \nPerni\xf6 \nPertteli \nPertunmaa \nPet\xe4j\xe4vesi \nPieks\xe4m\xe4ki \nPielavesi \nPietarsaari \nPihtipudas \nPiikki\xf6 \nPiippola \nPirkkala \nPohja \nPolvij\xe4rvi \nPomarkku \nPori \nPornainen \nPorvoo \nPosio \nPudasj\xe4rvi \nPukkila \nPulkkila \nPunkaharju \nPunkalaidun \nPuolanka \nPuumala \nPyht\xe4\xe4 \nPyh\xe4joki \nPyh\xe4j\xe4rvi \nPyh\xe4nt\xe4 \nPyh\xe4ranta \nPyh\xe4selk\xe4 \nPylk\xf6nm\xe4ki \nP\xe4lk\xe4ne \nP\xf6yty\xe4 \nRaahe \nRaisio \nRantasalmi \nRantsila \nRanua \nRauma \nRautalampi \nRautavaara \nRautj\xe4rvi \nReisj\xe4rvi \nRenko \nRiihim\xe4ki \nRistiina \nRistij\xe4rvi \nRovaniemi \nRuokolahti \nRuotsinpyht\xe4\xe4 \nRuovesi \nRusko \nRym\xe4ttyl\xe4 \nR\xe4\xe4kkyl\xe4 \nSaarij\xe4rvi \nSalla \nSalo \nSaltvik \nSammatti \nSauvo \nSavitaipale \nSavonlinna \nSavonranta \nSavukoski \nSein\xe4joki \nSievi \nSiikainen \nSiikajoki \nSiilinj\xe4rvi \nSimo \nSipoo \nSiuntio \nSodankyl\xe4 \nSoini \nSomero \nSonkaj\xe4rvi \nSotkamo \nSottunga \nSulkava \nSund \nSuomenniemi \nSuomusj\xe4rvi \nSuomussalmi \nSuonenjoki \nSysm\xe4 \nS\xe4kyl\xe4 \nS\xe4rkisalo \nTaipalsaari \nTaivalkoski \nTaivassalo \nTammela \nTammisaari \nTampere \nTarvasjoki \nTervo \nTervola \nTeuva \nTohmaj\xe4rvi \nToholampi \nToivakka \nTornio \nTurku \nTuulos \nTuusniemi \nTuusula \nTyrn\xe4v\xe4 \nT\xf6ys\xe4 \nUllava \nUlvila \nUrjala \nUtaj\xe4rvi \nUtsjoki \nUurainen \nUusikaarlepyy \nUusikaupunki \nVaala \nVaasa \nVahto \nValkeakoski \nValkeala \nValtimo \nVammala \nVampula \nVantaa \nVarkaus \nVarpaisj\xe4rvi \nVehmaa \nVelkua \nVesanto \nVesilahti \nVeteli \nVierem\xe4 \nVihanti \nVihti \nViitasaari \nVilppula \nVimpeli \nVirolahti \nVirrat \nV\xe5rd\xf6 \nV\xe4h\xe4kyr\xf6 \nV\xe4stanfj\xe4rd \nV\xf6yri-Maksamaa \nYlih\xe4rm\xe4 \nYli-Ii \nYlikiiminki \nYlistaro \nYlitornio \nYlivieska \nYl\xe4maa \nYl\xe4ne \nYl\xf6j\xe4rvi \nYp\xe4j\xe4 \n\xc4ets\xe4 \n\xc4ht\xe4ri \n\xc4\xe4nekoski \n '
-
-# FISocialSecurityNumber
-##############################################################
-
->>> from django.contrib.localflavor.fi.forms import FISocialSecurityNumber
->>> f = FISocialSecurityNumber()
->>> f.clean('010101-0101')
-u'010101-0101'
->>> f.clean('010101+0101')
-u'010101+0101'
->>> f.clean('010101A0101')
-u'010101A0101'
->>> f.clean('101010-0102')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Finnish social security number.']
->>> f.clean('10a010-0101')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Finnish social security number.']
->>> f.clean('101010-0\xe401')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Finnish social security number.']
->>> f.clean('101010b0101')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Finnish social security number.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f = FISocialSecurityNumber(required=False)
->>> f.clean('010101-0101')
-u'010101-0101'
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# BRZipCodeField ############################################################
->>> from django.contrib.localflavor.br.forms import BRZipCodeField
->>> f = BRZipCodeField()
->>> f.clean('12345-123')
-u'12345-123'
->>> f.clean('12345_123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('1234-123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('abcde-abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('12345-')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('-123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = BRZipCodeField(required=False)
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
->>> f.clean('-123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('12345-')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('abcde-abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('1234-123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('12345_123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
->>> f.clean('12345-123')
-u'12345-123'
-
-# BRCNPJField ############################################################
-
->>> from django.contrib.localflavor.br.forms import BRCNPJField
->>> f = BRCNPJField(required=True)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('12-345-678/9012-10')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CNPJ number.']
->>> f.clean('12.345.678/9012-10')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CNPJ number.']
->>> f.clean('12345678/9012-10')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CNPJ number.']
->>> f.clean('64.132.916/0001-88')
-'64.132.916/0001-88'
->>> f.clean('64-132-916/0001-88')
-'64-132-916/0001-88'
->>> f.clean('64132916/0001-88')
-'64132916/0001-88'
->>> f.clean('64.132.916/0001-XX')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires only numbers.']
->>> f = BRCNPJField(required=False)
->>> f.clean('')
-u''
-
-# BRCPFField #################################################################
-
->>> from django.contrib.localflavor.br.forms import BRCPFField
->>> f = BRCPFField()
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('489.294.654-54')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CPF number.']
->>> f.clean('295.669.575-98')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CPF number.']
->>> f.clean('539.315.127-22')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CPF number.']
->>> f.clean('663.256.017-26')
-u'663.256.017-26'
->>> f.clean('66325601726')
-u'66325601726'
->>> f.clean('375.788.573-20')
-u'375.788.573-20'
->>> f.clean('84828509895')
-u'84828509895'
->>> f.clean('375.788.573-XX')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires only numbers.']
->>> f.clean('375.788.573-000')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 14 characters (it has 15).']
->>> f.clean('123.456.78')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 11 characters (it has 10).']
->>> f.clean('123456789555')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires at most 11 digits or 14 characters.']
->>> f = BRCPFField(required=False)
->>> f.clean('')
-u''
->>> f.clean(None)
-u''
-
-# BRPhoneNumberField #########################################################
-
->>> from django.contrib.localflavor.br.forms import BRPhoneNumberField
->>> f = BRPhoneNumberField()
->>> f.clean('41-3562-3464')
-u'41-3562-3464'
->>> f.clean('4135623464')
-u'41-3562-3464'
->>> f.clean('41 3562-3464')
-u'41-3562-3464'
->>> f.clean('41 3562 3464')
-u'41-3562-3464'
->>> f.clean('(41) 3562 3464')
-u'41-3562-3464'
->>> f.clean('41.3562.3464')
-u'41-3562-3464'
->>> f.clean('41.3562-3464')
-u'41-3562-3464'
->>> f.clean(' (41) 3562.3464')
-u'41-3562-3464'
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = BRPhoneNumberField(required=False)
->>> f.clean('')
-u''
->>> f.clean(None)
-u''
->>> f.clean(' (41) 3562.3464')
-u'41-3562-3464'
->>> f.clean('41.3562-3464')
-u'41-3562-3464'
->>> f.clean('(41) 3562 3464')
-u'41-3562-3464'
->>> f.clean('4135623464')
-u'41-3562-3464'
->>> f.clean('41 3562-3464')
-u'41-3562-3464'
-
-# BRStateSelect ##############################################################
-
->>> from django.contrib.localflavor.br.forms import BRStateSelect
->>> w = BRStateSelect()
->>> w.render('states', 'PR')
-u'\nAcre \nAlagoas \nAmap\xe1 \nAmazonas \nBahia \nCear\xe1 \nDistrito Federal \nEsp\xedrito Santo \nGoi\xe1s \nMaranh\xe3o \nMato Grosso \nMato Grosso do Sul \nMinas Gerais \nPar\xe1 \nPara\xedba \nParan\xe1 \nPernambuco \nPiau\xed \nRio de Janeiro \nRio Grande do Norte \nRio Grande do Sul \nRond\xf4nia \nRoraima \nSanta Catarina \nS\xe3o Paulo \nSergipe \nTocantins \n '
-
-# BRStateChoiceField #########################################################
->>> from django.contrib.localflavor.br.forms import BRStateChoiceField
->>> f = BRStateChoiceField()
->>> ', '.join([f.clean(s) for s, _ in f.widget.choices])
-u'AC, AL, AP, AM, BA, CE, DF, ES, GO, MA, MT, MS, MG, PA, PB, PR, PE, PI, RJ, RN, RS, RO, RR, SC, SP, SE, TO'
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('pr')
-Traceback (most recent call last):
-...
-ValidationError: [u'Select a valid brazilian state. That state is not one of the available states.']
-
-# DEZipCodeField ##############################################################
-
->>> from django.contrib.localflavor.de.forms import DEZipCodeField
->>> f = DEZipCodeField()
->>> f.clean('99423')
-u'99423'
->>> f.clean(' 99423')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXXX.']
-
-# DEStateSelect #############################################################
-
->>> from django.contrib.localflavor.de.forms import DEStateSelect
->>> w = DEStateSelect()
->>> w.render('states', 'TH')
-u'\nBaden-Wuerttemberg \nBavaria \nBerlin \nBrandenburg \nBremen \nHamburg \nHessen \nMecklenburg-Western Pomerania \nLower Saxony \nNorth Rhine-Westphalia \nRhineland-Palatinate \nSaarland \nSaxony \nSaxony-Anhalt \nSchleswig-Holstein \nThuringia \n '
-
-# DEIdentityCardNumberField #################################################
-
->>> from django.contrib.localflavor.de.forms import DEIdentityCardNumberField
->>> f = DEIdentityCardNumberField()
->>> f.clean('7549313035D-6004103-0903042-0')
-u'7549313035D-6004103-0903042-0'
->>> f.clean('9786324830D 6104243 0910271 2')
-u'9786324830D-6104243-0910271-2'
->>> f.clean('0434657485D-6407276-0508137-9')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.']
-
-# CHZipCodeField ############################################################
-
->>> from django.contrib.localflavor.ch.forms import CHZipCodeField
->>> f = CHZipCodeField()
->>> f.clean('800x')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXX.']
->>> f.clean('80 00')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a zip code in the format XXXX.']
->>> f.clean('8000')
-u'8000'
-
-# CHPhoneNumberField ########################################################
-
->>> from django.contrib.localflavor.ch.forms import CHPhoneNumberField
->>> f = CHPhoneNumberField()
->>> f.clean('01234567890')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
->>> f.clean('1234567890')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
->>> f.clean('0123456789')
-u'012 345 67 89'
-
-# CHIdentityCardNumberField #################################################
-
->>> from django.contrib.localflavor.ch.forms import CHIdentityCardNumberField
->>> f = CHIdentityCardNumberField()
->>> f.clean('C1234567<0')
-u'C1234567<0'
->>> f.clean('C1234567<1')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.']
->>> f.clean('2123456700')
-u'2123456700'
->>> f.clean('2123456701')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.']
-
-# CHStateSelect #############################################################
-
->>> from django.contrib.localflavor.ch.forms import CHStateSelect
->>> w = CHStateSelect()
->>> w.render('state', 'AG')
-u'\nAargau \nAppenzell Innerrhoden \nAppenzell Ausserrhoden \nBasel-Stadt \nBasel-Land \nBerne \nFribourg \nGeneva \nGlarus \nGraubuenden \nJura \nLucerne \nNeuchatel \nNidwalden \nObwalden \nSchaffhausen \nSchwyz \nSolothurn \nSt. Gallen \nThurgau \nTicino \nUri \nValais \nVaud \nZug \nZurich \n '
-
-## AUPostCodeField ##########################################################
-
-A field that accepts a four digit Australian post code.
-
->>> from django.contrib.localflavor.au.forms import AUPostCodeField
->>> f = AUPostCodeField()
->>> f.clean('1234')
-u'1234'
->>> f.clean('2000')
-u'2000'
->>> f.clean('abcd')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a 4 digit post code.']
->>> f.clean('20001')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a 4 digit post code.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = AUPostCodeField(required=False)
->>> f.clean('1234')
-u'1234'
->>> f.clean('2000')
-u'2000'
->>> f.clean('abcd')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a 4 digit post code.']
->>> f.clean('20001')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a 4 digit post code.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-## AUPhoneNumberField ########################################################
-
-A field that accepts a 10 digit Australian phone number.
-llows spaces and parentheses around area code.
-
->>> from django.contrib.localflavor.au.forms import AUPhoneNumberField
->>> f = AUPhoneNumberField()
->>> f.clean('1234567890')
-u'1234567890'
->>> f.clean('0213456789')
-u'0213456789'
->>> f.clean('02 13 45 67 89')
-u'0213456789'
->>> f.clean('(02) 1345 6789')
-u'0213456789'
->>> f.clean('(02) 1345-6789')
-u'0213456789'
->>> f.clean('(02)1345-6789')
-u'0213456789'
->>> f.clean('0408 123 456')
-u'0408123456'
->>> f.clean('123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must contain 10 digits.']
->>> f.clean('1800DJANGO')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must contain 10 digits.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = AUPhoneNumberField(required=False)
->>> f.clean('1234567890')
-u'1234567890'
->>> f.clean('0213456789')
-u'0213456789'
->>> f.clean('02 13 45 67 89')
-u'0213456789'
->>> f.clean('(02) 1345 6789')
-u'0213456789'
->>> f.clean('(02) 1345-6789')
-u'0213456789'
->>> f.clean('(02)1345-6789')
-u'0213456789'
->>> f.clean('0408 123 456')
-u'0408123456'
->>> f.clean('123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must contain 10 digits.']
->>> f.clean('1800DJANGO')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must contain 10 digits.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-## AUStateSelect #############################################################
-
-AUStateSelect is a Select widget that uses a list of Australian
-states/territories as its choices.
-
->>> from django.contrib.localflavor.au.forms import AUStateSelect
->>> f = AUStateSelect()
->>> print f.render('state', 'NSW')
-
-Australian Capital Territory
-New South Wales
-Northern Territory
-Queensland
-South Australia
-Tasmania
-Victoria
-Western Australia
-
-
-## ISIdNumberField #############################################################
-
->>> from django.contrib.localflavor.is_.forms import *
->>> f = ISIdNumberField()
->>> f.clean('2308803449')
-u'230880-3449'
->>> f.clean('230880-3449')
-u'230880-3449'
->>> f.clean('230880 3449')
-u'230880-3449'
->>> f.clean('230880343')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 10 characters (it has 9).']
->>> f.clean('230880343234')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 11 characters (it has 12).']
->>> f.clean('abcdefghijk')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('2308803439')
-Traceback (most recent call last):
-...
-ValidationError: [u'The Icelandic identification number is not valid.']
->>> f.clean('2308803440')
-u'230880-3440'
->>> f = ISIdNumberField(required=False)
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-## ISPhoneNumberField #############################################################
-
->>> from django.contrib.localflavor.is_.forms import *
->>> f = ISPhoneNumberField()
->>> f.clean('1234567')
-u'1234567'
->>> f.clean('123 4567')
-u'1234567'
->>> f.clean('123-4567')
-u'1234567'
->>> f.clean('123-456')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
->>> f.clean('123456')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 7 characters (it has 6).']
->>> f.clean('123456555')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
->>> f.clean('abcdefg')
-Traceback (most recent call last):
-ValidationError: [u'Enter a valid value.']
->>> f.clean(' 1234567 ')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
->>> f.clean(' 12367 ')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
-
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f = ISPhoneNumberField(required=False)
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-## ISPostalCodeSelect #############################################################
-
->>> from django.contrib.localflavor.is_.forms import *
->>> f = ISPostalCodeSelect()
-
->>> f.render('foo', 'bar')
-u'\n101 Reykjav\xedk \n103 Reykjav\xedk \n104 Reykjav\xedk \n105 Reykjav\xedk \n107 Reykjav\xedk \n108 Reykjav\xedk \n109 Reykjav\xedk \n110 Reykjav\xedk \n111 Reykjav\xedk \n112 Reykjav\xedk \n113 Reykjav\xedk \n116 Kjalarnes \n121 Reykjav\xedk \n123 Reykjav\xedk \n124 Reykjav\xedk \n125 Reykjav\xedk \n127 Reykjav\xedk \n128 Reykjav\xedk \n129 Reykjav\xedk \n130 Reykjav\xedk \n132 Reykjav\xedk \n150 Reykjav\xedk \n155 Reykjav\xedk \n170 Seltjarnarnes \n172 Seltjarnarnes \n190 Vogar \n200 K\xf3pavogur \n201 K\xf3pavogur \n202 K\xf3pavogur \n203 K\xf3pavogur \n210 Gar\xf0ab\xe6r \n212 Gar\xf0ab\xe6r \n220 Hafnarfj\xf6r\xf0ur \n221 Hafnarfj\xf6r\xf0ur \n222 Hafnarfj\xf6r\xf0ur \n225 \xc1lftanes \n230 Reykjanesb\xe6r \n232 Reykjanesb\xe6r \n233 Reykjanesb\xe6r \n235 Keflav\xedkurflugv\xf6llur \n240 Grindav\xedk \n245 Sandger\xf0i \n250 Gar\xf0ur \n260 Reykjanesb\xe6r \n270 Mosfellsb\xe6r \n300 Akranes \n301 Akranes \n302 Akranes \n310 Borgarnes \n311 Borgarnes \n320 Reykholt \xed Borgarfir\xf0i \n340 Stykkish\xf3lmur \n345 Flatey \xe1 Brei\xf0afir\xf0i \n350 Grundarfj\xf6r\xf0ur \n355 \xd3lafsv\xedk \n356 Sn\xe6fellsb\xe6r \n360 Hellissandur \n370 B\xfa\xf0ardalur \n371 B\xfa\xf0ardalur \n380 Reykh\xf3lahreppur \n400 \xcdsafj\xf6r\xf0ur \n401 \xcdsafj\xf6r\xf0ur \n410 Hn\xedfsdalur \n415 Bolungarv\xedk \n420 S\xfa\xf0av\xedk \n425 Flateyri \n430 Su\xf0ureyri \n450 Patreksfj\xf6r\xf0ur \n451 Patreksfj\xf6r\xf0ur \n460 T\xe1lknafj\xf6r\xf0ur \n465 B\xedldudalur \n470 \xdeingeyri \n471 \xdeingeyri \n500 Sta\xf0ur \n510 H\xf3lmav\xedk \n512 H\xf3lmav\xedk \n520 Drangsnes \n522 Kj\xf6rvogur \n523 B\xe6r \n524 Nor\xf0urfj\xf6r\xf0ur \n530 Hvammstangi \n531 Hvammstangi \n540 Bl\xf6ndu\xf3s \n541 Bl\xf6ndu\xf3s \n545 Skagastr\xf6nd \n550 Sau\xf0\xe1rkr\xf3kur \n551 Sau\xf0\xe1rkr\xf3kur \n560 Varmahl\xed\xf0 \n565 Hofs\xf3s \n566 Hofs\xf3s \n570 Flj\xf3t \n580 Siglufj\xf6r\xf0ur \n600 Akureyri \n601 Akureyri \n602 Akureyri \n603 Akureyri \n610 Greniv\xedk \n611 Gr\xedmsey \n620 Dalv\xedk \n621 Dalv\xedk \n625 \xd3lafsfj\xf6r\xf0ur \n630 Hr\xedsey \n640 H\xfasav\xedk \n641 H\xfasav\xedk \n645 Fossh\xf3ll \n650 Laugar \n660 M\xfdvatn \n670 K\xf3pasker \n671 K\xf3pasker \n675 Raufarh\xf6fn \n680 \xde\xf3rsh\xf6fn \n681 \xde\xf3rsh\xf6fn \n685 Bakkafj\xf6r\xf0ur \n690 Vopnafj\xf6r\xf0ur \n700 Egilssta\xf0ir \n701 Egilssta\xf0ir \n710 Sey\xf0isfj\xf6r\xf0ur \n715 Mj\xf3ifj\xf6r\xf0ur \n720 Borgarfj\xf6r\xf0ur eystri \n730 Rey\xf0arfj\xf6r\xf0ur \n735 Eskifj\xf6r\xf0ur \n740 Neskaupsta\xf0ur \n750 F\xe1skr\xfa\xf0sfj\xf6r\xf0ur \n755 St\xf6\xf0varfj\xf6r\xf0ur \n760 Brei\xf0dalsv\xedk \n765 Dj\xfapivogur \n780 H\xf6fn \xed Hornafir\xf0i \n781 H\xf6fn \xed Hornafir\xf0i \n785 \xd6r\xe6fi \n800 Selfoss \n801 Selfoss \n802 Selfoss \n810 Hverager\xf0i \n815 \xdeorl\xe1ksh\xf6fn \n820 Eyrarbakki \n825 Stokkseyri \n840 Laugarvatn \n845 Fl\xfa\xf0ir \n850 Hella \n851 Hella \n860 Hvolsv\xf6llur \n861 Hvolsv\xf6llur \n870 V\xedk \n871 V\xedk \n880 Kirkjub\xe6jarklaustur \n900 Vestmannaeyjar \n902 Vestmannaeyjar \n '
-
-## CLRutField #############################################################
-
-CLRutField is a Field that checks the validity of the Chilean
-personal identification number (RUT). It has two modes relaxed (default) and
-strict.
-
->>> from django.contrib.localflavor.cl.forms import CLRutField
->>> rut = CLRutField()
-
->>> rut.clean('11-6')
-u'11-6'
->>> rut.clean('116')
-u'11-6'
-
-# valid format, bad verifier.
->>> rut.clean('11.111.111-0')
-Traceback (most recent call last):
-...
-ValidationError: [u'The Chilean RUT is not valid.']
->>> rut.clean('111')
-Traceback (most recent call last):
-...
-ValidationError: [u'The Chilean RUT is not valid.']
-
->>> rut.clean('767484100')
-u'76.748.410-0'
->>> rut.clean('78.412.790-7')
-u'78.412.790-7'
->>> rut.clean('8.334.6043')
-u'8.334.604-3'
->>> rut.clean('76793310-K')
-u'76.793.310-K'
-
-Strict RUT usage (does not allow imposible values)
->>> rut = CLRutField(strict=True)
-
->>> rut.clean('11-6')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
-
-# valid format, bad verifier.
->>> rut.clean('11.111.111-0')
-Traceback (most recent call last):
-...
-ValidationError: [u'The Chilean RUT is not valid.']
-
-# Correct input, invalid format.
->>> rut.clean('767484100')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
->>> rut.clean('78.412.790-7')
-u'78.412.790-7'
->>> rut.clean('8.334.6043')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
->>> rut.clean('76793310-K')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
-
-## CLRegionSelect #########################################################
->>> from django.contrib.localflavor.cl.forms import CLRegionSelect
->>> f = CLRegionSelect()
-
->>> f.render('foo', 'bar')
-u'\nRegi\xf3n Metropolitana de Santiago \nRegi\xf3n de Tarapac\xe1 \nRegi\xf3n de Antofagasta \nRegi\xf3n de Atacama \nRegi\xf3n de Coquimbo \nRegi\xf3n de Valpara\xedso \nRegi\xf3n del Libertador Bernardo O'Higgins \nRegi\xf3n del Maule \nRegi\xf3n del B\xedo B\xedo \nRegi\xf3n de la Araucan\xeda \nRegi\xf3n de los Lagos \nRegi\xf3n de Ays\xe9n del General Carlos Ib\xe1\xf1ez del Campo \nRegi\xf3n de Magallanes y la Ant\xe1rtica Chilena \nRegi\xf3n de Los R\xedos \nRegi\xf3n de Arica-Parinacota \n '
-
-# SKPostalCodeField #########################################################
-
->>> from django.contrib.localflavor.sk.forms import SKPostalCodeField
->>> f = SKPostalCodeField()
->>> f.clean('84545x')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXXXX or XXX XX.']
->>> f.clean('91909')
-u'91909'
->>> f.clean('917 01')
-u'91701'
-
-# SKRegionSelect ############################################################
-
->>> from django.contrib.localflavor.sk.forms import SKRegionSelect
->>> w = SKRegionSelect()
->>> w.render('regions', 'TT')
-u'\nBanska Bystrica region \nBratislava region \nKosice region \nNitra region \nPresov region \nTrencin region \nTrnava region \nZilina region \n '
-
-# SKDistrictSelect ##########################################################
-
->>> from django.contrib.localflavor.sk.forms import SKDistrictSelect
->>> w = SKDistrictSelect()
->>> w.render('Districts', 'RK')
-u'\nBanska Bystrica \nBanska Stiavnica \nBardejov \nBanovce nad Bebravou \nBrezno \nBratislava I \nBratislava II \nBratislava III \nBratislava IV \nBratislava V \nBytca \nCadca \nDetva \nDolny Kubin \nDunajska Streda \nGalanta \nGelnica \nHlohovec \nHumenne \nIlava \nKezmarok \nKomarno \nKosice I \nKosice II \nKosice III \nKosice IV \nKosice - okolie \nKrupina \nKysucke Nove Mesto \nLevice \nLevoca \nLiptovsky Mikulas \nLucenec \nMalacky \nMartin \nMedzilaborce \nMichalovce \nMyjava \nNamestovo \nNitra \nNove Mesto nad Vahom \nNove Zamky \nPartizanske \nPezinok \nPiestany \nPoltar \nPoprad \nPovazska Bystrica \nPresov \nPrievidza \nPuchov \nRevuca \nRimavska Sobota \nRoznava \nRuzomberok \nSabinov \nSenec \nSenica \nSkalica \nSnina \nSobrance \nSpisska Nova Ves \nStara Lubovna \nStropkov \nSvidnik \nSala \nTopolcany \nTrebisov \nTrencin \nTrnava \nTurcianske Teplice \nTvrdosin \nVelky Krtis \nVranov nad Toplou \nZlate Moravce \nZvolen \nZarnovica \nZiar nad Hronom \nZilina \n '
-
-# PLVoivodeshipSelect ##########################################################
-
->>> from django.contrib.localflavor.pl.forms import PLVoivodeshipSelect
->>> f = PLVoivodeshipSelect()
->>> f.render('voivodeships','pomerania')
-u'\nLower Silesia \nKuyavia-Pomerania \nLublin \nLubusz \nLodz \nLesser Poland \nMasovia \nOpole \nSubcarpatia \nPodlasie \nPomerania \nSilesia \nSwietokrzyskie \nWarmia-Masuria \nGreater Poland \nWest Pomerania \n '
-
-# PLAdministrativeUnitSelect ##########################################################
-
->>> from django.contrib.localflavor.pl.forms import PLAdministrativeUnitSelect
->>> f = PLAdministrativeUnitSelect()
->>> f.render('administrativeunit','katowice')
-u'\nWroc\u0142aw \nJelenia G\xf3ra \nLegnica \nboles\u0142awiecki \ndzier\u017coniowski \ng\u0142ogowski \ng\xf3rowski \njaworski \njeleniog\xf3rski \nkamiennog\xf3rski \nk\u0142odzki \nlegnicki \nluba\u0144ski \nlubi\u0144ski \nlw\xf3wecki \nmilicki \nole\u015bnicki \no\u0142awski \npolkowicki \nstrzeli\u0144ski \n\u015bredzki \n\u015bwidnicki \ntrzebnicki \nwa\u0142brzyski \nwo\u0142owski \nwroc\u0142awski \nz\u0105bkowicki \nzgorzelecki \nz\u0142otoryjski \nBydgoszcz \nToru\u0144 \nW\u0142oc\u0142awek \nGrudzi\u0105dz \naleksandrowski \nbrodnicki \nbydgoski \nche\u0142mi\u0144ski \ngolubsko-dobrzy\u0144ski \ngrudzi\u0105dzki \ninowroc\u0142awski \nlipnowski \nmogile\u0144ski \nnakielski \nradziejowski \nrypi\u0144ski \ns\u0119pole\u0144ski \n\u015bwiecki \ntoru\u0144ski \ntucholski \nw\u0105brzeski \nwroc\u0142awski \n\u017ani\u0144ski \nLublin \nBia\u0142a Podlaska \nChe\u0142m \nZamo\u015b\u0107 \nbialski \nbi\u0142gorajski \nche\u0142mski \nhrubieszowski \njanowski \nkrasnostawski \nkra\u015bnicki \nlubartowski \nlubelski \n\u0142\u0119czy\u0144ski \n\u0142ukowski \nopolski \nparczewski \npu\u0142awski \nradzy\u0144ski \nrycki \n\u015bwidnicki \ntomaszowski \nw\u0142odawski \nzamojski \nGorz\xf3w Wielkopolski \nZielona G\xf3ra \ngorzowski \nkro\u015bnie\u0144ski \nmi\u0119dzyrzecki \nnowosolski \ns\u0142ubicki \nstrzelecko-drezdenecki \nsule\u0144ci\u0144ski \n\u015bwiebodzi\u0144ski \nwschowski \nzielonog\xf3rski \n\u017caga\u0144ski \n\u017carski \n\u0141\xf3d\u017a \nPiotrk\xf3w Trybunalski \nSkierniewice \nbe\u0142chatowski \nbrzezi\u0144ski \nkutnowski \n\u0142aski \n\u0142\u0119czycki \n\u0142owicki \n\u0142\xf3dzki wschodni \nopoczy\u0144ski \npabianicki \npaj\u0119cza\u0144ski \npiotrkowski \npodd\u0119bicki \nradomszcza\u0144ski \nrawski \nsieradzki \nskierniewicki \ntomaszowski \nwielu\u0144ski \nwieruszowski \nzdu\u0144skowolski \nzgierski \nKrak\xf3w \nTarn\xf3w \nNowy S\u0105cz \nboche\u0144ski \nbrzeski \nchrzanowski \nd\u0105browski \ngorlicki \nkrakowski \nlimanowski \nmiechowski \nmy\u015blenicki \nnowos\u0105decki \nnowotarski \nolkuski \no\u015bwi\u0119cimski \nproszowicki \nsuski \ntarnowski \ntatrza\u0144ski \nwadowicki \nwielicki \nWarszawa \nOstro\u0142\u0119ka \nP\u0142ock \nRadom \nSiedlce \nbia\u0142obrzeski \nciechanowski \ngarwoli\u0144ski \ngostyni\u0144ski \ngrodziski \ngr\xf3jecki \nkozenicki \nlegionowski \nlipski \n\u0142osicki \nmakowski \nmi\u0144ski \nm\u0142awski \nnowodworski \nostro\u0142\u0119cki \nostrowski \notwocki \npiaseczy\u0144ski \np\u0142ocki \np\u0142o\u0144ski \npruszkowski \nprzasnyski \nprzysuski \npu\u0142tuski \nradomski \nsiedlecki \nsierpecki \nsochaczewski \nsoko\u0142owski \nszyd\u0142owiecki \nwarszawski zachodni \nw\u0119growski \nwo\u0142omi\u0144ski \nwyszkowski \nzwole\u0144ski \n\u017curomi\u0144ski \n\u017cyrardowski \nOpole \nbrzeski \ng\u0142ubczyski \nk\u0119dzierzy\u0144ski-kozielski \nkluczborski \nkrapkowicki \nnamys\u0142owski \nnyski \noleski \nopolski \nprudnicki \nstrzelecki \nRzesz\xf3w \nKrosno \nPrzemy\u015bl \nTarnobrzeg \nbieszczadzki \nbrzozowski \nd\u0119bicki \njaros\u0142awski \njasielski \nkolbuszowski \nkro\u015bnie\u0144ski \nleski \nle\u017cajski \nlubaczowski \n\u0142a\u0144cucki \nmielecki \nni\u017ca\u0144ski \nprzemyski \nprzeworski \nropczycko-s\u0119dziszowski \nrzeszowski \nsanocki \nstalowowolski \nstrzy\u017cowski \ntarnobrzeski \nBia\u0142ystok \n\u0141om\u017ca \nSuwa\u0142ki \naugustowski \nbia\u0142ostocki \nbielski \ngrajewski \nhajnowski \nkolne\u0144ski \n\u0142om\u017cy\u0144ski \nmoniecki \nsejne\u0144ski \nsiematycki \nsok\xf3lski \nsuwalski \nwysokomazowiecki \nzambrowski \nGda\u0144sk \nGdynia \nS\u0142upsk \nSopot \nbytowski \nchojnicki \ncz\u0142uchowski \nkartuski \nko\u015bcierski \nkwidzy\u0144ski \nl\u0119borski \nmalborski \nnowodworski \ngda\u0144ski \npucki \ns\u0142upski \nstarogardzki \nsztumski \ntczewski \nwejcherowski \nKatowice \nBielsko-Bia\u0142a \nBytom \nChorz\xf3w \nCz\u0119stochowa \nD\u0105browa G\xf3rnicza \nGliwice \nJastrz\u0119bie Zdr\xf3j \nJaworzno \nMys\u0142owice \nPiekary \u015al\u0105skie \nRuda \u015al\u0105ska \nRybnik \nSiemianowice \u015al\u0105skie \nSosnowiec \n\u015awi\u0119toch\u0142owice \nTychy \nZabrze \n\u017bory \nb\u0119dzi\u0144ski \nbielski \nbieru\u0144sko-l\u0119dzi\u0144ski \ncieszy\u0144ski \ncz\u0119stochowski \ngliwicki \nk\u0142obucki \nlubliniecki \nmiko\u0142owski \nmyszkowski \npszczy\u0144ski \nraciborski \nrybnicki \ntarnog\xf3rski \nwodzis\u0142awski \nzawiercia\u0144ski \n\u017cywiecki \nKielce \nbuski \nj\u0119drzejowski \nkazimierski \nkielecki \nkonecki \nopatowski \nostrowiecki \npi\u0144czowski \nsandomierski \nskar\u017cyski \nstarachowicki \nstaszowski \nw\u0142oszczowski \nOlsztyn \nElbl\u0105g \nbartoszycki \nbraniewski \ndzia\u0142dowski \nelbl\u0105ski \ne\u0142cki \ngi\u017cycki \ngo\u0142dapski \ni\u0142awski \nk\u0119trzy\u0144ski \nlidzbarski \nmr\u0105gowski \nnidzicki \nnowomiejski \nolecki \nolszty\u0144ski \nostr\xf3dzki \npiski \nszczycie\u0144ski \nw\u0119gorzewski \nPozna\u0144 \nKalisz \nKonin \nLeszno \nchodziejski \nczarnkowsko-trzcianecki \ngnie\u017anie\u0144ski \ngosty\u0144ski \ngrodziski \njaroci\u0144ski \nkaliski \nk\u0119pi\u0144ski \nkolski \nkoni\u0144ski \nko\u015bcia\u0144ski \nkrotoszy\u0144ski \nleszczy\u0144ski \nmi\u0119dzychodzki \nnowotomyski \nobornicki \nostrowski \nostrzeszowski \npilski \npleszewski \npozna\u0144ski \nrawicki \ns\u0142upecki \nszamotulski \n\u015bredzki \n\u015bremski \nturecki \nw\u0105growiecki \nwolszty\u0144ski \nwrzesi\u0144ski \nz\u0142otowski \nbia\u0142ogardzki \nchoszcze\u0144ski \ndrawski \ngoleniowski \ngryficki \ngryfi\u0144ski \nkamie\u0144ski \nko\u0142obrzeski \nkoszali\u0144ski \n\u0142obeski \nmy\u015bliborski \npolicki \npyrzycki \ns\u0142awie\u0144ski \nstargardzki \nszczecinecki \n\u015bwidwi\u0144ski \nwa\u0142ecki \n '
-
-# PLPostalCodeField ##############################################################
-
->>> from django.contrib.localflavor.pl.forms import PLPostalCodeField
->>> f = PLPostalCodeField()
->>> f.clean('43--434')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XX-XXX.']
->>> f.clean('41-403')
-u'41-403'
-
-# PLTaxNumberField ###############################################################
-
->>> from django.contrib.localflavor.pl.forms import PLTaxNumberField
->>> f = PLTaxNumberField()
->>> f.clean('43-343-234-323')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.']
->>> f.clean('43-34-234-323')
-u'43-34-234-323'
->>> f.clean('433-344-24-23')
-u'433-344-24-23'
-
-# PLNationalIdentificationNumberField ############################################
-
->>> from django.contrib.localflavor.pl.forms import PLNationalIdentificationNumberField
->>> f = PLNationalIdentificationNumberField()
->>> f.clean('80071610614')
-u'80071610614'
->>> f.clean('80071610610')
-Traceback (most recent call last):
-...
-ValidationError: [u'Wrong checksum for the National Identification Number.']
->>> f.clean('80')
-Traceback (most recent call last):
-...
-ValidationError: [u'National Identification Number consists of 11 digits.']
->>> f.clean('800716106AA')
-Traceback (most recent call last):
-...
-ValidationError: [u'National Identification Number consists of 11 digits.']
-
-# NLPhoneNumberField ########################################################
-
->>> from django.contrib.localflavor.nl.forms import NLPhoneNumberField
->>> f = NLPhoneNumberField(required=False)
->>> f.clean('')
-u''
->>> f.clean('012-3456789')
-'012-3456789'
->>> f.clean('0123456789')
-'0123456789'
->>> f.clean('+31-12-3456789')
-'+31-12-3456789'
->>> f.clean('(0123) 456789')
-'(0123) 456789'
->>> f.clean('foo')
-Traceback (most recent call last):
- ...
-ValidationError: [u'Enter a valid phone number']
-
-# NLZipCodeField ############################################################
-
->>> from django.contrib.localflavor.nl.forms import NLZipCodeField
->>> f = NLZipCodeField(required=False)
->>> f.clean('')
-u''
->>> f.clean('1234ab')
-u'1234 AB'
->>> f.clean('1234 ab')
-u'1234 AB'
->>> f.clean('1234 AB')
-u'1234 AB'
->>> f.clean('0123AB')
-Traceback (most recent call last):
- ...
-ValidationError: [u'Enter a valid postal code']
->>> f.clean('foo')
-Traceback (most recent call last):
- ...
-ValidationError: [u'Enter a valid postal code']
-
-# NLSoFiNumberField #########################################################
-
->>> from django.contrib.localflavor.nl.forms import NLSoFiNumberField
->>> f = NLSoFiNumberField(required=False)
->>> f.clean('')
-u''
->>> f.clean('123456782')
-'123456782'
->>> f.clean('000000000')
-Traceback (most recent call last):
- ...
-ValidationError: [u'Enter a valid SoFi number']
->>> f.clean('123456789')
-Traceback (most recent call last):
- ...
-ValidationError: [u'Enter a valid SoFi number']
->>> f.clean('foo')
-Traceback (most recent call last):
- ...
-ValidationError: [u'Enter a valid SoFi number']
-
-# NLProvinceSelect ##########################################################
-
->>> from django.contrib.localflavor.nl.forms import NLProvinceSelect
->>> s = NLProvinceSelect()
->>> s.render('provinces', 'OV')
-u'\nDrente \nFlevoland \nFriesland \nGelderland \nGroningen \nLimburg \nNoord-Brabant \nNoord-Holland \nOverijssel \nUtrecht \nZeeland \nZuid-Holland \n '
-
-# ARProvinceField #############################################################
-
->>> from django.contrib.localflavor.ar.forms import ARProvinceSelect
->>> f = ARProvinceSelect()
->>> f.render('provincias', 'A')
-u'\nBuenos Aires \nCatamarca \nChaco \nChubut \nCiudad Aut\xf3noma de Buenos Aires \nC\xf3rdoba \nCorrientes \nEntre R\xedos \nFormosa \nJujuy \nLa Pampa \nLa Rioja \nMendoza \nMisiones \nNeuqu\xe9n \nR\xedo Negro \nSalta \nSan Juan \nSan Luis \nSanta Cruz \nSanta Fe \nSantiago del Estero \nTierra del Fuego, Ant\xe1rtida e Islas del Atl\xe1ntico Sur \nTucum\xe1n \n '
-
-# ARPostalCodeField ###########################################################
-
->>> from django.contrib.localflavor.ar.forms import ARPostalCodeField
->>> f = ARPostalCodeField()
->>> f.clean('5000')
-u'5000'
->>> f.clean('C1064AAB')
-u'C1064AAB'
->>> f.clean('c1064AAB')
-u'C1064AAB'
->>> f.clean('C1064aab')
-u'C1064AAB'
->>> f.clean(u'4400')
-u'4400'
->>> f.clean(u'C1064AAB')
-u'C1064AAB'
->>> f.clean('C1064AABB')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
->>> f.clean('C1064AA')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
->>> f.clean('C106AAB')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
->>> f.clean('106AAB')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
->>> f.clean('500')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
->>> f.clean('5PPP')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(u'')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = ARPostalCodeField(required=False)
->>> f.clean('5000')
-u'5000'
->>> f.clean('C1064AAB')
-u'C1064AAB'
->>> f.clean('c1064AAB')
-u'C1064AAB'
->>> f.clean('C1064aab')
-u'C1064AAB'
->>> f.clean(u'4400')
-u'4400'
->>> f.clean(u'C1064AAB')
-u'C1064AAB'
->>> f.clean('C1064AABB')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
->>> f.clean('C1064AA')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
->>> f.clean('C106AAB')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
->>> f.clean('106AAB')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
->>> f.clean('500')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
->>> f.clean('5PPP')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
->>> f.clean(u'')
-u''
-
-# ARDNIField ##################################################################
-
->>> from django.contrib.localflavor.ar.forms import ARDNIField
->>> f = ARDNIField()
->>> f.clean('20123456')
-u'20123456'
->>> f.clean('20.123.456')
-u'20123456'
->>> f.clean('9123456')
-u'9123456'
->>> f.clean('9.123.456')
-u'9123456'
->>> f.clean(u'20123456')
-u'20123456'
->>> f.clean(u'20.123.456')
-u'20123456'
->>> f.clean('20.123456')
-u'20123456'
->>> f.clean('101234566')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires 7 or 8 digits.']
->>> f.clean('W0123456')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires only numbers.']
->>> f.clean('10,123,456')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires only numbers.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(u'')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = ARDNIField(required=False)
->>> f.clean('20123456')
-u'20123456'
->>> f.clean('20.123.456')
-u'20123456'
->>> f.clean('9123456')
-u'9123456'
->>> f.clean('9.123.456')
-u'9123456'
->>> f.clean(u'20123456')
-u'20123456'
->>> f.clean(u'20.123.456')
-u'20123456'
->>> f.clean('20.123456')
-u'20123456'
->>> f.clean('101234566')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires 7 or 8 digits.']
->>> f.clean('W0123456')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires only numbers.']
->>> f.clean('10,123,456')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field requires only numbers.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
->>> f.clean(u'')
-u''
-
-# ARCUITField #################################################################
-
->>> from django.contrib.localflavor.ar.forms import ARCUITField
->>> f = ARCUITField()
->>> f.clean('20-10123456-9')
-u'20-10123456-9'
->>> f.clean(u'20-10123456-9')
-u'20-10123456-9'
->>> f.clean('27-10345678-4')
-u'27-10345678-4'
->>> f.clean('20101234569')
-u'20-10123456-9'
->>> f.clean('27103456784')
-u'27-10345678-4'
->>> f.clean('2-10123456-9')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('210123456-9')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('20-10123456')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('20-10123456-')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('20-10123456-5')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CUIT.']
->>> f.clean(u'2-10123456-9')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('27-10345678-1')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CUIT.']
->>> f.clean(u'27-10345678-1')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CUIT.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(u'')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = ARCUITField(required=False)
->>> f.clean('20-10123456-9')
-u'20-10123456-9'
->>> f.clean(u'20-10123456-9')
-u'20-10123456-9'
->>> f.clean('27-10345678-4')
-u'27-10345678-4'
->>> f.clean('20101234569')
-u'20-10123456-9'
->>> f.clean('27103456784')
-u'27-10345678-4'
->>> f.clean('2-10123456-9')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('210123456-9')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('20-10123456')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('20-10123456-')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('20-10123456-5')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CUIT.']
->>> f.clean(u'2-10123456-9')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
->>> f.clean('27-10345678-1')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CUIT.']
->>> f.clean(u'27-10345678-1')
-Traceback (most recent call last):
-...
-ValidationError: [u'Invalid CUIT.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
->>> f.clean(u'')
-u''
-
-# CAPostalCodeField ##############################################################
-
-CAPostalCodeField validates that the data is a six-character Canadian postal code.
->>> from django.contrib.localflavor.ca.forms import CAPostalCodeField
->>> f = CAPostalCodeField()
->>> f.clean('T2S 2H7')
-u'T2S 2H7'
->>> f.clean('T2S 2H')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean('2T6 H8I')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean('T2S2H')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean(90210)
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f = CAPostalCodeField(required=False)
->>> f.clean('T2S 2H7')
-u'T2S 2H7'
->>> f.clean('T2S2H7')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean('T2S 2H')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean('2T6 H8I')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean('T2S2H')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean(90210)
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a postal code in the format XXX XXX.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# CAPhoneNumberField ##########################################################
-
-CAPhoneNumberField validates that the data is a valid Canadian phone number,
-including the area code. It's normalized to XXX-XXX-XXXX format.
-Note: This test is exactly the same as the USPhoneNumberField except using a real
-Candian area code
-
->>> from django.contrib.localflavor.ca.forms import CAPhoneNumberField
->>> f = CAPhoneNumberField()
->>> f.clean('403-555-1212')
-u'403-555-1212'
->>> f.clean('4035551212')
-u'403-555-1212'
->>> f.clean('403 555-1212')
-u'403-555-1212'
->>> f.clean('(403) 555-1212')
-u'403-555-1212'
->>> f.clean('403 555 1212')
-u'403-555-1212'
->>> f.clean('403.555.1212')
-u'403-555-1212'
->>> f.clean('403.555-1212')
-u'403-555-1212'
->>> f.clean(' (403) 555.1212 ')
-u'403-555-1212'
->>> f.clean('555-1212')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
->>> f.clean('403-55-1212')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = CAPhoneNumberField(required=False)
->>> f.clean('403-555-1212')
-u'403-555-1212'
->>> f.clean('4035551212')
-u'403-555-1212'
->>> f.clean('403 555-1212')
-u'403-555-1212'
->>> f.clean('(403) 555-1212')
-u'403-555-1212'
->>> f.clean('403 555 1212')
-u'403-555-1212'
->>> f.clean('403.555.1212')
-u'403-555-1212'
->>> f.clean('403.555-1212')
-u'403-555-1212'
->>> f.clean(' (403) 555.1212 ')
-u'403-555-1212'
->>> f.clean('555-1212')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
->>> f.clean('403-55-1212')
-Traceback (most recent call last):
-...
-ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# CAProvinceField ################################################################
-
-CAProvinceField validates that the data is either an abbreviation or name of a
-Canadian province.
->>> from django.contrib.localflavor.ca.forms import CAProvinceField
->>> f = CAProvinceField()
->>> f.clean('ab')
-u'AB'
->>> f.clean('BC')
-u'BC'
->>> f.clean('nova scotia')
-u'NS'
->>> f.clean(' manitoba ')
-u'MB'
->>> f.clean('T2S 2H7')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a Canadian province or territory.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = CAProvinceField(required=False)
->>> f.clean('ab')
-u'AB'
->>> f.clean('BC')
-u'BC'
->>> f.clean('nova scotia')
-u'NS'
->>> f.clean(' manitoba ')
-u'MB'
->>> f.clean('T2S 2H7')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a Canadian province or territory.']
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
-
-# CAProvinceSelect ###############################################################
-
-CAProvinceSelect is a Select widget that uses a list of Canadian provinces/territories
-as its choices.
->>> from django.contrib.localflavor.ca.forms import CAProvinceSelect
->>> w = CAProvinceSelect()
->>> print w.render('province', 'AB')
-
-Alberta
-British Columbia
-Manitoba
-New Brunswick
-Newfoundland and Labrador
-Northwest Territories
-Nova Scotia
-Nunavut
-Ontario
-Prince Edward Island
-Quebec
-Saskatchewan
-Yukon
-
-
-# CASocialInsuranceNumberField #################################################
->>> from django.contrib.localflavor.ca.forms import CASocialInsuranceNumberField
->>> f = CASocialInsuranceNumberField()
->>> f.clean('046-454-286')
-u'046-454-286'
->>> f.clean('046-454-287')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
->>> f.clean('046 454 286')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
->>> f.clean('046-44-286')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
-
-## Generic DateField ##########################################################
-
->>> from django.contrib.localflavor.generic.forms import *
-
-A DateField that uses generic dd/mm/yy dates instead of mm/dd/yy where
-appropriate.
-
->>> import datetime
->>> f = DateField()
->>> f.clean(datetime.date(2006, 10, 25))
-datetime.date(2006, 10, 25)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
-datetime.date(2006, 10, 25)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
-datetime.date(2006, 10, 25)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
-datetime.date(2006, 10, 25)
->>> f.clean('2006-10-25')
-datetime.date(2006, 10, 25)
->>> f.clean('25/10/2006')
-datetime.date(2006, 10, 25)
->>> f.clean('25/10/06')
-datetime.date(2006, 10, 25)
->>> f.clean('Oct 25 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('October 25 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('October 25, 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('25 October 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('25 October, 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('2006-4-31')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean('200a-10-25')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean('10/25/06')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = DateField(required=False)
->>> f.clean(None)
->>> repr(f.clean(None))
-'None'
->>> f.clean('')
->>> repr(f.clean(''))
-'None'
-
-DateField accepts an optional input_formats parameter:
->>> f = DateField(input_formats=['%Y %m %d'])
->>> f.clean(datetime.date(2006, 10, 25))
-datetime.date(2006, 10, 25)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
-datetime.date(2006, 10, 25)
->>> f.clean('2006 10 25')
-datetime.date(2006, 10, 25)
-
-The input_formats parameter overrides all default input formats,
-so the default formats won't work unless you specify them:
->>> f.clean('2006-10-25')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean('25/10/2006')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean('25/10/06')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
-
-## Generic DateTimeField ######################################################
-
-A DateField that uses generic dd/mm/yy dates instead of mm/dd/yy where
-appropriate.
-
->>> import datetime
->>> f = DateTimeField()
->>> f.clean(datetime.date(2006, 10, 25))
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
-datetime.datetime(2006, 10, 25, 14, 30, 59)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
-datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
->>> f.clean('2006-10-25 14:30:45')
-datetime.datetime(2006, 10, 25, 14, 30, 45)
->>> f.clean('2006-10-25 14:30:00')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('2006-10-25 14:30')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('2006-10-25')
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean('25/10/2006 14:30:45')
-datetime.datetime(2006, 10, 25, 14, 30, 45)
->>> f.clean('25/10/2006 14:30:00')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('25/10/2006 14:30')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('25/10/2006')
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean('25/10/06 14:30:45')
-datetime.datetime(2006, 10, 25, 14, 30, 45)
->>> f.clean('25/10/06 14:30:00')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('25/10/06 14:30')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('25/10/06')
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean('hello')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date/time.']
->>> f.clean('2006-10-25 4:30 p.m.')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date/time.']
-
-DateField accepts an optional input_formats parameter:
->>> f = DateTimeField(input_formats=['%Y %m %d %I:%M %p'])
->>> f.clean(datetime.date(2006, 10, 25))
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
-datetime.datetime(2006, 10, 25, 14, 30, 59)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
-datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
->>> f.clean('2006 10 25 2:30 PM')
-datetime.datetime(2006, 10, 25, 14, 30)
-
-The input_formats parameter overrides all default input formats,
-so the default formats won't work unless you specify them:
->>> f.clean('2006-10-25 14:30:45')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date/time.']
-
->>> f = DateTimeField(required=False)
->>> f.clean(None)
->>> repr(f.clean(None))
-'None'
->>> f.clean('')
->>> repr(f.clean(''))
-'None'
-
-"""
diff --git a/tests/regressiontests/forms/localflavor/__init__.py b/tests/regressiontests/forms/localflavor/__init__.py
new file mode 100644
index 0000000000..40a96afc6f
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/tests/regressiontests/forms/localflavor/ar.py b/tests/regressiontests/forms/localflavor/ar.py
new file mode 100644
index 0000000000..e1c827c4a0
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/ar.py
@@ -0,0 +1,294 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ AR form fields.
+
+tests = r"""
+# ARProvinceField #############################################################
+
+>>> from django.contrib.localflavor.ar.forms import ARProvinceSelect
+>>> f = ARProvinceSelect()
+>>> f.render('provincias', 'A')
+u'\nBuenos Aires \nCatamarca \nChaco \nChubut \nCiudad Aut\xf3noma de Buenos Aires \nC\xf3rdoba \nCorrientes \nEntre R\xedos \nFormosa \nJujuy \nLa Pampa \nLa Rioja \nMendoza \nMisiones \nNeuqu\xe9n \nR\xedo Negro \nSalta \nSan Juan \nSan Luis \nSanta Cruz \nSanta Fe \nSantiago del Estero \nTierra del Fuego, Ant\xe1rtida e Islas del Atl\xe1ntico Sur \nTucum\xe1n \n '
+
+# ARPostalCodeField ###########################################################
+
+>>> from django.contrib.localflavor.ar.forms import ARPostalCodeField
+>>> f = ARPostalCodeField()
+>>> f.clean('5000')
+u'5000'
+>>> f.clean('C1064AAB')
+u'C1064AAB'
+>>> f.clean('c1064AAB')
+u'C1064AAB'
+>>> f.clean('C1064aab')
+u'C1064AAB'
+>>> f.clean(u'4400')
+u'4400'
+>>> f.clean(u'C1064AAB')
+u'C1064AAB'
+>>> f.clean('C1064AABB')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
+>>> f.clean('C1064AA')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
+>>> f.clean('C106AAB')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
+>>> f.clean('106AAB')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
+>>> f.clean('500')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
+>>> f.clean('5PPP')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(u'')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = ARPostalCodeField(required=False)
+>>> f.clean('5000')
+u'5000'
+>>> f.clean('C1064AAB')
+u'C1064AAB'
+>>> f.clean('c1064AAB')
+u'C1064AAB'
+>>> f.clean('C1064aab')
+u'C1064AAB'
+>>> f.clean(u'4400')
+u'4400'
+>>> f.clean(u'C1064AAB')
+u'C1064AAB'
+>>> f.clean('C1064AABB')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
+>>> f.clean('C1064AA')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
+>>> f.clean('C106AAB')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
+>>> f.clean('106AAB')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
+>>> f.clean('500')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 4 characters (it has 3).']
+>>> f.clean('5PPP')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format NNNN or ANNNNAAA.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+>>> f.clean(u'')
+u''
+
+# ARDNIField ##################################################################
+
+>>> from django.contrib.localflavor.ar.forms import ARDNIField
+>>> f = ARDNIField()
+>>> f.clean('20123456')
+u'20123456'
+>>> f.clean('20.123.456')
+u'20123456'
+>>> f.clean('9123456')
+u'9123456'
+>>> f.clean('9.123.456')
+u'9123456'
+>>> f.clean(u'20123456')
+u'20123456'
+>>> f.clean(u'20.123.456')
+u'20123456'
+>>> f.clean('20.123456')
+u'20123456'
+>>> f.clean('101234566')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires 7 or 8 digits.']
+>>> f.clean('W0123456')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires only numbers.']
+>>> f.clean('10,123,456')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires only numbers.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(u'')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = ARDNIField(required=False)
+>>> f.clean('20123456')
+u'20123456'
+>>> f.clean('20.123.456')
+u'20123456'
+>>> f.clean('9123456')
+u'9123456'
+>>> f.clean('9.123.456')
+u'9123456'
+>>> f.clean(u'20123456')
+u'20123456'
+>>> f.clean(u'20.123.456')
+u'20123456'
+>>> f.clean('20.123456')
+u'20123456'
+>>> f.clean('101234566')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires 7 or 8 digits.']
+>>> f.clean('W0123456')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires only numbers.']
+>>> f.clean('10,123,456')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires only numbers.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+>>> f.clean(u'')
+u''
+
+# ARCUITField #################################################################
+
+>>> from django.contrib.localflavor.ar.forms import ARCUITField
+>>> f = ARCUITField()
+>>> f.clean('20-10123456-9')
+u'20-10123456-9'
+>>> f.clean(u'20-10123456-9')
+u'20-10123456-9'
+>>> f.clean('27-10345678-4')
+u'27-10345678-4'
+>>> f.clean('20101234569')
+u'20-10123456-9'
+>>> f.clean('27103456784')
+u'27-10345678-4'
+>>> f.clean('2-10123456-9')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('210123456-9')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('20-10123456')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('20-10123456-')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('20-10123456-5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CUIT.']
+>>> f.clean(u'2-10123456-9')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('27-10345678-1')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CUIT.']
+>>> f.clean(u'27-10345678-1')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CUIT.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(u'')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = ARCUITField(required=False)
+>>> f.clean('20-10123456-9')
+u'20-10123456-9'
+>>> f.clean(u'20-10123456-9')
+u'20-10123456-9'
+>>> f.clean('27-10345678-4')
+u'27-10345678-4'
+>>> f.clean('20101234569')
+u'20-10123456-9'
+>>> f.clean('27103456784')
+u'27-10345678-4'
+>>> f.clean('2-10123456-9')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('210123456-9')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('20-10123456')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('20-10123456-')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('20-10123456-5')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CUIT.']
+>>> f.clean(u'2-10123456-9')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid CUIT in XX-XXXXXXXX-X or XXXXXXXXXXXX format.']
+>>> f.clean('27-10345678-1')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CUIT.']
+>>> f.clean(u'27-10345678-1')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CUIT.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+>>> f.clean(u'')
+u''
+"""
diff --git a/tests/regressiontests/forms/localflavor/au.py b/tests/regressiontests/forms/localflavor/au.py
new file mode 100644
index 0000000000..fd4c0d6980
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/au.py
@@ -0,0 +1,134 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ AU form fields.
+
+tests = r"""
+## AUPostCodeField ##########################################################
+
+A field that accepts a four digit Australian post code.
+
+>>> from django.contrib.localflavor.au.forms import AUPostCodeField
+>>> f = AUPostCodeField()
+>>> f.clean('1234')
+u'1234'
+>>> f.clean('2000')
+u'2000'
+>>> f.clean('abcd')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a 4 digit post code.']
+>>> f.clean('20001')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a 4 digit post code.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = AUPostCodeField(required=False)
+>>> f.clean('1234')
+u'1234'
+>>> f.clean('2000')
+u'2000'
+>>> f.clean('abcd')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a 4 digit post code.']
+>>> f.clean('20001')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a 4 digit post code.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+## AUPhoneNumberField ########################################################
+
+A field that accepts a 10 digit Australian phone number.
+llows spaces and parentheses around area code.
+
+>>> from django.contrib.localflavor.au.forms import AUPhoneNumberField
+>>> f = AUPhoneNumberField()
+>>> f.clean('1234567890')
+u'1234567890'
+>>> f.clean('0213456789')
+u'0213456789'
+>>> f.clean('02 13 45 67 89')
+u'0213456789'
+>>> f.clean('(02) 1345 6789')
+u'0213456789'
+>>> f.clean('(02) 1345-6789')
+u'0213456789'
+>>> f.clean('(02)1345-6789')
+u'0213456789'
+>>> f.clean('0408 123 456')
+u'0408123456'
+>>> f.clean('123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must contain 10 digits.']
+>>> f.clean('1800DJANGO')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must contain 10 digits.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = AUPhoneNumberField(required=False)
+>>> f.clean('1234567890')
+u'1234567890'
+>>> f.clean('0213456789')
+u'0213456789'
+>>> f.clean('02 13 45 67 89')
+u'0213456789'
+>>> f.clean('(02) 1345 6789')
+u'0213456789'
+>>> f.clean('(02) 1345-6789')
+u'0213456789'
+>>> f.clean('(02)1345-6789')
+u'0213456789'
+>>> f.clean('0408 123 456')
+u'0408123456'
+>>> f.clean('123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must contain 10 digits.']
+>>> f.clean('1800DJANGO')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must contain 10 digits.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+## AUStateSelect #############################################################
+
+AUStateSelect is a Select widget that uses a list of Australian
+states/territories as its choices.
+
+>>> from django.contrib.localflavor.au.forms import AUStateSelect
+>>> f = AUStateSelect()
+>>> print f.render('state', 'NSW')
+
+Australian Capital Territory
+New South Wales
+Northern Territory
+Queensland
+South Australia
+Tasmania
+Victoria
+Western Australia
+
+"""
diff --git a/tests/regressiontests/forms/localflavor/br.py b/tests/regressiontests/forms/localflavor/br.py
new file mode 100644
index 0000000000..757f382d64
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/br.py
@@ -0,0 +1,220 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ BR form fields.
+
+tests = r"""
+# BRZipCodeField ############################################################
+>>> from django.contrib.localflavor.br.forms import BRZipCodeField
+>>> f = BRZipCodeField()
+>>> f.clean('12345-123')
+u'12345-123'
+>>> f.clean('12345_123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('1234-123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('abcde-abc')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('12345-')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('-123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = BRZipCodeField(required=False)
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+>>> f.clean('-123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('12345-')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('abcde-abc')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('1234-123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('12345_123')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX-XXX.']
+>>> f.clean('12345-123')
+u'12345-123'
+
+# BRCNPJField ############################################################
+
+>>> from django.contrib.localflavor.br.forms import BRCNPJField
+>>> f = BRCNPJField(required=True)
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('12-345-678/9012-10')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CNPJ number.']
+>>> f.clean('12.345.678/9012-10')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CNPJ number.']
+>>> f.clean('12345678/9012-10')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CNPJ number.']
+>>> f.clean('64.132.916/0001-88')
+'64.132.916/0001-88'
+>>> f.clean('64-132-916/0001-88')
+'64-132-916/0001-88'
+>>> f.clean('64132916/0001-88')
+'64132916/0001-88'
+>>> f.clean('64.132.916/0001-XX')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires only numbers.']
+>>> f = BRCNPJField(required=False)
+>>> f.clean('')
+u''
+
+# BRCPFField #################################################################
+
+>>> from django.contrib.localflavor.br.forms import BRCPFField
+>>> f = BRCPFField()
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('489.294.654-54')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CPF number.']
+>>> f.clean('295.669.575-98')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CPF number.']
+>>> f.clean('539.315.127-22')
+Traceback (most recent call last):
+...
+ValidationError: [u'Invalid CPF number.']
+>>> f.clean('663.256.017-26')
+u'663.256.017-26'
+>>> f.clean('66325601726')
+u'66325601726'
+>>> f.clean('375.788.573-20')
+u'375.788.573-20'
+>>> f.clean('84828509895')
+u'84828509895'
+>>> f.clean('375.788.573-XX')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires only numbers.']
+>>> f.clean('375.788.573-000')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 14 characters (it has 15).']
+>>> f.clean('123.456.78')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 11 characters (it has 10).']
+>>> f.clean('123456789555')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field requires at most 11 digits or 14 characters.']
+>>> f = BRCPFField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+
+# BRPhoneNumberField #########################################################
+
+>>> from django.contrib.localflavor.br.forms import BRPhoneNumberField
+>>> f = BRPhoneNumberField()
+>>> f.clean('41-3562-3464')
+u'41-3562-3464'
+>>> f.clean('4135623464')
+u'41-3562-3464'
+>>> f.clean('41 3562-3464')
+u'41-3562-3464'
+>>> f.clean('41 3562 3464')
+u'41-3562-3464'
+>>> f.clean('(41) 3562 3464')
+u'41-3562-3464'
+>>> f.clean('41.3562.3464')
+u'41-3562-3464'
+>>> f.clean('41.3562-3464')
+u'41-3562-3464'
+>>> f.clean(' (41) 3562.3464')
+u'41-3562-3464'
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = BRPhoneNumberField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+>>> f.clean(' (41) 3562.3464')
+u'41-3562-3464'
+>>> f.clean('41.3562-3464')
+u'41-3562-3464'
+>>> f.clean('(41) 3562 3464')
+u'41-3562-3464'
+>>> f.clean('4135623464')
+u'41-3562-3464'
+>>> f.clean('41 3562-3464')
+u'41-3562-3464'
+
+# BRStateSelect ##############################################################
+
+>>> from django.contrib.localflavor.br.forms import BRStateSelect
+>>> w = BRStateSelect()
+>>> w.render('states', 'PR')
+u'\nAcre \nAlagoas \nAmap\xe1 \nAmazonas \nBahia \nCear\xe1 \nDistrito Federal \nEsp\xedrito Santo \nGoi\xe1s \nMaranh\xe3o \nMato Grosso \nMato Grosso do Sul \nMinas Gerais \nPar\xe1 \nPara\xedba \nParan\xe1 \nPernambuco \nPiau\xed \nRio de Janeiro \nRio Grande do Norte \nRio Grande do Sul \nRond\xf4nia \nRoraima \nSanta Catarina \nS\xe3o Paulo \nSergipe \nTocantins \n '
+
+# BRStateChoiceField #########################################################
+>>> from django.contrib.localflavor.br.forms import BRStateChoiceField
+>>> f = BRStateChoiceField()
+>>> ', '.join([f.clean(s) for s, _ in f.widget.choices])
+u'AC, AL, AP, AM, BA, CE, DF, ES, GO, MA, MT, MS, MG, PA, PB, PR, PE, PI, RJ, RN, RS, RO, RR, SC, SP, SE, TO'
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('pr')
+Traceback (most recent call last):
+...
+ValidationError: [u'Select a valid brazilian state. That state is not one of the available states.']
+"""
diff --git a/tests/regressiontests/forms/localflavor/ca.py b/tests/regressiontests/forms/localflavor/ca.py
new file mode 100644
index 0000000000..baeb2ad9a8
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/ca.py
@@ -0,0 +1,221 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ CA form fields.
+
+tests = r"""
+# CAPostalCodeField ##############################################################
+
+CAPostalCodeField validates that the data is a six-character Canadian postal code.
+>>> from django.contrib.localflavor.ca.forms import CAPostalCodeField
+>>> f = CAPostalCodeField()
+>>> f.clean('T2S 2H7')
+u'T2S 2H7'
+>>> f.clean('T2S 2H')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean('2T6 H8I')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean('T2S2H')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean(90210)
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f = CAPostalCodeField(required=False)
+>>> f.clean('T2S 2H7')
+u'T2S 2H7'
+>>> f.clean('T2S2H7')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean('T2S 2H')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean('2T6 H8I')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean('T2S2H')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean(90210)
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXX XXX.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+# CAPhoneNumberField ##########################################################
+
+CAPhoneNumberField validates that the data is a valid Canadian phone number,
+including the area code. It's normalized to XXX-XXX-XXXX format.
+Note: This test is exactly the same as the USPhoneNumberField except using a real
+Candian area code
+
+>>> from django.contrib.localflavor.ca.forms import CAPhoneNumberField
+>>> f = CAPhoneNumberField()
+>>> f.clean('403-555-1212')
+u'403-555-1212'
+>>> f.clean('4035551212')
+u'403-555-1212'
+>>> f.clean('403 555-1212')
+u'403-555-1212'
+>>> f.clean('(403) 555-1212')
+u'403-555-1212'
+>>> f.clean('403 555 1212')
+u'403-555-1212'
+>>> f.clean('403.555.1212')
+u'403-555-1212'
+>>> f.clean('403.555-1212')
+u'403-555-1212'
+>>> f.clean(' (403) 555.1212 ')
+u'403-555-1212'
+>>> f.clean('555-1212')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
+>>> f.clean('403-55-1212')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = CAPhoneNumberField(required=False)
+>>> f.clean('403-555-1212')
+u'403-555-1212'
+>>> f.clean('4035551212')
+u'403-555-1212'
+>>> f.clean('403 555-1212')
+u'403-555-1212'
+>>> f.clean('(403) 555-1212')
+u'403-555-1212'
+>>> f.clean('403 555 1212')
+u'403-555-1212'
+>>> f.clean('403.555.1212')
+u'403-555-1212'
+>>> f.clean('403.555-1212')
+u'403-555-1212'
+>>> f.clean(' (403) 555.1212 ')
+u'403-555-1212'
+>>> f.clean('555-1212')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
+>>> f.clean('403-55-1212')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+# CAProvinceField ################################################################
+
+CAProvinceField validates that the data is either an abbreviation or name of a
+Canadian province.
+>>> from django.contrib.localflavor.ca.forms import CAProvinceField
+>>> f = CAProvinceField()
+>>> f.clean('ab')
+u'AB'
+>>> f.clean('BC')
+u'BC'
+>>> f.clean('nova scotia')
+u'NS'
+>>> f.clean(' manitoba ')
+u'MB'
+>>> f.clean('T2S 2H7')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a Canadian province or territory.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = CAProvinceField(required=False)
+>>> f.clean('ab')
+u'AB'
+>>> f.clean('BC')
+u'BC'
+>>> f.clean('nova scotia')
+u'NS'
+>>> f.clean(' manitoba ')
+u'MB'
+>>> f.clean('T2S 2H7')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a Canadian province or territory.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+# CAProvinceSelect ###############################################################
+
+CAProvinceSelect is a Select widget that uses a list of Canadian provinces/territories
+as its choices.
+>>> from django.contrib.localflavor.ca.forms import CAProvinceSelect
+>>> w = CAProvinceSelect()
+>>> print w.render('province', 'AB')
+
+Alberta
+British Columbia
+Manitoba
+New Brunswick
+Newfoundland and Labrador
+Northwest Territories
+Nova Scotia
+Nunavut
+Ontario
+Prince Edward Island
+Quebec
+Saskatchewan
+Yukon
+
+
+# CASocialInsuranceNumberField #################################################
+>>> from django.contrib.localflavor.ca.forms import CASocialInsuranceNumberField
+>>> f = CASocialInsuranceNumberField()
+>>> f.clean('046-454-286')
+u'046-454-286'
+>>> f.clean('046-454-287')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
+>>> f.clean('046 454 286')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
+>>> f.clean('046-44-286')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Canadian Social Insurance number in XXX-XXX-XXXX format.']
+"""
diff --git a/tests/regressiontests/forms/localflavor/ch.py b/tests/regressiontests/forms/localflavor/ch.py
new file mode 100644
index 0000000000..b4f8e7d667
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/ch.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ CH form fields.
+
+tests = r"""
+# CHZipCodeField ############################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHZipCodeField
+>>> f = CHZipCodeField()
+>>> f.clean('800x')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXX.']
+>>> f.clean('80 00')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXX.']
+>>> f.clean('8000')
+u'8000'
+
+# CHPhoneNumberField ########################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHPhoneNumberField
+>>> f = CHPhoneNumberField()
+>>> f.clean('01234567890')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
+>>> f.clean('1234567890')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0XX XXX XX XX format.']
+>>> f.clean('0123456789')
+u'012 345 67 89'
+
+# CHIdentityCardNumberField #################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHIdentityCardNumberField
+>>> f = CHIdentityCardNumberField()
+>>> f.clean('C1234567<0')
+u'C1234567<0'
+>>> f.clean('C1234567<1')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.']
+>>> f.clean('2123456700')
+u'2123456700'
+>>> f.clean('2123456701')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Swiss identity or passport card number in X1234567<0 or 1234567890 format.']
+
+# CHStateSelect #############################################################
+
+>>> from django.contrib.localflavor.ch.forms import CHStateSelect
+>>> w = CHStateSelect()
+>>> w.render('state', 'AG')
+u'\nAargau \nAppenzell Innerrhoden \nAppenzell Ausserrhoden \nBasel-Stadt \nBasel-Land \nBerne \nFribourg \nGeneva \nGlarus \nGraubuenden \nJura \nLucerne \nNeuchatel \nNidwalden \nObwalden \nSchaffhausen \nSchwyz \nSolothurn \nSt. Gallen \nThurgau \nTicino \nUri \nValais \nVaud \nZug \nZurich \n '
+"""
diff --git a/tests/regressiontests/forms/localflavor/cl.py b/tests/regressiontests/forms/localflavor/cl.py
new file mode 100644
index 0000000000..407f6610e4
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/cl.py
@@ -0,0 +1,74 @@
+
+# Tests for the contrib/localflavor/ CL form fields.
+
+tests = r"""
+## CLRutField #############################################################
+
+CLRutField is a Field that checks the validity of the Chilean
+personal identification number (RUT). It has two modes relaxed (default) and
+strict.
+
+>>> from django.contrib.localflavor.cl.forms import CLRutField
+>>> rut = CLRutField()
+
+>>> rut.clean('11-6')
+u'11-6'
+>>> rut.clean('116')
+u'11-6'
+
+# valid format, bad verifier.
+>>> rut.clean('11.111.111-0')
+Traceback (most recent call last):
+...
+ValidationError: [u'The Chilean RUT is not valid.']
+>>> rut.clean('111')
+Traceback (most recent call last):
+...
+ValidationError: [u'The Chilean RUT is not valid.']
+
+>>> rut.clean('767484100')
+u'76.748.410-0'
+>>> rut.clean('78.412.790-7')
+u'78.412.790-7'
+>>> rut.clean('8.334.6043')
+u'8.334.604-3'
+>>> rut.clean('76793310-K')
+u'76.793.310-K'
+
+Strict RUT usage (does not allow imposible values)
+>>> rut = CLRutField(strict=True)
+
+>>> rut.clean('11-6')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
+
+# valid format, bad verifier.
+>>> rut.clean('11.111.111-0')
+Traceback (most recent call last):
+...
+ValidationError: [u'The Chilean RUT is not valid.']
+
+# Correct input, invalid format.
+>>> rut.clean('767484100')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
+>>> rut.clean('78.412.790-7')
+u'78.412.790-7'
+>>> rut.clean('8.334.6043')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
+>>> rut.clean('76793310-K')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter valid a Chilean RUT. The format is XX.XXX.XXX-X.']
+
+## CLRegionSelect #########################################################
+>>> from django.contrib.localflavor.cl.forms import CLRegionSelect
+>>> f = CLRegionSelect()
+
+>>> f.render('foo', 'bar')
+u'\nRegi\xf3n Metropolitana de Santiago \nRegi\xf3n de Tarapac\xe1 \nRegi\xf3n de Antofagasta \nRegi\xf3n de Atacama \nRegi\xf3n de Coquimbo \nRegi\xf3n de Valpara\xedso \nRegi\xf3n del Libertador Bernardo O'Higgins \nRegi\xf3n del Maule \nRegi\xf3n del B\xedo B\xedo \nRegi\xf3n de la Araucan\xeda \nRegi\xf3n de los Lagos \nRegi\xf3n de Ays\xe9n del General Carlos Ib\xe1\xf1ez del Campo \nRegi\xf3n de Magallanes y la Ant\xe1rtica Chilena \nRegi\xf3n de Los R\xedos \nRegi\xf3n de Arica-Parinacota \n '
+"""
diff --git a/tests/regressiontests/forms/localflavor/de.py b/tests/regressiontests/forms/localflavor/de.py
new file mode 100644
index 0000000000..e02323fc62
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/de.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ DE form fields.
+
+tests = r"""
+# DEZipCodeField ##############################################################
+
+>>> from django.contrib.localflavor.de.forms import DEZipCodeField
+>>> f = DEZipCodeField()
+>>> f.clean('99423')
+u'99423'
+>>> f.clean(' 99423')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+
+# DEStateSelect #############################################################
+
+>>> from django.contrib.localflavor.de.forms import DEStateSelect
+>>> w = DEStateSelect()
+>>> w.render('states', 'TH')
+u'\nBaden-Wuerttemberg \nBavaria \nBerlin \nBrandenburg \nBremen \nHamburg \nHessen \nMecklenburg-Western Pomerania \nLower Saxony \nNorth Rhine-Westphalia \nRhineland-Palatinate \nSaarland \nSaxony \nSaxony-Anhalt \nSchleswig-Holstein \nThuringia \n '
+
+# DEIdentityCardNumberField #################################################
+
+>>> from django.contrib.localflavor.de.forms import DEIdentityCardNumberField
+>>> f = DEIdentityCardNumberField()
+>>> f.clean('7549313035D-6004103-0903042-0')
+u'7549313035D-6004103-0903042-0'
+>>> f.clean('9786324830D 6104243 0910271 2')
+u'9786324830D-6104243-0910271-2'
+>>> f.clean('0434657485D-6407276-0508137-9')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid German identity card number in XXXXXXXXXXX-XXXXXXX-XXXXXXX-X format.']
+"""
diff --git a/tests/regressiontests/forms/localflavor/fi.py b/tests/regressiontests/forms/localflavor/fi.py
new file mode 100644
index 0000000000..f29fcc3c69
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/fi.py
@@ -0,0 +1,99 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ FI form fields.
+
+tests = r"""
+# FIZipCodeField #############################################################
+
+FIZipCodeField validates that the data is a valid FI zipcode.
+>>> from django.contrib.localflavor.fi.forms import FIZipCodeField
+>>> f = FIZipCodeField()
+>>> f.clean('20540')
+u'20540'
+>>> f.clean('20101')
+u'20101'
+>>> f.clean('20s40')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+>>> f.clean('205401')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = FIZipCodeField(required=False)
+>>> f.clean('20540')
+u'20540'
+>>> f.clean('20101')
+u'20101'
+>>> f.clean('20s40')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+>>> f.clean('205401')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+# FIMunicipalitySelect ###############################################################
+
+A Select widget that uses a list of Finnish municipalities as its choices.
+>>> from django.contrib.localflavor.fi.forms import FIMunicipalitySelect
+>>> w = FIMunicipalitySelect()
+>>> unicode(w.render('municipalities', 'turku'))
+u'\nAkaa \nAlah\xe4rm\xe4 \nAlaj\xe4rvi \nAlastaro \nAlavieska \nAlavus \nAnjalankoski \nArtj\xe4rvi \nAsikkala \nAskainen \nAskola \nAura \nBr\xe4nd\xf6 \nDragsfj\xe4rd \nEcker\xf6 \nElim\xe4ki \nEno \nEnonkoski \nEnonteki\xf6 \nEspoo \nEura \nEurajoki \nEvij\xe4rvi \nFinstr\xf6m \nForssa \nF\xf6gl\xf6 \nGeta \nHaapaj\xe4rvi \nHaapavesi \nHailuoto \nHalikko \nHalsua \nHamina \nHammarland \nHankasalmi \nHanko \nHarjavalta \nHartola \nHattula \nHauho \nHaukipudas \nHausj\xe4rvi \nHeinola \nHein\xe4vesi \nHelsinki \nHimanka \nHirvensalmi \nHollola \nHonkajoki \nHoutskari \nHuittinen \nHumppila \nHyrynsalmi \nHyvink\xe4\xe4 \nH\xe4meenkoski \nH\xe4meenkyr\xf6 \nH\xe4meenlinna \nIi \nIisalmi \nIitti \nIkaalinen \nIlmajoki \nIlomantsi \nImatra \nInari \nIni\xf6 \nInkoo \nIsojoki \nIsokyr\xf6 \nJaala \nJalasj\xe4rvi \nJanakkala \nJoensuu \nJokioinen \nJomala \nJoroinen \nJoutsa \nJoutseno \nJuankoski \nJurva \nJuuka \nJuupajoki \nJuva \nJyv\xe4skyl\xe4 \nJyv\xe4skyl\xe4n maalaiskunta \nJ\xe4mij\xe4rvi \nJ\xe4ms\xe4 \nJ\xe4ms\xe4nkoski \nJ\xe4rvenp\xe4\xe4 \nKaarina \nKaavi \nKajaani \nKalajoki \nKalvola \nKangasala \nKangasniemi \nKankaanp\xe4\xe4 \nKannonkoski \nKannus \nKarijoki \nKarjaa \nKarjalohja \nKarkkila \nKarstula \nKarttula \nKarvia \nKaskinen \nKauhajoki \nKauhava \nKauniainen \nKaustinen \nKeitele \nKemi \nKemij\xe4rvi \nKeminmaa \nKemi\xf6 \nKempele \nKerava \nKerim\xe4ki \nKestil\xe4 \nKes\xe4lahti \nKeuruu \nKihni\xf6 \nKiikala \nKiikoinen \nKiiminki \nKinnula \nKirkkonummi \nKisko \nKitee \nKittil\xe4 \nKiukainen \nKiuruvesi \nKivij\xe4rvi \nKokem\xe4ki \nKokkola \nKolari \nKonnevesi \nKontiolahti \nKorpilahti \nKorppoo \nKorsn\xe4s \nKortesj\xe4rvi \nKoskiTl \nKotka \nKouvola \nKristiinankaupunki \nKruunupyy \nKuhmalahti \nKuhmo \nKuhmoinen \nKumlinge \nKuopio \nKuortane \nKurikka \nKuru \nKustavi \nKuusamo \nKuusankoski \nKuusjoki \nKylm\xe4koski \nKyyj\xe4rvi \nK\xe4lvi\xe4 \nK\xe4rk\xf6l\xe4 \nK\xe4rs\xe4m\xe4ki \nK\xf6kar \nK\xf6yli\xf6 \nLahti \nLaihia \nLaitila \nLammi \nLapinj\xe4rvi \nLapinlahti \nLappaj\xe4rvi \nLappeenranta \nLappi \nLapua \nLaukaa \nLavia \nLehtim\xe4ki \nLeivonm\xe4ki \nLemi \nLemland \nLemp\xe4\xe4l\xe4 \nLemu \nLepp\xe4virta \nLestij\xe4rvi \nLieksa \nLieto \nLiljendal \nLiminka \nLiperi \nLohja \nLohtaja \nLoimaa \nLoppi \nLoviisa \nLuhanka \nLumijoki \nLumparland \nLuoto \nLuum\xe4ki \nLuvia \nMaalahti \nMaaninka \nMaarianhamina \nMarttila \nMasku \nMellil\xe4 \nMerij\xe4rvi \nMerikarvia \nMerimasku \nMiehikk\xe4l\xe4 \nMikkeli \nMouhij\xe4rvi \nMuhos \nMultia \nMuonio \nMustasaari \nMuurame \nMuurla \nMyn\xe4m\xe4ki \nMyrskyl\xe4 \nM\xe4nts\xe4l\xe4 \nM\xe4ntt\xe4 \nM\xe4ntyharju \nNaantali \nNakkila \nNastola \nNauvo \nNilsi\xe4 \nNivala \nNokia \nNoormarkku \nNousiainen \nNummi-Pusula \nNurmes \nNurmij\xe4rvi \nNurmo \nN\xe4rpi\xf6 \nOravainen \nOrimattila \nOrip\xe4\xe4 \nOrivesi \nOulainen \nOulu \nOulunsalo \nOutokumpu \nPadasjoki \nPaimio \nPaltamo \nParainen \nParikkala \nParkano \nPeders\xf6re \nPelkosenniemi \nPello \nPerho \nPernaja \nPerni\xf6 \nPertteli \nPertunmaa \nPet\xe4j\xe4vesi \nPieks\xe4m\xe4ki \nPielavesi \nPietarsaari \nPihtipudas \nPiikki\xf6 \nPiippola \nPirkkala \nPohja \nPolvij\xe4rvi \nPomarkku \nPori \nPornainen \nPorvoo \nPosio \nPudasj\xe4rvi \nPukkila \nPulkkila \nPunkaharju \nPunkalaidun \nPuolanka \nPuumala \nPyht\xe4\xe4 \nPyh\xe4joki \nPyh\xe4j\xe4rvi \nPyh\xe4nt\xe4 \nPyh\xe4ranta \nPyh\xe4selk\xe4 \nPylk\xf6nm\xe4ki \nP\xe4lk\xe4ne \nP\xf6yty\xe4 \nRaahe \nRaisio \nRantasalmi \nRantsila \nRanua \nRauma \nRautalampi \nRautavaara \nRautj\xe4rvi \nReisj\xe4rvi \nRenko \nRiihim\xe4ki \nRistiina \nRistij\xe4rvi \nRovaniemi \nRuokolahti \nRuotsinpyht\xe4\xe4 \nRuovesi \nRusko \nRym\xe4ttyl\xe4 \nR\xe4\xe4kkyl\xe4 \nSaarij\xe4rvi \nSalla \nSalo \nSaltvik \nSammatti \nSauvo \nSavitaipale \nSavonlinna \nSavonranta \nSavukoski \nSein\xe4joki \nSievi \nSiikainen \nSiikajoki \nSiilinj\xe4rvi \nSimo \nSipoo \nSiuntio \nSodankyl\xe4 \nSoini \nSomero \nSonkaj\xe4rvi \nSotkamo \nSottunga \nSulkava \nSund \nSuomenniemi \nSuomusj\xe4rvi \nSuomussalmi \nSuonenjoki \nSysm\xe4 \nS\xe4kyl\xe4 \nS\xe4rkisalo \nTaipalsaari \nTaivalkoski \nTaivassalo \nTammela \nTammisaari \nTampere \nTarvasjoki \nTervo \nTervola \nTeuva \nTohmaj\xe4rvi \nToholampi \nToivakka \nTornio \nTurku \nTuulos \nTuusniemi \nTuusula \nTyrn\xe4v\xe4 \nT\xf6ys\xe4 \nUllava \nUlvila \nUrjala \nUtaj\xe4rvi \nUtsjoki \nUurainen \nUusikaarlepyy \nUusikaupunki \nVaala \nVaasa \nVahto \nValkeakoski \nValkeala \nValtimo \nVammala \nVampula \nVantaa \nVarkaus \nVarpaisj\xe4rvi \nVehmaa \nVelkua \nVesanto \nVesilahti \nVeteli \nVierem\xe4 \nVihanti \nVihti \nViitasaari \nVilppula \nVimpeli \nVirolahti \nVirrat \nV\xe5rd\xf6 \nV\xe4h\xe4kyr\xf6 \nV\xe4stanfj\xe4rd \nV\xf6yri-Maksamaa \nYlih\xe4rm\xe4 \nYli-Ii \nYlikiiminki \nYlistaro \nYlitornio \nYlivieska \nYl\xe4maa \nYl\xe4ne \nYl\xf6j\xe4rvi \nYp\xe4j\xe4 \n\xc4ets\xe4 \n\xc4ht\xe4ri \n\xc4\xe4nekoski \n '
+
+# FISocialSecurityNumber ##############################################################
+
+>>> from django.contrib.localflavor.fi.forms import FISocialSecurityNumber
+>>> f = FISocialSecurityNumber()
+>>> f.clean('010101-0101')
+u'010101-0101'
+>>> f.clean('010101+0101')
+u'010101+0101'
+>>> f.clean('010101A0101')
+u'010101A0101'
+>>> f.clean('101010-0102')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Finnish social security number.']
+>>> f.clean('10a010-0101')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Finnish social security number.']
+>>> f.clean('101010-0\xe401')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Finnish social security number.']
+>>> f.clean('101010b0101')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Finnish social security number.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f = FISocialSecurityNumber(required=False)
+>>> f.clean('010101-0101')
+u'010101-0101'
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+"""
diff --git a/tests/regressiontests/forms/localflavor/fr.py b/tests/regressiontests/forms/localflavor/fr.py
new file mode 100644
index 0000000000..ea6c7899aa
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/fr.py
@@ -0,0 +1,224 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ FR form fields.
+
+tests = r"""
+# FRZipCodeField #############################################################
+
+FRZipCodeField validates that the data is a valid FR zipcode.
+>>> from django.contrib.localflavor.fr.forms import FRZipCodeField
+>>> f = FRZipCodeField()
+>>> f.clean('75001')
+u'75001'
+>>> f.clean('93200')
+u'93200'
+>>> f.clean('2A200')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+>>> f.clean('980001')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = FRZipCodeField(required=False)
+>>> f.clean('75001')
+u'75001'
+>>> f.clean('93200')
+u'93200'
+>>> f.clean('2A200')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+>>> f.clean('980001')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+
+# FRPhoneNumberField ##########################################################
+
+FRPhoneNumberField validates that the data is a valid french phone number.
+It's normalized to 0X XX XX XX XX format. Dots are valid too.
+>>> from django.contrib.localflavor.fr.forms import FRPhoneNumberField
+>>> f = FRPhoneNumberField()
+>>> f.clean('01 55 44 58 64')
+u'01 55 44 58 64'
+>>> f.clean('0155445864')
+u'01 55 44 58 64'
+>>> f.clean('01 5544 5864')
+u'01 55 44 58 64'
+>>> f.clean('01 55.44.58.64')
+u'01 55 44 58 64'
+>>> f.clean('01.55.44.58.64')
+u'01 55 44 58 64'
+>>> f.clean('01,55,44,58,64')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
+>>> f.clean('555 015 544')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = FRPhoneNumberField(required=False)
+>>> f.clean('01 55 44 58 64')
+u'01 55 44 58 64'
+>>> f.clean('0155445864')
+u'01 55 44 58 64'
+>>> f.clean('01 5544 5864')
+u'01 55 44 58 64'
+>>> f.clean('01 55.44.58.64')
+u'01 55 44 58 64'
+>>> f.clean('01.55.44.58.64')
+u'01 55 44 58 64'
+>>> f.clean('01,55,44,58,64')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
+>>> f.clean('555 015 544')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in 0X XX XX XX XX format.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+# FRDepartmentSelect ###############################################################
+
+FRDepartmentSelect is a Select widget that uses a list of french departments
+including DOM TOM
+>>> from django.contrib.localflavor.fr.forms import FRDepartmentSelect
+>>> w = FRDepartmentSelect()
+>>> print w.render('dep', 'Paris')
+
+01 - Ain
+02 - Aisne
+03 - Allier
+04 - Alpes-de-Haute-Provence
+05 - Hautes-Alpes
+06 - Alpes-Maritimes
+07 - Ardeche
+08 - Ardennes
+09 - Ariege
+10 - Aube
+11 - Aude
+12 - Aveyron
+13 - Bouches-du-Rhone
+14 - Calvados
+15 - Cantal
+16 - Charente
+17 - Charente-Maritime
+18 - Cher
+19 - Correze
+21 - Cote-d'Or
+22 - Cotes-d'Armor
+23 - Creuse
+24 - Dordogne
+25 - Doubs
+26 - Drome
+27 - Eure
+28 - Eure-et-Loire
+29 - Finistere
+2A - Corse-du-Sud
+2B - Haute-Corse
+30 - Gard
+31 - Haute-Garonne
+32 - Gers
+33 - Gironde
+34 - Herault
+35 - Ille-et-Vilaine
+36 - Indre
+37 - Indre-et-Loire
+38 - Isere
+39 - Jura
+40 - Landes
+41 - Loir-et-Cher
+42 - Loire
+43 - Haute-Loire
+44 - Loire-Atlantique
+45 - Loiret
+46 - Lot
+47 - Lot-et-Garonne
+48 - Lozere
+49 - Maine-et-Loire
+50 - Manche
+51 - Marne
+52 - Haute-Marne
+53 - Mayenne
+54 - Meurthe-et-Moselle
+55 - Meuse
+56 - Morbihan
+57 - Moselle
+58 - Nievre
+59 - Nord
+60 - Oise
+61 - Orne
+62 - Pas-de-Calais
+63 - Puy-de-Dome
+64 - Pyrenees-Atlantiques
+65 - Hautes-Pyrenees
+66 - Pyrenees-Orientales
+67 - Bas-Rhin
+68 - Haut-Rhin
+69 - Rhone
+70 - Haute-Saone
+71 - Saone-et-Loire
+72 - Sarthe
+73 - Savoie
+74 - Haute-Savoie
+75 - Paris
+76 - Seine-Maritime
+77 - Seine-et-Marne
+78 - Yvelines
+79 - Deux-Sevres
+80 - Somme
+81 - Tarn
+82 - Tarn-et-Garonne
+83 - Var
+84 - Vaucluse
+85 - Vendee
+86 - Vienne
+87 - Haute-Vienne
+88 - Vosges
+89 - Yonne
+90 - Territoire de Belfort
+91 - Essonne
+92 - Hauts-de-Seine
+93 - Seine-Saint-Denis
+94 - Val-de-Marne
+95 - Val-d'Oise
+2A - Corse du sud
+2B - Haute Corse
+971 - Guadeloupe
+972 - Martinique
+973 - Guyane
+974 - La Reunion
+975 - Saint-Pierre-et-Miquelon
+976 - Mayotte
+984 - Terres Australes et Antarctiques
+986 - Wallis et Futuna
+987 - Polynesie Francaise
+988 - Nouvelle-Caledonie
+
+"""
diff --git a/tests/regressiontests/forms/localflavor/generic.py b/tests/regressiontests/forms/localflavor/generic.py
new file mode 100644
index 0000000000..0dbe30d709
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/generic.py
@@ -0,0 +1,163 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ generic form fields.
+
+tests = r"""
+## Generic DateField ##########################################################
+
+>>> from django.contrib.localflavor.generic.forms import *
+
+A DateField that uses generic dd/mm/yy dates instead of mm/dd/yy where
+appropriate.
+
+>>> import datetime
+>>> f = DateField()
+>>> f.clean(datetime.date(2006, 10, 25))
+datetime.date(2006, 10, 25)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
+datetime.date(2006, 10, 25)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
+datetime.date(2006, 10, 25)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
+datetime.date(2006, 10, 25)
+>>> f.clean('2006-10-25')
+datetime.date(2006, 10, 25)
+>>> f.clean('25/10/2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('25/10/06')
+datetime.date(2006, 10, 25)
+>>> f.clean('Oct 25 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('October 25 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('October 25, 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('25 October 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('25 October, 2006')
+datetime.date(2006, 10, 25)
+>>> f.clean('2006-4-31')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean('200a-10-25')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean('10/25/06')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = DateField(required=False)
+>>> f.clean(None)
+>>> repr(f.clean(None))
+'None'
+>>> f.clean('')
+>>> repr(f.clean(''))
+'None'
+
+DateField accepts an optional input_formats parameter:
+>>> f = DateField(input_formats=['%Y %m %d'])
+>>> f.clean(datetime.date(2006, 10, 25))
+datetime.date(2006, 10, 25)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
+datetime.date(2006, 10, 25)
+>>> f.clean('2006 10 25')
+datetime.date(2006, 10, 25)
+
+The input_formats parameter overrides all default input formats,
+so the default formats won't work unless you specify them:
+>>> f.clean('2006-10-25')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean('25/10/2006')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+>>> f.clean('25/10/06')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date.']
+
+## Generic DateTimeField ######################################################
+
+A DateField that uses generic dd/mm/yy dates instead of mm/dd/yy where
+appropriate.
+
+>>> import datetime
+>>> f = DateTimeField()
+>>> f.clean(datetime.date(2006, 10, 25))
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
+datetime.datetime(2006, 10, 25, 14, 30, 59)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
+datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
+>>> f.clean('2006-10-25 14:30:45')
+datetime.datetime(2006, 10, 25, 14, 30, 45)
+>>> f.clean('2006-10-25 14:30:00')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('2006-10-25 14:30')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('2006-10-25')
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean('25/10/2006 14:30:45')
+datetime.datetime(2006, 10, 25, 14, 30, 45)
+>>> f.clean('25/10/2006 14:30:00')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('25/10/2006 14:30')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('25/10/2006')
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean('25/10/06 14:30:45')
+datetime.datetime(2006, 10, 25, 14, 30, 45)
+>>> f.clean('25/10/06 14:30:00')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('25/10/06 14:30')
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean('25/10/06')
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean('hello')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date/time.']
+>>> f.clean('2006-10-25 4:30 p.m.')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date/time.']
+
+DateField accepts an optional input_formats parameter:
+>>> f = DateTimeField(input_formats=['%Y %m %d %I:%M %p'])
+>>> f.clean(datetime.date(2006, 10, 25))
+datetime.datetime(2006, 10, 25, 0, 0)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
+datetime.datetime(2006, 10, 25, 14, 30)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
+datetime.datetime(2006, 10, 25, 14, 30, 59)
+>>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
+datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
+>>> f.clean('2006 10 25 2:30 PM')
+datetime.datetime(2006, 10, 25, 14, 30)
+
+The input_formats parameter overrides all default input formats,
+so the default formats won't work unless you specify them:
+>>> f.clean('2006-10-25 14:30:45')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid date/time.']
+
+>>> f = DateTimeField(required=False)
+>>> f.clean(None)
+>>> repr(f.clean(None))
+'None'
+>>> f.clean('')
+>>> repr(f.clean(''))
+'None'
+
+"""
diff --git a/tests/regressiontests/forms/localflavor/is_.py b/tests/regressiontests/forms/localflavor/is_.py
new file mode 100644
index 0000000000..6851441a79
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/is_.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ IS form fields.
+
+tests = r"""
+## ISIdNumberField #############################################################
+
+>>> from django.contrib.localflavor.is_.forms import *
+>>> f = ISIdNumberField()
+>>> f.clean('2308803449')
+u'230880-3449'
+>>> f.clean('230880-3449')
+u'230880-3449'
+>>> f.clean('230880 3449')
+u'230880-3449'
+>>> f.clean('230880343')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 10 characters (it has 9).']
+>>> f.clean('230880343234')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 11 characters (it has 12).']
+>>> f.clean('abcdefghijk')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Icelandic identification number. The format is XXXXXX-XXXX.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('2308803439')
+Traceback (most recent call last):
+...
+ValidationError: [u'The Icelandic identification number is not valid.']
+>>> f.clean('2308803440')
+u'230880-3440'
+>>> f = ISIdNumberField(required=False)
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+## ISPhoneNumberField #############################################################
+
+>>> from django.contrib.localflavor.is_.forms import *
+>>> f = ISPhoneNumberField()
+>>> f.clean('1234567')
+u'1234567'
+>>> f.clean('123 4567')
+u'1234567'
+>>> f.clean('123-4567')
+u'1234567'
+>>> f.clean('123-456')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+>>> f.clean('123456')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at least 7 characters (it has 6).']
+>>> f.clean('123456555')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
+>>> f.clean('abcdefg')
+Traceback (most recent call last):
+ValidationError: [u'Enter a valid value.']
+>>> f.clean(' 1234567 ')
+Traceback (most recent call last):
+...
+ValidationError: [u'Ensure this value has at most 8 characters (it has 9).']
+>>> f.clean(' 12367 ')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid value.']
+
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f = ISPhoneNumberField(required=False)
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+## ISPostalCodeSelect #############################################################
+
+>>> from django.contrib.localflavor.is_.forms import *
+>>> f = ISPostalCodeSelect()
+
+>>> f.render('foo', 'bar')
+u'\n101 Reykjav\xedk \n103 Reykjav\xedk \n104 Reykjav\xedk \n105 Reykjav\xedk \n107 Reykjav\xedk \n108 Reykjav\xedk \n109 Reykjav\xedk \n110 Reykjav\xedk \n111 Reykjav\xedk \n112 Reykjav\xedk \n113 Reykjav\xedk \n116 Kjalarnes \n121 Reykjav\xedk \n123 Reykjav\xedk \n124 Reykjav\xedk \n125 Reykjav\xedk \n127 Reykjav\xedk \n128 Reykjav\xedk \n129 Reykjav\xedk \n130 Reykjav\xedk \n132 Reykjav\xedk \n150 Reykjav\xedk \n155 Reykjav\xedk \n170 Seltjarnarnes \n172 Seltjarnarnes \n190 Vogar \n200 K\xf3pavogur \n201 K\xf3pavogur \n202 K\xf3pavogur \n203 K\xf3pavogur \n210 Gar\xf0ab\xe6r \n212 Gar\xf0ab\xe6r \n220 Hafnarfj\xf6r\xf0ur \n221 Hafnarfj\xf6r\xf0ur \n222 Hafnarfj\xf6r\xf0ur \n225 \xc1lftanes \n230 Reykjanesb\xe6r \n232 Reykjanesb\xe6r \n233 Reykjanesb\xe6r \n235 Keflav\xedkurflugv\xf6llur \n240 Grindav\xedk \n245 Sandger\xf0i \n250 Gar\xf0ur \n260 Reykjanesb\xe6r \n270 Mosfellsb\xe6r \n300 Akranes \n301 Akranes \n302 Akranes \n310 Borgarnes \n311 Borgarnes \n320 Reykholt \xed Borgarfir\xf0i \n340 Stykkish\xf3lmur \n345 Flatey \xe1 Brei\xf0afir\xf0i \n350 Grundarfj\xf6r\xf0ur \n355 \xd3lafsv\xedk \n356 Sn\xe6fellsb\xe6r \n360 Hellissandur \n370 B\xfa\xf0ardalur \n371 B\xfa\xf0ardalur \n380 Reykh\xf3lahreppur \n400 \xcdsafj\xf6r\xf0ur \n401 \xcdsafj\xf6r\xf0ur \n410 Hn\xedfsdalur \n415 Bolungarv\xedk \n420 S\xfa\xf0av\xedk \n425 Flateyri \n430 Su\xf0ureyri \n450 Patreksfj\xf6r\xf0ur \n451 Patreksfj\xf6r\xf0ur \n460 T\xe1lknafj\xf6r\xf0ur \n465 B\xedldudalur \n470 \xdeingeyri \n471 \xdeingeyri \n500 Sta\xf0ur \n510 H\xf3lmav\xedk \n512 H\xf3lmav\xedk \n520 Drangsnes \n522 Kj\xf6rvogur \n523 B\xe6r \n524 Nor\xf0urfj\xf6r\xf0ur \n530 Hvammstangi \n531 Hvammstangi \n540 Bl\xf6ndu\xf3s \n541 Bl\xf6ndu\xf3s \n545 Skagastr\xf6nd \n550 Sau\xf0\xe1rkr\xf3kur \n551 Sau\xf0\xe1rkr\xf3kur \n560 Varmahl\xed\xf0 \n565 Hofs\xf3s \n566 Hofs\xf3s \n570 Flj\xf3t \n580 Siglufj\xf6r\xf0ur \n600 Akureyri \n601 Akureyri \n602 Akureyri \n603 Akureyri \n610 Greniv\xedk \n611 Gr\xedmsey \n620 Dalv\xedk \n621 Dalv\xedk \n625 \xd3lafsfj\xf6r\xf0ur \n630 Hr\xedsey \n640 H\xfasav\xedk \n641 H\xfasav\xedk \n645 Fossh\xf3ll \n650 Laugar \n660 M\xfdvatn \n670 K\xf3pasker \n671 K\xf3pasker \n675 Raufarh\xf6fn \n680 \xde\xf3rsh\xf6fn \n681 \xde\xf3rsh\xf6fn \n685 Bakkafj\xf6r\xf0ur \n690 Vopnafj\xf6r\xf0ur \n700 Egilssta\xf0ir \n701 Egilssta\xf0ir \n710 Sey\xf0isfj\xf6r\xf0ur \n715 Mj\xf3ifj\xf6r\xf0ur \n720 Borgarfj\xf6r\xf0ur eystri \n730 Rey\xf0arfj\xf6r\xf0ur \n735 Eskifj\xf6r\xf0ur \n740 Neskaupsta\xf0ur \n750 F\xe1skr\xfa\xf0sfj\xf6r\xf0ur \n755 St\xf6\xf0varfj\xf6r\xf0ur \n760 Brei\xf0dalsv\xedk \n765 Dj\xfapivogur \n780 H\xf6fn \xed Hornafir\xf0i \n781 H\xf6fn \xed Hornafir\xf0i \n785 \xd6r\xe6fi \n800 Selfoss \n801 Selfoss \n802 Selfoss \n810 Hverager\xf0i \n815 \xdeorl\xe1ksh\xf6fn \n820 Eyrarbakki \n825 Stokkseyri \n840 Laugarvatn \n845 Fl\xfa\xf0ir \n850 Hella \n851 Hella \n860 Hvolsv\xf6llur \n861 Hvolsv\xf6llur \n870 V\xedk \n871 V\xedk \n880 Kirkjub\xe6jarklaustur \n900 Vestmannaeyjar \n902 Vestmannaeyjar \n '
+"""
+
diff --git a/tests/regressiontests/forms/localflavor/it.py b/tests/regressiontests/forms/localflavor/it.py
new file mode 100644
index 0000000000..10023a7cf6
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/it.py
@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ IT form fields.
+
+tests = r"""
+# ITZipCodeField #############################################################
+
+>>> from django.contrib.localflavor.it.forms import ITZipCodeField
+>>> f = ITZipCodeField()
+>>> f.clean('00100')
+u'00100'
+>>> f.clean(' 00100')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid zip code.']
+
+# ITRegionSelect #############################################################
+
+>>> from django.contrib.localflavor.it.forms import ITRegionSelect
+>>> w = ITRegionSelect()
+>>> w.render('regions', 'PMN')
+u'\nAbruzzo \nBasilicata \nCalabria \nCampania \nEmilia-Romagna \nFriuli-Venezia Giulia \nLazio \nLiguria \nLombardia \nMarche \nMolise \nPiemonte \nPuglia \nSardegna \nSicilia \nToscana \nTrentino-Alto Adige \nUmbria \nValle d\u2019Aosta \nVeneto \n '
+
+# ITSocialSecurityNumberField #################################################
+
+>>> from django.contrib.localflavor.it.forms import ITSocialSecurityNumberField
+>>> f = ITSocialSecurityNumberField()
+>>> f.clean('LVSGDU99T71H501L')
+u'LVSGDU99T71H501L'
+>>> f.clean('LBRRME11A01L736W')
+u'LBRRME11A01L736W'
+>>> f.clean('lbrrme11a01l736w')
+u'LBRRME11A01L736W'
+>>> f.clean('LBR RME 11A01 L736W')
+u'LBRRME11A01L736W'
+>>> f.clean('LBRRME11A01L736A')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Social Security number.']
+>>> f.clean('%BRRME11A01L736W')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid Social Security number.']
+
+# ITVatNumberField ###########################################################
+
+>>> from django.contrib.localflavor.it.forms import ITVatNumberField
+>>> f = ITVatNumberField()
+>>> f.clean('07973780013')
+u'07973780013'
+>>> f.clean('7973780013')
+u'07973780013'
+>>> f.clean(7973780013)
+u'07973780013'
+>>> f.clean('07973780014')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid VAT number.']
+>>> f.clean('A7973780013')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid VAT number.']
+"""
diff --git a/tests/regressiontests/forms/localflavor/jp.py b/tests/regressiontests/forms/localflavor/jp.py
new file mode 100644
index 0000000000..7b5b82667c
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/jp.py
@@ -0,0 +1,106 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ JP form fields.
+
+tests = r"""
+# JPPostalCodeField ###############################################################
+
+A form field that validates its input is a Japanese postcode.
+
+Accepts 7 digits(with/out hyphen).
+>>> from django.contrib.localflavor.jp.forms import JPPostalCodeField
+>>> f = JPPostalCodeField()
+>>> f.clean('251-0032')
+u'2510032'
+>>> f.clean('2510032')
+u'2510032'
+>>> f.clean('2510-032')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
+>>> f.clean('251a0032')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
+>>> f.clean('a51-0032')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
+>>> f.clean('25100321')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = JPPostalCodeField(required=False)
+>>> f.clean('251-0032')
+u'2510032'
+>>> f.clean('2510032')
+u'2510032'
+>>> f.clean('2510-032')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXXXXXX or XXX-XXXX.']
+>>> f.clean('')
+u''
+>>> f.clean(None)
+u''
+
+# JPPrefectureSelect ###############################################################
+
+A Select widget that uses a list of Japanese prefectures as its choices.
+>>> from django.contrib.localflavor.jp.forms import JPPrefectureSelect
+>>> w = JPPrefectureSelect()
+>>> print w.render('prefecture', 'kanagawa')
+
+Hokkaido
+Aomori
+Iwate
+Miyagi
+Akita
+Yamagata
+Fukushima
+Ibaraki
+Tochigi
+Gunma
+Saitama
+Chiba
+Tokyo
+Kanagawa
+Yamanashi
+Nagano
+Niigata
+Toyama
+Ishikawa
+Fukui
+Gifu
+Shizuoka
+Aichi
+Mie
+Shiga
+Kyoto
+Osaka
+Hyogo
+Nara
+Wakayama
+Tottori
+Shimane
+Okayama
+Hiroshima
+Yamaguchi
+Tokushima
+Kagawa
+Ehime
+Kochi
+Fukuoka
+Saga
+Nagasaki
+Kumamoto
+Oita
+Miyazaki
+Kagoshima
+Okinawa
+
+"""
diff --git a/tests/regressiontests/forms/localflavor/nl.py b/tests/regressiontests/forms/localflavor/nl.py
new file mode 100644
index 0000000000..38bbf72384
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/nl.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ NL form fields.
+
+tests = r"""
+# NLPhoneNumberField ########################################################
+
+>>> from django.contrib.localflavor.nl.forms import NLPhoneNumberField
+>>> f = NLPhoneNumberField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean('012-3456789')
+'012-3456789'
+>>> f.clean('0123456789')
+'0123456789'
+>>> f.clean('+31-12-3456789')
+'+31-12-3456789'
+>>> f.clean('(0123) 456789')
+'(0123) 456789'
+>>> f.clean('foo')
+Traceback (most recent call last):
+ ...
+ValidationError: [u'Enter a valid phone number']
+
+# NLZipCodeField ############################################################
+
+>>> from django.contrib.localflavor.nl.forms import NLZipCodeField
+>>> f = NLZipCodeField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean('1234ab')
+u'1234 AB'
+>>> f.clean('1234 ab')
+u'1234 AB'
+>>> f.clean('1234 AB')
+u'1234 AB'
+>>> f.clean('0123AB')
+Traceback (most recent call last):
+ ...
+ValidationError: [u'Enter a valid postal code']
+>>> f.clean('foo')
+Traceback (most recent call last):
+ ...
+ValidationError: [u'Enter a valid postal code']
+
+# NLSoFiNumberField #########################################################
+
+>>> from django.contrib.localflavor.nl.forms import NLSoFiNumberField
+>>> f = NLSoFiNumberField(required=False)
+>>> f.clean('')
+u''
+>>> f.clean('123456782')
+'123456782'
+>>> f.clean('000000000')
+Traceback (most recent call last):
+ ...
+ValidationError: [u'Enter a valid SoFi number']
+>>> f.clean('123456789')
+Traceback (most recent call last):
+ ...
+ValidationError: [u'Enter a valid SoFi number']
+>>> f.clean('foo')
+Traceback (most recent call last):
+ ...
+ValidationError: [u'Enter a valid SoFi number']
+
+# NLProvinceSelect ##########################################################
+
+>>> from django.contrib.localflavor.nl.forms import NLProvinceSelect
+>>> s = NLProvinceSelect()
+>>> s.render('provinces', 'OV')
+u'\nDrente \nFlevoland \nFriesland \nGelderland \nGroningen \nLimburg \nNoord-Brabant \nNoord-Holland \nOverijssel \nUtrecht \nZeeland \nZuid-Holland \n '
+"""
diff --git a/tests/regressiontests/forms/localflavor/pl.py b/tests/regressiontests/forms/localflavor/pl.py
new file mode 100644
index 0000000000..be8437208b
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/pl.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ PL form fields.
+
+tests = r"""
+# PLVoivodeshipSelect ##########################################################
+
+>>> from django.contrib.localflavor.pl.forms import PLVoivodeshipSelect
+>>> f = PLVoivodeshipSelect()
+>>> f.render('voivodeships','pomerania')
+u'\nLower Silesia \nKuyavia-Pomerania \nLublin \nLubusz \nLodz \nLesser Poland \nMasovia \nOpole \nSubcarpatia \nPodlasie \nPomerania \nSilesia \nSwietokrzyskie \nWarmia-Masuria \nGreater Poland \nWest Pomerania \n '
+
+# PLAdministrativeUnitSelect ##########################################################
+
+>>> from django.contrib.localflavor.pl.forms import PLAdministrativeUnitSelect
+>>> f = PLAdministrativeUnitSelect()
+>>> f.render('administrativeunit','katowice')
+u'\nWroc\u0142aw \nJelenia G\xf3ra \nLegnica \nboles\u0142awiecki \ndzier\u017coniowski \ng\u0142ogowski \ng\xf3rowski \njaworski \njeleniog\xf3rski \nkamiennog\xf3rski \nk\u0142odzki \nlegnicki \nluba\u0144ski \nlubi\u0144ski \nlw\xf3wecki \nmilicki \nole\u015bnicki \no\u0142awski \npolkowicki \nstrzeli\u0144ski \n\u015bredzki \n\u015bwidnicki \ntrzebnicki \nwa\u0142brzyski \nwo\u0142owski \nwroc\u0142awski \nz\u0105bkowicki \nzgorzelecki \nz\u0142otoryjski \nBydgoszcz \nToru\u0144 \nW\u0142oc\u0142awek \nGrudzi\u0105dz \naleksandrowski \nbrodnicki \nbydgoski \nche\u0142mi\u0144ski \ngolubsko-dobrzy\u0144ski \ngrudzi\u0105dzki \ninowroc\u0142awski \nlipnowski \nmogile\u0144ski \nnakielski \nradziejowski \nrypi\u0144ski \ns\u0119pole\u0144ski \n\u015bwiecki \ntoru\u0144ski \ntucholski \nw\u0105brzeski \nwroc\u0142awski \n\u017ani\u0144ski \nLublin \nBia\u0142a Podlaska \nChe\u0142m \nZamo\u015b\u0107 \nbialski \nbi\u0142gorajski \nche\u0142mski \nhrubieszowski \njanowski \nkrasnostawski \nkra\u015bnicki \nlubartowski \nlubelski \n\u0142\u0119czy\u0144ski \n\u0142ukowski \nopolski \nparczewski \npu\u0142awski \nradzy\u0144ski \nrycki \n\u015bwidnicki \ntomaszowski \nw\u0142odawski \nzamojski \nGorz\xf3w Wielkopolski \nZielona G\xf3ra \ngorzowski \nkro\u015bnie\u0144ski \nmi\u0119dzyrzecki \nnowosolski \ns\u0142ubicki \nstrzelecko-drezdenecki \nsule\u0144ci\u0144ski \n\u015bwiebodzi\u0144ski \nwschowski \nzielonog\xf3rski \n\u017caga\u0144ski \n\u017carski \n\u0141\xf3d\u017a \nPiotrk\xf3w Trybunalski \nSkierniewice \nbe\u0142chatowski \nbrzezi\u0144ski \nkutnowski \n\u0142aski \n\u0142\u0119czycki \n\u0142owicki \n\u0142\xf3dzki wschodni \nopoczy\u0144ski \npabianicki \npaj\u0119cza\u0144ski \npiotrkowski \npodd\u0119bicki \nradomszcza\u0144ski \nrawski \nsieradzki \nskierniewicki \ntomaszowski \nwielu\u0144ski \nwieruszowski \nzdu\u0144skowolski \nzgierski \nKrak\xf3w \nTarn\xf3w \nNowy S\u0105cz \nboche\u0144ski \nbrzeski \nchrzanowski \nd\u0105browski \ngorlicki \nkrakowski \nlimanowski \nmiechowski \nmy\u015blenicki \nnowos\u0105decki \nnowotarski \nolkuski \no\u015bwi\u0119cimski \nproszowicki \nsuski \ntarnowski \ntatrza\u0144ski \nwadowicki \nwielicki \nWarszawa \nOstro\u0142\u0119ka \nP\u0142ock \nRadom \nSiedlce \nbia\u0142obrzeski \nciechanowski \ngarwoli\u0144ski \ngostyni\u0144ski \ngrodziski \ngr\xf3jecki \nkozenicki \nlegionowski \nlipski \n\u0142osicki \nmakowski \nmi\u0144ski \nm\u0142awski \nnowodworski \nostro\u0142\u0119cki \nostrowski \notwocki \npiaseczy\u0144ski \np\u0142ocki \np\u0142o\u0144ski \npruszkowski \nprzasnyski \nprzysuski \npu\u0142tuski \nradomski \nsiedlecki \nsierpecki \nsochaczewski \nsoko\u0142owski \nszyd\u0142owiecki \nwarszawski zachodni \nw\u0119growski \nwo\u0142omi\u0144ski \nwyszkowski \nzwole\u0144ski \n\u017curomi\u0144ski \n\u017cyrardowski \nOpole \nbrzeski \ng\u0142ubczyski \nk\u0119dzierzy\u0144ski-kozielski \nkluczborski \nkrapkowicki \nnamys\u0142owski \nnyski \noleski \nopolski \nprudnicki \nstrzelecki \nRzesz\xf3w \nKrosno \nPrzemy\u015bl \nTarnobrzeg \nbieszczadzki \nbrzozowski \nd\u0119bicki \njaros\u0142awski \njasielski \nkolbuszowski \nkro\u015bnie\u0144ski \nleski \nle\u017cajski \nlubaczowski \n\u0142a\u0144cucki \nmielecki \nni\u017ca\u0144ski \nprzemyski \nprzeworski \nropczycko-s\u0119dziszowski \nrzeszowski \nsanocki \nstalowowolski \nstrzy\u017cowski \ntarnobrzeski \nBia\u0142ystok \n\u0141om\u017ca \nSuwa\u0142ki \naugustowski \nbia\u0142ostocki \nbielski \ngrajewski \nhajnowski \nkolne\u0144ski \n\u0142om\u017cy\u0144ski \nmoniecki \nsejne\u0144ski \nsiematycki \nsok\xf3lski \nsuwalski \nwysokomazowiecki \nzambrowski \nGda\u0144sk \nGdynia \nS\u0142upsk \nSopot \nbytowski \nchojnicki \ncz\u0142uchowski \nkartuski \nko\u015bcierski \nkwidzy\u0144ski \nl\u0119borski \nmalborski \nnowodworski \ngda\u0144ski \npucki \ns\u0142upski \nstarogardzki \nsztumski \ntczewski \nwejcherowski \nKatowice \nBielsko-Bia\u0142a \nBytom \nChorz\xf3w \nCz\u0119stochowa \nD\u0105browa G\xf3rnicza \nGliwice \nJastrz\u0119bie Zdr\xf3j \nJaworzno \nMys\u0142owice \nPiekary \u015al\u0105skie \nRuda \u015al\u0105ska \nRybnik \nSiemianowice \u015al\u0105skie \nSosnowiec \n\u015awi\u0119toch\u0142owice \nTychy \nZabrze \n\u017bory \nb\u0119dzi\u0144ski \nbielski \nbieru\u0144sko-l\u0119dzi\u0144ski \ncieszy\u0144ski \ncz\u0119stochowski \ngliwicki \nk\u0142obucki \nlubliniecki \nmiko\u0142owski \nmyszkowski \npszczy\u0144ski \nraciborski \nrybnicki \ntarnog\xf3rski \nwodzis\u0142awski \nzawiercia\u0144ski \n\u017cywiecki \nKielce \nbuski \nj\u0119drzejowski \nkazimierski \nkielecki \nkonecki \nopatowski \nostrowiecki \npi\u0144czowski \nsandomierski \nskar\u017cyski \nstarachowicki \nstaszowski \nw\u0142oszczowski \nOlsztyn \nElbl\u0105g \nbartoszycki \nbraniewski \ndzia\u0142dowski \nelbl\u0105ski \ne\u0142cki \ngi\u017cycki \ngo\u0142dapski \ni\u0142awski \nk\u0119trzy\u0144ski \nlidzbarski \nmr\u0105gowski \nnidzicki \nnowomiejski \nolecki \nolszty\u0144ski \nostr\xf3dzki \npiski \nszczycie\u0144ski \nw\u0119gorzewski \nPozna\u0144 \nKalisz \nKonin \nLeszno \nchodziejski \nczarnkowsko-trzcianecki \ngnie\u017anie\u0144ski \ngosty\u0144ski \ngrodziski \njaroci\u0144ski \nkaliski \nk\u0119pi\u0144ski \nkolski \nkoni\u0144ski \nko\u015bcia\u0144ski \nkrotoszy\u0144ski \nleszczy\u0144ski \nmi\u0119dzychodzki \nnowotomyski \nobornicki \nostrowski \nostrzeszowski \npilski \npleszewski \npozna\u0144ski \nrawicki \ns\u0142upecki \nszamotulski \n\u015bredzki \n\u015bremski \nturecki \nw\u0105growiecki \nwolszty\u0144ski \nwrzesi\u0144ski \nz\u0142otowski \nbia\u0142ogardzki \nchoszcze\u0144ski \ndrawski \ngoleniowski \ngryficki \ngryfi\u0144ski \nkamie\u0144ski \nko\u0142obrzeski \nkoszali\u0144ski \n\u0142obeski \nmy\u015bliborski \npolicki \npyrzycki \ns\u0142awie\u0144ski \nstargardzki \nszczecinecki \n\u015bwidwi\u0144ski \nwa\u0142ecki \n '
+
+# PLPostalCodeField ##############################################################
+
+>>> from django.contrib.localflavor.pl.forms import PLPostalCodeField
+>>> f = PLPostalCodeField()
+>>> f.clean('43--434')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XX-XXX.']
+>>> f.clean('41-403')
+u'41-403'
+
+# PLTaxNumberField ###############################################################
+
+>>> from django.contrib.localflavor.pl.forms import PLTaxNumberField
+>>> f = PLTaxNumberField()
+>>> f.clean('43-343-234-323')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a tax number field (NIP) in the format XXX-XXX-XX-XX or XX-XX-XXX-XXX.']
+>>> f.clean('43-34-234-323')
+u'43-34-234-323'
+>>> f.clean('433-344-24-23')
+u'433-344-24-23'
+
+# PLNationalIdentificationNumberField ############################################
+
+>>> from django.contrib.localflavor.pl.forms import PLNationalIdentificationNumberField
+>>> f = PLNationalIdentificationNumberField()
+>>> f.clean('80071610614')
+u'80071610614'
+>>> f.clean('80071610610')
+Traceback (most recent call last):
+...
+ValidationError: [u'Wrong checksum for the National Identification Number.']
+>>> f.clean('80')
+Traceback (most recent call last):
+...
+ValidationError: [u'National Identification Number consists of 11 digits.']
+>>> f.clean('800716106AA')
+Traceback (most recent call last):
+...
+ValidationError: [u'National Identification Number consists of 11 digits.']
+"""
diff --git a/tests/regressiontests/forms/localflavor/sk.py b/tests/regressiontests/forms/localflavor/sk.py
new file mode 100644
index 0000000000..069a99b2d2
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/sk.py
@@ -0,0 +1,31 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ SK form fields.
+
+tests = r"""
+# SKPostalCodeField #########################################################
+
+>>> from django.contrib.localflavor.sk.forms import SKPostalCodeField
+>>> f = SKPostalCodeField()
+>>> f.clean('84545x')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postal code in the format XXXXX or XXX XX.']
+>>> f.clean('91909')
+u'91909'
+>>> f.clean('917 01')
+u'91701'
+
+# SKRegionSelect ############################################################
+
+>>> from django.contrib.localflavor.sk.forms import SKRegionSelect
+>>> w = SKRegionSelect()
+>>> w.render('regions', 'TT')
+u'\nBanska Bystrica region \nBratislava region \nKosice region \nNitra region \nPresov region \nTrencin region \nTrnava region \nZilina region \n '
+
+# SKDistrictSelect ##########################################################
+
+>>> from django.contrib.localflavor.sk.forms import SKDistrictSelect
+>>> w = SKDistrictSelect()
+>>> w.render('Districts', 'RK')
+u'\nBanska Bystrica \nBanska Stiavnica \nBardejov \nBanovce nad Bebravou \nBrezno \nBratislava I \nBratislava II \nBratislava III \nBratislava IV \nBratislava V \nBytca \nCadca \nDetva \nDolny Kubin \nDunajska Streda \nGalanta \nGelnica \nHlohovec \nHumenne \nIlava \nKezmarok \nKomarno \nKosice I \nKosice II \nKosice III \nKosice IV \nKosice - okolie \nKrupina \nKysucke Nove Mesto \nLevice \nLevoca \nLiptovsky Mikulas \nLucenec \nMalacky \nMartin \nMedzilaborce \nMichalovce \nMyjava \nNamestovo \nNitra \nNove Mesto nad Vahom \nNove Zamky \nPartizanske \nPezinok \nPiestany \nPoltar \nPoprad \nPovazska Bystrica \nPresov \nPrievidza \nPuchov \nRevuca \nRimavska Sobota \nRoznava \nRuzomberok \nSabinov \nSenec \nSenica \nSkalica \nSnina \nSobrance \nSpisska Nova Ves \nStara Lubovna \nStropkov \nSvidnik \nSala \nTopolcany \nTrebisov \nTrencin \nTrnava \nTurcianske Teplice \nTvrdosin \nVelky Krtis \nVranov nad Toplou \nZlate Moravce \nZvolen \nZarnovica \nZiar nad Hronom \nZilina \n '
+"""
diff --git a/tests/regressiontests/forms/localflavor/uk.py b/tests/regressiontests/forms/localflavor/uk.py
new file mode 100644
index 0000000000..d7848f70a8
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/uk.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ UK form fields.
+
+tests = r"""
+# UKPostcodeField #############################################################
+
+UKPostcodeField validates that the data is a valid UK postcode.
+>>> from django.contrib.localflavor.uk.forms import UKPostcodeField
+>>> f = UKPostcodeField()
+>>> f.clean('BT32 4PX')
+u'BT32 4PX'
+>>> f.clean('GIR 0AA')
+u'GIR 0AA'
+>>> f.clean('BT324PX')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
+>>> f.clean('1NV 4L1D')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = UKPostcodeField(required=False)
+>>> f.clean('BT32 4PX')
+u'BT32 4PX'
+>>> f.clean('GIR 0AA')
+u'GIR 0AA'
+>>> f.clean('1NV 4L1D')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
+>>> f.clean('BT324PX')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a postcode. A space is required between the two postcode parts.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+"""
diff --git a/tests/regressiontests/forms/localflavor/us.py b/tests/regressiontests/forms/localflavor/us.py
new file mode 100644
index 0000000000..dfbfef681d
--- /dev/null
+++ b/tests/regressiontests/forms/localflavor/us.py
@@ -0,0 +1,260 @@
+# -*- coding: utf-8 -*-
+# Tests for the contrib/localflavor/ US form fields.
+
+tests = r"""
+# USZipCodeField ##############################################################
+
+USZipCodeField validates that the data is either a five-digit U.S. zip code or
+a zip+4.
+>>> from django.contrib.localflavor.us.forms import USZipCodeField
+>>> f = USZipCodeField()
+>>> f.clean('60606')
+u'60606'
+>>> f.clean(60606)
+u'60606'
+>>> f.clean('04000')
+u'04000'
+>>> f.clean('4000')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
+>>> f.clean('60606-1234')
+u'60606-1234'
+>>> f.clean('6060-1234')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
+>>> f.clean('60606-')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = USZipCodeField(required=False)
+>>> f.clean('60606')
+u'60606'
+>>> f.clean(60606)
+u'60606'
+>>> f.clean('04000')
+u'04000'
+>>> f.clean('4000')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
+>>> f.clean('60606-1234')
+u'60606-1234'
+>>> f.clean('6060-1234')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
+>>> f.clean('60606-')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a zip code in the format XXXXX or XXXXX-XXXX.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+# USPhoneNumberField ##########################################################
+
+USPhoneNumberField validates that the data is a valid U.S. phone number,
+including the area code. It's normalized to XXX-XXX-XXXX format.
+>>> from django.contrib.localflavor.us.forms import USPhoneNumberField
+>>> f = USPhoneNumberField()
+>>> f.clean('312-555-1212')
+u'312-555-1212'
+>>> f.clean('3125551212')
+u'312-555-1212'
+>>> f.clean('312 555-1212')
+u'312-555-1212'
+>>> f.clean('(312) 555-1212')
+u'312-555-1212'
+>>> f.clean('312 555 1212')
+u'312-555-1212'
+>>> f.clean('312.555.1212')
+u'312-555-1212'
+>>> f.clean('312.555-1212')
+u'312-555-1212'
+>>> f.clean(' (312) 555.1212 ')
+u'312-555-1212'
+>>> f.clean('555-1212')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
+>>> f.clean('312-55-1212')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = USPhoneNumberField(required=False)
+>>> f.clean('312-555-1212')
+u'312-555-1212'
+>>> f.clean('3125551212')
+u'312-555-1212'
+>>> f.clean('312 555-1212')
+u'312-555-1212'
+>>> f.clean('(312) 555-1212')
+u'312-555-1212'
+>>> f.clean('312 555 1212')
+u'312-555-1212'
+>>> f.clean('312.555.1212')
+u'312-555-1212'
+>>> f.clean('312.555-1212')
+u'312-555-1212'
+>>> f.clean(' (312) 555.1212 ')
+u'312-555-1212'
+>>> f.clean('555-1212')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
+>>> f.clean('312-55-1212')
+Traceback (most recent call last):
+...
+ValidationError: [u'Phone numbers must be in XXX-XXX-XXXX format.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+# USStateField ################################################################
+
+USStateField validates that the data is either an abbreviation or name of a
+U.S. state.
+>>> from django.contrib.localflavor.us.forms import USStateField
+>>> f = USStateField()
+>>> f.clean('il')
+u'IL'
+>>> f.clean('IL')
+u'IL'
+>>> f.clean('illinois')
+u'IL'
+>>> f.clean(' illinois ')
+u'IL'
+>>> f.clean(60606)
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a U.S. state or territory.']
+>>> f.clean(None)
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+>>> f.clean('')
+Traceback (most recent call last):
+...
+ValidationError: [u'This field is required.']
+
+>>> f = USStateField(required=False)
+>>> f.clean('il')
+u'IL'
+>>> f.clean('IL')
+u'IL'
+>>> f.clean('illinois')
+u'IL'
+>>> f.clean(' illinois ')
+u'IL'
+>>> f.clean(60606)
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a U.S. state or territory.']
+>>> f.clean(None)
+u''
+>>> f.clean('')
+u''
+
+# USStateSelect ###############################################################
+
+USStateSelect is a Select widget that uses a list of U.S. states/territories
+as its choices.
+>>> from django.contrib.localflavor.us.forms import USStateSelect
+>>> w = USStateSelect()
+>>> print w.render('state', 'IL')
+
+Alabama
+Alaska
+American Samoa
+Arizona
+Arkansas
+California
+Colorado
+Connecticut
+Delaware
+District of Columbia
+Federated States of Micronesia
+Florida
+Georgia
+Guam
+Hawaii
+Idaho
+Illinois
+Indiana
+Iowa
+Kansas
+Kentucky
+Louisiana
+Maine
+Marshall Islands
+Maryland
+Massachusetts
+Michigan
+Minnesota
+Mississippi
+Missouri
+Montana
+Nebraska
+Nevada
+New Hampshire
+New Jersey
+New Mexico
+New York
+North Carolina
+North Dakota
+Northern Mariana Islands
+Ohio
+Oklahoma
+Oregon
+Palau
+Pennsylvania
+Puerto Rico
+Rhode Island
+South Carolina
+South Dakota
+Tennessee
+Texas
+Utah
+Vermont
+Virgin Islands
+Virginia
+Washington
+West Virginia
+Wisconsin
+Wyoming
+
+
+# USSocialSecurityNumberField #################################################
+>>> from django.contrib.localflavor.us.forms import USSocialSecurityNumberField
+>>> f = USSocialSecurityNumberField()
+>>> f.clean('987-65-4330')
+u'987-65-4330'
+>>> f.clean('987654330')
+u'987-65-4330'
+>>> f.clean('078-05-1120')
+Traceback (most recent call last):
+...
+ValidationError: [u'Enter a valid U.S. Social Security number in XXX-XX-XXXX format.']
+"""
diff --git a/tests/regressiontests/forms/regressions.py b/tests/regressiontests/forms/regressions.py
index 3212e20170..1bfb425188 100644
--- a/tests/regressiontests/forms/regressions.py
+++ b/tests/regressiontests/forms/regressions.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Tests to prevent against recurrences of earlier bugs.
-regression_tests = r"""
+tests = r"""
It should be possible to re-use attribute dictionaries (#3810)
>>> from django.newforms import *
>>> extra_attrs = {'class': 'special'}
diff --git a/tests/regressiontests/forms/tests.py b/tests/regressiontests/forms/tests.py
index 616d6e5ff5..a732f9fdb0 100644
--- a/tests/regressiontests/forms/tests.py
+++ b/tests/regressiontests/forms/tests.py
@@ -1,3987 +1,54 @@
# -*- coding: utf-8 -*-
-from localflavor import localflavor_tests
-from regressions import regression_tests
-from util import util_tests
-
-form_tests = r"""
->>> from django.newforms import *
->>> from django.newforms.widgets import RadioFieldRenderer
->>> import datetime
->>> import time
->>> import re
->>> try:
-... from decimal import Decimal
-... except ImportError:
-... from django.utils._decimal import Decimal
-
-###########
-# Widgets #
-###########
-
-Each Widget class corresponds to an HTML form widget. A Widget knows how to
-render itself, given a field name and some data. Widgets don't perform
-validation.
-
-# TextInput Widget ############################################################
-
->>> w = TextInput()
->>> w.render('email', '')
-u' '
->>> w.render('email', None)
-u' '
->>> w.render('email', 'test@example.com')
-u' '
->>> w.render('email', 'some "quoted" & ampersanded value')
-u' '
->>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
-u' '
-
-# Note that doctest in Python 2.4 (and maybe 2.5?) doesn't support non-ascii
-# characters in output, so we're displaying the repr() here.
->>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
-u' '
-
-You can also pass 'attrs' to the constructor:
->>> w = TextInput(attrs={'class': 'fun'})
->>> w.render('email', '')
-u' '
->>> w.render('email', 'foo@example.com')
-u' '
-
-'attrs' passed to render() get precedence over those passed to the constructor:
->>> w = TextInput(attrs={'class': 'pretty'})
->>> w.render('email', '', attrs={'class': 'special'})
-u' '
-
-# PasswordInput Widget ############################################################
-
->>> w = PasswordInput()
->>> w.render('email', '')
-u' '
->>> w.render('email', None)
-u' '
->>> w.render('email', 'test@example.com')
-u' '
->>> w.render('email', 'some "quoted" & ampersanded value')
-u' '
->>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
-u' '
-
-You can also pass 'attrs' to the constructor:
->>> w = PasswordInput(attrs={'class': 'fun'})
->>> w.render('email', '')
-u' '
->>> w.render('email', 'foo@example.com')
-u' '
-
-'attrs' passed to render() get precedence over those passed to the constructor:
->>> w = PasswordInput(attrs={'class': 'pretty'})
->>> w.render('email', '', attrs={'class': 'special'})
-u' '
-
->>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
-u' '
-
-The render_value argument lets you specify whether the widget should render
-its value. You may want to do this for security reasons.
->>> w = PasswordInput(render_value=True)
->>> w.render('email', 'secret')
-u' '
->>> w = PasswordInput(render_value=False)
->>> w.render('email', '')
-u' '
->>> w.render('email', None)
-u' '
->>> w.render('email', 'secret')
-u' '
->>> w = PasswordInput(attrs={'class': 'fun'}, render_value=False)
->>> w.render('email', 'secret')
-u' '
-
-# HiddenInput Widget ############################################################
-
->>> w = HiddenInput()
->>> w.render('email', '')
-u' '
->>> w.render('email', None)
-u' '
->>> w.render('email', 'test@example.com')
-u' '
->>> w.render('email', 'some "quoted" & ampersanded value')
-u' '
->>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
-u' '
-
-You can also pass 'attrs' to the constructor:
->>> w = HiddenInput(attrs={'class': 'fun'})
->>> w.render('email', '')
-u' '
->>> w.render('email', 'foo@example.com')
-u' '
-
-'attrs' passed to render() get precedence over those passed to the constructor:
->>> w = HiddenInput(attrs={'class': 'pretty'})
->>> w.render('email', '', attrs={'class': 'special'})
-u' '
-
->>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
-u' '
-
-'attrs' passed to render() get precedence over those passed to the constructor:
->>> w = HiddenInput(attrs={'class': 'pretty'})
->>> w.render('email', '', attrs={'class': 'special'})
-u' '
-
-# MultipleHiddenInput Widget ##################################################
-
->>> w = MultipleHiddenInput()
->>> w.render('email', [])
-u''
->>> w.render('email', None)
-u''
->>> w.render('email', ['test@example.com'])
-u' '
->>> w.render('email', ['some "quoted" & ampersanded value'])
-u' '
->>> w.render('email', ['test@example.com', 'foo@example.com'])
-u' \n '
->>> w.render('email', ['test@example.com'], attrs={'class': 'fun'})
-u' '
->>> w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'})
-u' \n '
-
-You can also pass 'attrs' to the constructor:
->>> w = MultipleHiddenInput(attrs={'class': 'fun'})
->>> w.render('email', [])
-u''
->>> w.render('email', ['foo@example.com'])
-u' '
->>> w.render('email', ['foo@example.com', 'test@example.com'])
-u' \n '
-
-'attrs' passed to render() get precedence over those passed to the constructor:
->>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
->>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
-u' '
-
->>> w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'})
-u' '
-
-'attrs' passed to render() get precedence over those passed to the constructor:
->>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
->>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
-u' '
-
-# FileInput Widget ############################################################
-
-FileInput widgets don't ever show the value, because the old value is of no use
-if you are updating the form or if the provided file generated an error.
->>> w = FileInput()
->>> w.render('email', '')
-u' '
->>> w.render('email', None)
-u' '
->>> w.render('email', 'test@example.com')
-u' '
->>> w.render('email', 'some "quoted" & ampersanded value')
-u' '
->>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
-u' '
-
-You can also pass 'attrs' to the constructor:
->>> w = FileInput(attrs={'class': 'fun'})
->>> w.render('email', '')
-u' '
->>> w.render('email', 'foo@example.com')
-u' '
-
->>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
-u' '
-
-# Textarea Widget #############################################################
-
->>> w = Textarea()
->>> w.render('msg', '')
-u''
->>> w.render('msg', None)
-u''
->>> w.render('msg', 'value')
-u''
->>> w.render('msg', 'some "quoted" & ampersanded value')
-u''
->>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20})
-u''
-
-You can also pass 'attrs' to the constructor:
->>> w = Textarea(attrs={'class': 'pretty'})
->>> w.render('msg', '')
-u''
->>> w.render('msg', 'example')
-u''
-
-'attrs' passed to render() get precedence over those passed to the constructor:
->>> w = Textarea(attrs={'class': 'pretty'})
->>> w.render('msg', '', attrs={'class': 'special'})
-u''
-
->>> w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
-u''
-
-# CheckboxInput Widget ########################################################
-
->>> w = CheckboxInput()
->>> w.render('is_cool', '')
-u' '
->>> w.render('is_cool', None)
-u' '
->>> w.render('is_cool', False)
-u' '
->>> w.render('is_cool', True)
-u' '
-
-Using any value that's not in ('', None, False, True) will check the checkbox
-and set the 'value' attribute.
->>> w.render('is_cool', 'foo')
-u' '
-
->>> w.render('is_cool', False, attrs={'class': 'pretty'})
-u' '
-
-You can also pass 'attrs' to the constructor:
->>> w = CheckboxInput(attrs={'class': 'pretty'})
->>> w.render('is_cool', '')
-u' '
-
-'attrs' passed to render() get precedence over those passed to the constructor:
->>> w = CheckboxInput(attrs={'class': 'pretty'})
->>> w.render('is_cool', '', attrs={'class': 'special'})
-u' '
-
-You can pass 'check_test' to the constructor. This is a callable that takes the
-value and returns True if the box should be checked.
->>> w = CheckboxInput(check_test=lambda value: value.startswith('hello'))
->>> w.render('greeting', '')
-u' '
->>> w.render('greeting', 'hello')
-u' '
->>> w.render('greeting', 'hello there')
-u' '
->>> w.render('greeting', 'hello & goodbye')
-u' '
-
-A subtlety: If the 'check_test' argument cannot handle a value and raises any
-exception during its __call__, then the exception will be swallowed and the box
-will not be checked. In this example, the 'check_test' assumes the value has a
-startswith() method, which fails for the values True, False and None.
->>> w.render('greeting', True)
-u' '
->>> w.render('greeting', False)
-u' '
->>> w.render('greeting', None)
-u' '
-
-# Select Widget ###############################################################
-
->>> w = Select()
->>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
-
-If the value is None, none of the options are selected:
->>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
-
-If the value corresponds to a label (but not to an option value), none of the options are selected:
->>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
-
-The value is compared to its str():
->>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
-
-1
-2
-3
-
->>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
-
-1
-2
-3
-
->>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
-
-1
-2
-3
-
-
-The 'choices' argument can be any iterable:
->>> from itertools import chain
->>> def get_choices():
-... for i in range(5):
-... yield (i, i)
->>> print w.render('num', 2, choices=get_choices())
-
-0
-1
-2
-3
-4
-
->>> things = ({'id': 1, 'name': 'And Boom'}, {'id': 2, 'name': 'One More Thing!'})
->>> class SomeForm(Form):
-... somechoice = ChoiceField(choices=chain((('', '-'*9),), [(thing['id'], thing['name']) for thing in things]))
->>> f = SomeForm()
->>> f.as_table()
-u'Somechoice: \n--------- \nAnd Boom \nOne More Thing! \n '
->>> f.as_table()
-u'Somechoice: \n--------- \nAnd Boom \nOne More Thing! \n '
->>> f = SomeForm({'somechoice': 2})
->>> f.as_table()
-u'Somechoice: \n--------- \nAnd Boom \nOne More Thing! \n '
-
-You can also pass 'choices' to the constructor:
->>> w = Select(choices=[(1, 1), (2, 2), (3, 3)])
->>> print w.render('num', 2)
-
-1
-2
-3
-
-
-If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
->>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
-
-1
-2
-3
-4
-5
-
-
->>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
-u'\n1 \n2 \n3 \n\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111 \nabc\u0107\u017e\u0161\u0111 \n '
-
-If choices is passed to the constructor and is a generator, it can be iterated
-over multiple times without getting consumed:
->>> w = Select(choices=get_choices())
->>> print w.render('num', 2)
-
-0
-1
-2
-3
-4
-
->>> print w.render('num', 3)
-
-0
-1
-2
-3
-4
-
-
-# NullBooleanSelect Widget ####################################################
-
->>> w = NullBooleanSelect()
->>> print w.render('is_cool', True)
-
-Unknown
-Yes
-No
-
->>> print w.render('is_cool', False)
-
-Unknown
-Yes
-No
-
->>> print w.render('is_cool', None)
-
-Unknown
-Yes
-No
-
->>> print w.render('is_cool', '2')
-
-Unknown
-Yes
-No
-
->>> print w.render('is_cool', '3')
-
-Unknown
-Yes
-No
-
-
-# SelectMultiple Widget #######################################################
-
->>> w = SelectMultiple()
->>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
->>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
->>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
-
-If the value is None, none of the options are selected:
->>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
-
-If the value corresponds to a label (but not to an option value), none of the options are selected:
->>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
-
-If multiple values are given, but some of them are not valid, the valid ones are selected:
->>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-John
-Paul
-George
-Ringo
-
-
-The value is compared to its str():
->>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
-
-1
-2
-3
-
->>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
-
-1
-2
-3
-
->>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
-
-1
-2
-3
-
-
-The 'choices' argument can be any iterable:
->>> def get_choices():
-... for i in range(5):
-... yield (i, i)
->>> print w.render('nums', [2], choices=get_choices())
-
-0
-1
-2
-3
-4
-
-
-You can also pass 'choices' to the constructor:
->>> w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
->>> print w.render('nums', [2])
-
-1
-2
-3
-
-
-If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
->>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
-
-1
-2
-3
-4
-5
-
-
->>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
-u'\n1 \n2 \n3 \n\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111 \nabc\u0107\u017e\u0161\u0111 \n '
-
-# RadioSelect Widget ##########################################################
-
->>> w = RadioSelect()
->>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-
-If the value is None, none of the options are checked:
->>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-
-If the value corresponds to a label (but not to an option value), none of the options are checked:
->>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-
-The value is compared to its str():
->>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
-
->>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
-
->>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
-
-
-The 'choices' argument can be any iterable:
->>> def get_choices():
-... for i in range(5):
-... yield (i, i)
->>> print w.render('num', 2, choices=get_choices())
-
-
-You can also pass 'choices' to the constructor:
->>> w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)])
->>> print w.render('num', 2)
-
-
-If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
->>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
-
-
-RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
-You can manipulate that object directly to customize the way the RadioSelect
-is rendered.
->>> w = RadioSelect()
->>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
->>> for inp in r:
-... print inp
- John
- Paul
- George
- Ringo
->>> for inp in r:
-... print '%s ' % inp
- John
- Paul
- George
- Ringo
->>> for inp in r:
-... print '%s %s
' % (inp.tag(), inp.choice_label)
- John
- Paul
- George
- Ringo
->>> for inp in r:
-... print '%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())
-beatle J J John True
-beatle J P Paul False
-beatle J G George False
-beatle J R Ringo False
-
-You can create your own custom renderers for RadioSelect to use.
->>> class MyRenderer(RadioFieldRenderer):
-... def render(self):
-... return u' \n'.join([unicode(choice) for choice in self])
->>> w = RadioSelect(renderer=MyRenderer)
->>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
- John
- Paul
- George
- Ringo
-
-A RadioFieldRenderer object also allows index access to individual RadioInput
-objects.
->>> w = RadioSelect()
->>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
->>> print r[1]
- Paul
->>> print r[0]
- John
->>> r[0].is_checked()
-True
->>> r[1].is_checked()
-False
->>> r[1].name, r[1].value, r[1].choice_value, r[1].choice_label
-('beatle', u'J', u'P', u'Paul')
->>> r[10]
-Traceback (most recent call last):
-...
-IndexError: list index out of range
-
-# Unicode choices are correctly rendered as HTML
->>> w = RadioSelect()
->>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
-u''
-
-# Attributes provided at instantiation are passed to the constituent inputs
->>> w = RadioSelect(attrs={'id':'foo'})
->>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-
-# Attributes provided at render-time are passed to the constituent inputs
->>> w = RadioSelect()
->>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'})
-
-
-# CheckboxSelectMultiple Widget ###############################################
-
->>> w = CheckboxSelectMultiple()
->>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
->>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
->>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-
-If the value is None, none of the options are selected:
->>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-
-If the value corresponds to a label (but not to an option value), none of the options are selected:
->>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-
-If multiple values are given, but some of them are not valid, the valid ones are selected:
->>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
-
-
-The value is compared to its str():
->>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
-
->>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
-
->>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
-
-
-The 'choices' argument can be any iterable:
->>> def get_choices():
-... for i in range(5):
-... yield (i, i)
->>> print w.render('nums', [2], choices=get_choices())
-
-
-You can also pass 'choices' to the constructor:
->>> w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
->>> print w.render('nums', [2])
-
-
-If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
->>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
-
-
->>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
-u''
-
-# MultiWidget #################################################################
-
->>> class MyMultiWidget(MultiWidget):
-... def decompress(self, value):
-... if value:
-... return value.split('__')
-... return ['', '']
-... def format_output(self, rendered_widgets):
-... return u' '.join(rendered_widgets)
->>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})))
->>> w.render('name', ['john', 'lennon'])
-u' '
->>> w.render('name', 'john__lennon')
-u' '
->>> w.render('name', 'john__lennon', attrs={'id':'foo'})
-u' '
->>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'})
->>> w.render('name', ['john', 'lennon'])
-u' '
-
-# SplitDateTimeWidget #########################################################
-
->>> w = SplitDateTimeWidget()
->>> w.render('date', '')
-u' '
->>> w.render('date', None)
-u' '
->>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
-u' '
->>> w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)])
-u' '
-
-You can also pass 'attrs' to the constructor. In this case, the attrs will be
-included on both widgets.
->>> w = SplitDateTimeWidget(attrs={'class': 'pretty'})
->>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
-u' '
-
-##########
-# Fields #
-##########
-
-Each Field class does some sort of validation. Each Field has a clean() method,
-which either raises django.newforms.ValidationError or returns the "clean"
-data -- usually a Unicode object, but, in some rare cases, a list.
-
-Each Field's __init__() takes at least these parameters:
- required -- Boolean that specifies whether the field is required.
- True by default.
- 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.
-
-Other than that, the Field subclasses have class-specific options for
-__init__(). For example, CharField has a max_length option.
-
-# CharField ###################################################################
-
->>> f = CharField()
->>> f.clean(1)
-u'1'
->>> f.clean('hello')
-u'hello'
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean([1, 2, 3])
-u'[1, 2, 3]'
-
->>> f = CharField(required=False)
->>> f.clean(1)
-u'1'
->>> f.clean('hello')
-u'hello'
->>> f.clean(None)
-u''
->>> f.clean('')
-u''
->>> f.clean([1, 2, 3])
-u'[1, 2, 3]'
-
-CharField accepts an optional max_length parameter:
->>> f = CharField(max_length=10, required=False)
->>> f.clean('12345')
-u'12345'
->>> f.clean('1234567890')
-u'1234567890'
->>> f.clean('1234567890a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 10 characters (it has 11).']
-
-CharField accepts an optional min_length parameter:
->>> f = CharField(min_length=10, required=False)
->>> f.clean('')
-u''
->>> f.clean('12345')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 10 characters (it has 5).']
->>> f.clean('1234567890')
-u'1234567890'
->>> f.clean('1234567890a')
-u'1234567890a'
-
->>> f = CharField(min_length=10, required=True)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('12345')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 10 characters (it has 5).']
->>> f.clean('1234567890')
-u'1234567890'
->>> f.clean('1234567890a')
-u'1234567890a'
-
-# IntegerField ################################################################
-
->>> f = IntegerField()
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('1')
-1
->>> isinstance(f.clean('1'), int)
-True
->>> f.clean('23')
-23
->>> f.clean('a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a whole number.']
->>> f.clean(42)
-42
->>> f.clean(3.14)
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a whole number.']
->>> f.clean('1 ')
-1
->>> f.clean(' 1')
-1
->>> f.clean(' 1 ')
-1
->>> f.clean('1a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a whole number.']
-
->>> f = IntegerField(required=False)
->>> f.clean('')
->>> repr(f.clean(''))
-'None'
->>> f.clean(None)
->>> repr(f.clean(None))
-'None'
->>> f.clean('1')
-1
->>> isinstance(f.clean('1'), int)
-True
->>> f.clean('23')
-23
->>> f.clean('a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a whole number.']
->>> f.clean('1 ')
-1
->>> f.clean(' 1')
-1
->>> f.clean(' 1 ')
-1
->>> f.clean('1a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a whole number.']
-
-IntegerField accepts an optional max_value parameter:
->>> f = IntegerField(max_value=10)
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(1)
-1
->>> f.clean(10)
-10
->>> f.clean(11)
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is less than or equal to 10.']
->>> f.clean('10')
-10
->>> f.clean('11')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is less than or equal to 10.']
-
-IntegerField accepts an optional min_value parameter:
->>> f = IntegerField(min_value=10)
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(1)
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is greater than or equal to 10.']
->>> f.clean(10)
-10
->>> f.clean(11)
-11
->>> f.clean('10')
-10
->>> f.clean('11')
-11
-
-min_value and max_value can be used together:
->>> f = IntegerField(min_value=10, max_value=20)
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(1)
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is greater than or equal to 10.']
->>> f.clean(10)
-10
->>> f.clean(11)
-11
->>> f.clean('10')
-10
->>> f.clean('11')
-11
->>> f.clean(20)
-20
->>> f.clean(21)
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is less than or equal to 20.']
-
-# FloatField ##################################################################
-
->>> f = FloatField()
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('1')
-1.0
->>> isinstance(f.clean('1'), float)
-True
->>> f.clean('23')
-23.0
->>> f.clean('3.14')
-3.1400000000000001
->>> f.clean(3.14)
-3.1400000000000001
->>> f.clean(42)
-42.0
->>> f.clean('a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a number.']
->>> f.clean('1.0 ')
-1.0
->>> f.clean(' 1.0')
-1.0
->>> f.clean(' 1.0 ')
-1.0
->>> f.clean('1.0a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a number.']
-
->>> f = FloatField(required=False)
->>> f.clean('')
-
->>> f.clean(None)
-
->>> f.clean('1')
-1.0
-
-FloatField accepts min_value and max_value just like IntegerField:
->>> f = FloatField(max_value=1.5, min_value=0.5)
-
->>> f.clean('1.6')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is less than or equal to 1.5.']
->>> f.clean('0.4')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
->>> f.clean('1.5')
-1.5
->>> f.clean('0.5')
-0.5
-
-# DecimalField ################################################################
-
->>> f = DecimalField(max_digits=4, decimal_places=2)
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('1')
-Decimal("1")
->>> isinstance(f.clean('1'), Decimal)
-True
->>> f.clean('23')
-Decimal("23")
->>> f.clean('3.14')
-Decimal("3.14")
->>> f.clean(3.14)
-Decimal("3.14")
->>> f.clean(Decimal('3.14'))
-Decimal("3.14")
->>> f.clean('a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a number.']
->>> f.clean('1.0 ')
-Decimal("1.0")
->>> f.clean(' 1.0')
-Decimal("1.0")
->>> f.clean(' 1.0 ')
-Decimal("1.0")
->>> f.clean('1.0a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a number.']
->>> f.clean('123.45')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure that there are no more than 4 digits in total.']
->>> f.clean('1.234')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure that there are no more than 2 decimal places.']
->>> f.clean('123.4')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure that there are no more than 2 digits before the decimal point.']
->>> f.clean('-12.34')
-Decimal("-12.34")
->>> f.clean('-123.45')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure that there are no more than 4 digits in total.']
->>> f.clean('-.12')
-Decimal("-0.12")
->>> f.clean('-00.12')
-Decimal("-0.12")
->>> f.clean('-000.12')
-Decimal("-0.12")
->>> f.clean('-000.123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure that there are no more than 2 decimal places.']
->>> f.clean('-000.1234')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure that there are no more than 4 digits in total.']
->>> f.clean('--0.12')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a number.']
-
->>> f = DecimalField(max_digits=4, decimal_places=2, required=False)
->>> f.clean('')
-
->>> f.clean(None)
-
->>> f.clean('1')
-Decimal("1")
-
-DecimalField accepts min_value and max_value just like IntegerField:
->>> f = DecimalField(max_digits=4, decimal_places=2, max_value=Decimal('1.5'), min_value=Decimal('0.5'))
-
->>> f.clean('1.6')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is less than or equal to 1.5.']
->>> f.clean('0.4')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value is greater than or equal to 0.5.']
->>> f.clean('1.5')
-Decimal("1.5")
->>> f.clean('0.5')
-Decimal("0.5")
->>> f.clean('.5')
-Decimal("0.5")
->>> f.clean('00.50')
-Decimal("0.50")
-
-# DateField ###################################################################
-
->>> import datetime
->>> f = DateField()
->>> f.clean(datetime.date(2006, 10, 25))
-datetime.date(2006, 10, 25)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
-datetime.date(2006, 10, 25)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
-datetime.date(2006, 10, 25)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
-datetime.date(2006, 10, 25)
->>> f.clean('2006-10-25')
-datetime.date(2006, 10, 25)
->>> f.clean('10/25/2006')
-datetime.date(2006, 10, 25)
->>> f.clean('10/25/06')
-datetime.date(2006, 10, 25)
->>> f.clean('Oct 25 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('October 25 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('October 25, 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('25 October 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('25 October, 2006')
-datetime.date(2006, 10, 25)
->>> f.clean('2006-4-31')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean('200a-10-25')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean('25/10/06')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = DateField(required=False)
->>> f.clean(None)
->>> repr(f.clean(None))
-'None'
->>> f.clean('')
->>> repr(f.clean(''))
-'None'
-
-DateField accepts an optional input_formats parameter:
->>> f = DateField(input_formats=['%Y %m %d'])
->>> f.clean(datetime.date(2006, 10, 25))
-datetime.date(2006, 10, 25)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
-datetime.date(2006, 10, 25)
->>> f.clean('2006 10 25')
-datetime.date(2006, 10, 25)
-
-The input_formats parameter overrides all default input formats,
-so the default formats won't work unless you specify them:
->>> f.clean('2006-10-25')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean('10/25/2006')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean('10/25/06')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
-
-# TimeField ###################################################################
-
->>> import datetime
->>> f = TimeField()
->>> f.clean(datetime.time(14, 25))
-datetime.time(14, 25)
->>> f.clean(datetime.time(14, 25, 59))
-datetime.time(14, 25, 59)
->>> f.clean('14:25')
-datetime.time(14, 25)
->>> f.clean('14:25:59')
-datetime.time(14, 25, 59)
->>> f.clean('hello')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid time.']
->>> f.clean('1:24 p.m.')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid time.']
-
-TimeField accepts an optional input_formats parameter:
->>> f = TimeField(input_formats=['%I:%M %p'])
->>> f.clean(datetime.time(14, 25))
-datetime.time(14, 25)
->>> f.clean(datetime.time(14, 25, 59))
-datetime.time(14, 25, 59)
->>> f.clean('4:25 AM')
-datetime.time(4, 25)
->>> f.clean('4:25 PM')
-datetime.time(16, 25)
-
-The input_formats parameter overrides all default input formats,
-so the default formats won't work unless you specify them:
->>> f.clean('14:30:45')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid time.']
-
-# DateTimeField ###############################################################
-
->>> import datetime
->>> f = DateTimeField()
->>> f.clean(datetime.date(2006, 10, 25))
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
-datetime.datetime(2006, 10, 25, 14, 30, 59)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
-datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
->>> f.clean('2006-10-25 14:30:45')
-datetime.datetime(2006, 10, 25, 14, 30, 45)
->>> f.clean('2006-10-25 14:30:00')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('2006-10-25 14:30')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('2006-10-25')
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean('10/25/2006 14:30:45')
-datetime.datetime(2006, 10, 25, 14, 30, 45)
->>> f.clean('10/25/2006 14:30:00')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('10/25/2006 14:30')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('10/25/2006')
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean('10/25/06 14:30:45')
-datetime.datetime(2006, 10, 25, 14, 30, 45)
->>> f.clean('10/25/06 14:30:00')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('10/25/06 14:30')
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean('10/25/06')
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean('hello')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date/time.']
->>> f.clean('2006-10-25 4:30 p.m.')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date/time.']
-
-DateField accepts an optional input_formats parameter:
->>> f = DateTimeField(input_formats=['%Y %m %d %I:%M %p'])
->>> f.clean(datetime.date(2006, 10, 25))
-datetime.datetime(2006, 10, 25, 0, 0)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30))
-datetime.datetime(2006, 10, 25, 14, 30)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59))
-datetime.datetime(2006, 10, 25, 14, 30, 59)
->>> f.clean(datetime.datetime(2006, 10, 25, 14, 30, 59, 200))
-datetime.datetime(2006, 10, 25, 14, 30, 59, 200)
->>> f.clean('2006 10 25 2:30 PM')
-datetime.datetime(2006, 10, 25, 14, 30)
-
-The input_formats parameter overrides all default input formats,
-so the default formats won't work unless you specify them:
->>> f.clean('2006-10-25 14:30:45')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date/time.']
-
->>> f = DateTimeField(required=False)
->>> f.clean(None)
->>> repr(f.clean(None))
-'None'
->>> f.clean('')
->>> repr(f.clean(''))
-'None'
-
-# RegexField ##################################################################
-
->>> f = RegexField('^\d[A-F]\d$')
->>> f.clean('2A2')
-u'2A2'
->>> f.clean('3F3')
-u'3F3'
->>> f.clean('3G3')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
->>> f.clean(' 2A2')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
->>> f.clean('2A2 ')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = RegexField('^\d[A-F]\d$', required=False)
->>> f.clean('2A2')
-u'2A2'
->>> f.clean('3F3')
-u'3F3'
->>> f.clean('3G3')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
->>> f.clean('')
-u''
-
-Alternatively, RegexField can take a compiled regular expression:
->>> f = RegexField(re.compile('^\d[A-F]\d$'))
->>> f.clean('2A2')
-u'2A2'
->>> f.clean('3F3')
-u'3F3'
->>> f.clean('3G3')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
->>> f.clean(' 2A2')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
->>> f.clean('2A2 ')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
-
-RegexField takes an optional error_message argument:
->>> f = RegexField('^\d\d\d\d$', error_message='Enter a four-digit number.')
->>> f.clean('1234')
-u'1234'
->>> f.clean('123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a four-digit number.']
->>> f.clean('abcd')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a four-digit number.']
-
-RegexField also access min_length and max_length parameters, for convenience.
->>> f = RegexField('^\d+$', min_length=5, max_length=10)
->>> f.clean('123')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 5 characters (it has 3).']
->>> f.clean('abc')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 5 characters (it has 3).']
->>> f.clean('12345')
-u'12345'
->>> f.clean('1234567890')
-u'1234567890'
->>> f.clean('12345678901')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 10 characters (it has 11).']
->>> f.clean('12345a')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid value.']
-
-# EmailField ##################################################################
-
->>> f = EmailField()
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('person@example.com')
-u'person@example.com'
->>> f.clean('foo')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid e-mail address.']
->>> f.clean('foo@')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid e-mail address.']
->>> f.clean('foo@bar')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid e-mail address.']
-
->>> f = EmailField(required=False)
->>> f.clean('')
-u''
->>> f.clean(None)
-u''
->>> f.clean('person@example.com')
-u'person@example.com'
->>> f.clean('foo')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid e-mail address.']
->>> f.clean('foo@')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid e-mail address.']
->>> f.clean('foo@bar')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid e-mail address.']
-
-EmailField also access min_length and max_length parameters, for convenience.
->>> f = EmailField(min_length=10, max_length=15)
->>> f.clean('a@foo.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 10 characters (it has 9).']
->>> f.clean('alf@foo.com')
-u'alf@foo.com'
->>> f.clean('alf123456788@foo.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 15 characters (it has 20).']
-
-# FileField ##################################################################
-
->>> f = FileField()
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f.clean({})
-Traceback (most recent call last):
-...
-ValidationError: [u'No file was submitted.']
-
->>> f.clean('some content that is not a file')
-Traceback (most recent call last):
-...
-ValidationError: [u'No file was submitted. Check the encoding type on the form.']
-
->>> f.clean({'filename': 'name', 'content':None})
-Traceback (most recent call last):
-...
-ValidationError: [u'The submitted file is empty.']
-
->>> f.clean({'filename': 'name', 'content':''})
-Traceback (most recent call last):
-...
-ValidationError: [u'The submitted file is empty.']
-
->>> type(f.clean({'filename': 'name', 'content':'Some File Content'}))
-
-
-# URLField ##################################################################
-
->>> f = URLField()
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('http://localhost')
-u'http://localhost'
->>> f.clean('http://example.com')
-u'http://example.com'
->>> f.clean('http://www.example.com')
-u'http://www.example.com'
->>> f.clean('http://www.example.com:8000/test')
-u'http://www.example.com:8000/test'
->>> f.clean('http://200.8.9.10')
-u'http://200.8.9.10'
->>> f.clean('http://200.8.9.10:8000/test')
-u'http://200.8.9.10:8000/test'
->>> f.clean('foo')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://example')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://example.')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
-
->>> f = URLField(required=False)
->>> f.clean('')
-u''
->>> f.clean(None)
-u''
->>> f.clean('http://example.com')
-u'http://example.com'
->>> f.clean('http://www.example.com')
-u'http://www.example.com'
->>> f.clean('foo')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://example')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://example.')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
-
-URLField takes an optional verify_exists parameter, which is False by default.
-This verifies that the URL is live on the Internet and doesn't return a 404 or 500:
->>> f = URLField(verify_exists=True)
->>> f.clean('http://www.google.com') # This will fail if there's no Internet connection
-u'http://www.google.com'
->>> f.clean('http://example')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid URL.']
->>> f.clean('http://www.jfoiwjfoi23jfoijoaijfoiwjofiwjefewl.com') # bad domain
-Traceback (most recent call last):
-...
-ValidationError: [u'This URL appears to be a broken link.']
->>> f.clean('http://google.com/we-love-microsoft.html') # good domain, bad page
-Traceback (most recent call last):
-...
-ValidationError: [u'This URL appears to be a broken link.']
->>> f = URLField(verify_exists=True, required=False)
->>> f.clean('')
-u''
->>> f.clean('http://www.google.com') # This will fail if there's no Internet connection
-u'http://www.google.com'
-
-URLField also access min_length and max_length parameters, for convenience.
->>> f = URLField(min_length=15, max_length=20)
->>> f.clean('http://f.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at least 15 characters (it has 12).']
->>> f.clean('http://example.com')
-u'http://example.com'
->>> f.clean('http://abcdefghijklmnopqrstuvwxyz.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 20 characters (it has 37).']
-
-URLField should prepend 'http://' if no scheme was given
->>> f = URLField(required=False)
->>> f.clean('example.com')
-u'http://example.com'
->>> f.clean('')
-u''
->>> f.clean('https://example.com')
-u'https://example.com'
-
-# BooleanField ################################################################
-
->>> f = BooleanField()
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(True)
-True
->>> f.clean(False)
-False
->>> f.clean(1)
-True
->>> f.clean(0)
-False
->>> f.clean('Django rocks')
-True
-
->>> f = BooleanField(required=False)
->>> f.clean('')
-False
->>> f.clean(None)
-False
->>> f.clean(True)
-True
->>> f.clean(False)
-False
->>> f.clean(1)
-True
->>> f.clean(0)
-False
->>> f.clean('Django rocks')
-True
-
-# ChoiceField #################################################################
-
->>> f = ChoiceField(choices=[('1', '1'), ('2', '2')])
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(1)
-u'1'
->>> f.clean('1')
-u'1'
->>> f.clean('3')
-Traceback (most recent call last):
-...
-ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
-
->>> f = ChoiceField(choices=[('1', '1'), ('2', '2')], required=False)
->>> f.clean('')
-u''
->>> f.clean(None)
-u''
->>> f.clean(1)
-u'1'
->>> f.clean('1')
-u'1'
->>> f.clean('3')
-Traceback (most recent call last):
-...
-ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
-
->>> f = ChoiceField(choices=[('J', 'John'), ('P', 'Paul')])
->>> f.clean('J')
-u'J'
->>> f.clean('John')
-Traceback (most recent call last):
-...
-ValidationError: [u'Select a valid choice. That choice is not one of the available choices.']
-
-# NullBooleanField ############################################################
-
->>> f = NullBooleanField()
->>> f.clean('')
->>> f.clean(True)
-True
->>> f.clean(False)
-False
->>> f.clean(None)
->>> f.clean('1')
->>> f.clean('2')
->>> f.clean('3')
->>> f.clean('hello')
-
-# MultipleChoiceField #########################################################
-
->>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')])
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean([1])
-[u'1']
->>> f.clean(['1'])
-[u'1']
->>> f.clean(['1', '2'])
-[u'1', u'2']
->>> f.clean([1, '2'])
-[u'1', u'2']
->>> f.clean((1, '2'))
-[u'1', u'2']
->>> f.clean('hello')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a list of values.']
->>> f.clean([])
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(())
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(['3'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
-
->>> f = MultipleChoiceField(choices=[('1', '1'), ('2', '2')], required=False)
->>> f.clean('')
-[]
->>> f.clean(None)
-[]
->>> f.clean([1])
-[u'1']
->>> f.clean(['1'])
-[u'1']
->>> f.clean(['1', '2'])
-[u'1', u'2']
->>> f.clean([1, '2'])
-[u'1', u'2']
->>> f.clean((1, '2'))
-[u'1', u'2']
->>> f.clean('hello')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a list of values.']
->>> f.clean([])
-[]
->>> f.clean(())
-[]
->>> f.clean(['3'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Select a valid choice. 3 is not one of the available choices.']
-
-# ComboField ##################################################################
-
-ComboField takes a list of fields that should be used to validate a value,
-in that order.
->>> f = ComboField(fields=[CharField(max_length=20), EmailField()])
->>> f.clean('test@example.com')
-u'test@example.com'
->>> f.clean('longemailaddress@example.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 20 characters (it has 28).']
->>> f.clean('not an e-mail')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid e-mail address.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> f = ComboField(fields=[CharField(max_length=20), EmailField()], required=False)
->>> f.clean('test@example.com')
-u'test@example.com'
->>> f.clean('longemailaddress@example.com')
-Traceback (most recent call last):
-...
-ValidationError: [u'Ensure this value has at most 20 characters (it has 28).']
->>> f.clean('not an e-mail')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid e-mail address.']
->>> f.clean('')
-u''
->>> f.clean(None)
-u''
-
-# SplitDateTimeField ##########################################################
-
->>> f = SplitDateTimeField()
->>> f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)])
-datetime.datetime(2006, 1, 10, 7, 30)
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('hello')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a list of values.']
->>> f.clean(['hello', 'there'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.', u'Enter a valid time.']
->>> f.clean(['2006-01-10', 'there'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid time.']
->>> f.clean(['hello', '07:30'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
-
->>> f = SplitDateTimeField(required=False)
->>> f.clean([datetime.date(2006, 1, 10), datetime.time(7, 30)])
-datetime.datetime(2006, 1, 10, 7, 30)
->>> f.clean(['2006-01-10', '07:30'])
-datetime.datetime(2006, 1, 10, 7, 30)
->>> f.clean(None)
->>> f.clean('')
->>> f.clean([''])
->>> f.clean(['', ''])
->>> f.clean('hello')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a list of values.']
->>> f.clean(['hello', 'there'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.', u'Enter a valid time.']
->>> f.clean(['2006-01-10', 'there'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid time.']
->>> f.clean(['hello', '07:30'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
->>> f.clean(['2006-01-10', ''])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid time.']
->>> f.clean(['2006-01-10'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid time.']
->>> f.clean(['', '07:30'])
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid date.']
-
-#########
-# Forms #
-#########
-
-A Form is a collection of Fields. It knows how to validate a set of data and it
-knows how to render itself in a couple of default ways (e.g., an HTML table).
-You can pass it data in __init__(), as a dictionary.
-
-# Form ########################################################################
-
->>> class Person(Form):
-... first_name = CharField()
-... last_name = CharField()
-... birthday = DateField()
-
-Pass a dictionary to a Form's __init__().
->>> p = Person({'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9'})
->>> p.is_bound
-True
->>> p.errors
-{}
->>> p.is_valid()
-True
->>> p.errors.as_ul()
-u''
->>> p.errors.as_text()
-u''
->>> p.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
->>> print p['first_name']
-
->>> print p['last_name']
-
->>> print p['birthday']
-
->>> print p['nonexistentfield']
-Traceback (most recent call last):
-...
-KeyError: "Key 'nonexistentfield' not found in Form"
-
->>> for boundfield in p:
-... print boundfield
-
-
-
->>> for boundfield in p:
-... print boundfield.label, boundfield.data
-First name John
-Last name Lennon
-Birthday 1940-10-9
->>> print p
-First name:
-Last name:
-Birthday:
-
-Empty dictionaries are valid, too.
->>> p = Person({})
->>> p.is_bound
-True
->>> p.errors
-{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
->>> p.is_valid()
-False
->>> p.cleaned_data
-Traceback (most recent call last):
-...
-AttributeError: 'Person' object has no attribute 'cleaned_data'
->>> print p
-First name:
-Last name:
-Birthday:
->>> print p.as_table()
-First name:
-Last name:
-Birthday:
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
->>> print p.as_p()
-
-First name:
-
-Last name:
-
-Birthday:
-
-If you don't pass any values to the Form's __init__(), or if you pass None,
-the Form will be considered unbound and won't do any validation. Form.errors
-will be an empty dictionary *but* Form.is_valid() will return False.
->>> p = Person()
->>> p.is_bound
-False
->>> p.errors
-{}
->>> p.is_valid()
-False
->>> p.cleaned_data
-Traceback (most recent call last):
-...
-AttributeError: 'Person' object has no attribute 'cleaned_data'
->>> print p
-First name:
-Last name:
-Birthday:
->>> print p.as_table()
-First name:
-Last name:
-Birthday:
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
->>> print p.as_p()
-First name:
-Last name:
-Birthday:
-
-Unicode values are handled properly.
->>> p = Person({'first_name': u'John', 'last_name': u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111', 'birthday': '1940-10-9'})
->>> p.as_table()
-u'First name: \nLast name: \nBirthday: '
->>> p.as_ul()
-u'First name: \nLast name: \nBirthday: '
->>> p.as_p()
-u'First name:
\nLast name:
\nBirthday:
'
-
->>> p = Person({'last_name': u'Lennon'})
->>> p.errors
-{'first_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
->>> p.is_valid()
-False
->>> p.errors.as_ul()
-u''
->>> print p.errors.as_text()
-* first_name
- * This field is required.
-* birthday
- * This field is required.
->>> p.cleaned_data
-Traceback (most recent call last):
-...
-AttributeError: 'Person' object has no attribute 'cleaned_data'
->>> p['first_name'].errors
-[u'This field is required.']
->>> p['first_name'].errors.as_ul()
-u''
->>> p['first_name'].errors.as_text()
-u'* This field is required.'
-
->>> p = Person()
->>> print p['first_name']
-
->>> print p['last_name']
-
->>> print p['birthday']
-
-
-cleaned_data will always *only* contain a key for fields defined in the
-Form, even if you pass extra data when you define the Form. In this
-example, we pass a bunch of extra fields to the form constructor,
-but cleaned_data contains only the form's fields.
->>> data = {'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9', 'extra1': 'hello', 'extra2': 'hello'}
->>> p = Person(data)
->>> p.is_valid()
-True
->>> p.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
-
-cleaned_data will include a key and value for *all* fields defined in the Form,
-even if the Form's data didn't include a value for fields that are not
-required. In this example, the data dictionary doesn't include a value for the
-"nick_name" field, but cleaned_data includes it. For CharFields, it's set to the
-empty string.
->>> class OptionalPersonForm(Form):
-... first_name = CharField()
-... last_name = CharField()
-... nick_name = CharField(required=False)
->>> data = {'first_name': u'John', 'last_name': u'Lennon'}
->>> f = OptionalPersonForm(data)
->>> f.is_valid()
-True
->>> f.cleaned_data
-{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}
-
-For DateFields, it's set to None.
->>> class OptionalPersonForm(Form):
-... first_name = CharField()
-... last_name = CharField()
-... birth_date = DateField(required=False)
->>> data = {'first_name': u'John', 'last_name': u'Lennon'}
->>> f = OptionalPersonForm(data)
->>> f.is_valid()
-True
->>> f.cleaned_data
-{'birth_date': None, 'first_name': u'John', 'last_name': u'Lennon'}
-
-"auto_id" tells the Form to add an "id" attribute to each form element.
-If it's a string that contains '%s', Django will use that as a format string
-into which the field's name will be inserted. It will also put a around
-the human-readable labels for a field.
->>> p = Person(auto_id='%s_id')
->>> print p.as_table()
-First name:
-Last name:
-Birthday:
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
->>> print p.as_p()
-First name:
-Last name:
-Birthday:
-
-If auto_id is any True value whose str() does not contain '%s', the "id"
-attribute will be the name of the field.
->>> p = Person(auto_id=True)
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
-
-If auto_id is any False value, an "id" attribute won't be output unless it
-was manually entered.
->>> p = Person(auto_id=False)
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
-
-In this example, auto_id is False, but the "id" attribute for the "first_name"
-field is given. Also note that field gets a , while the others don't.
->>> class PersonNew(Form):
-... first_name = CharField(widget=TextInput(attrs={'id': 'first_name_id'}))
-... last_name = CharField()
-... birthday = DateField()
->>> p = PersonNew(auto_id=False)
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
-
-If the "id" attribute is specified in the Form and auto_id is True, the "id"
-attribute in the Form gets precedence.
->>> p = PersonNew(auto_id=True)
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
-
->>> class SignupForm(Form):
-... email = EmailField()
-... get_spam = BooleanField()
->>> f = SignupForm(auto_id=False)
->>> print f['email']
-
->>> print f['get_spam']
-
-
->>> f = SignupForm({'email': 'test@example.com', 'get_spam': True}, auto_id=False)
->>> print f['email']
-
->>> print f['get_spam']
-
-
-Any Field can have a Widget class passed to its constructor:
->>> class ContactForm(Form):
-... subject = CharField()
-... message = CharField(widget=Textarea)
->>> f = ContactForm(auto_id=False)
->>> print f['subject']
-
->>> print f['message']
-
-
-as_textarea(), as_text() and as_hidden() are shortcuts for changing the output
-widget type:
->>> f['subject'].as_textarea()
-u''
->>> f['message'].as_text()
-u' '
->>> f['message'].as_hidden()
-u' '
-
-The 'widget' parameter to a Field can also be an instance:
->>> class ContactForm(Form):
-... subject = CharField()
-... message = CharField(widget=Textarea(attrs={'rows': 80, 'cols': 20}))
->>> f = ContactForm(auto_id=False)
->>> print f['message']
-
-
-Instance-level attrs are *not* carried over to as_textarea(), as_text() and
-as_hidden():
->>> f['message'].as_text()
-u' '
->>> f = ContactForm({'subject': 'Hello', 'message': 'I love you.'}, auto_id=False)
->>> f['subject'].as_textarea()
-u''
->>> f['message'].as_text()
-u' '
->>> f['message'].as_hidden()
-u' '
-
-For a form with a , use ChoiceField:
->>> class FrameworkForm(Form):
-... name = CharField()
-... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')])
->>> f = FrameworkForm(auto_id=False)
->>> print f['language']
-
-Python
-Java
-
->>> f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
->>> print f['language']
-
-Python
-Java
-
-
-A subtlety: If one of the choices' value is the empty string and the form is
-unbound, then the for the empty-string choice will get selected="selected".
->>> class FrameworkForm(Form):
-... name = CharField()
-... language = ChoiceField(choices=[('', '------'), ('P', 'Python'), ('J', 'Java')])
->>> f = FrameworkForm(auto_id=False)
->>> print f['language']
-
-------
-Python
-Java
-
-
-You can specify widget attributes in the Widget constructor.
->>> class FrameworkForm(Form):
-... name = CharField()
-... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=Select(attrs={'class': 'foo'}))
->>> f = FrameworkForm(auto_id=False)
->>> print f['language']
-
-Python
-Java
-
->>> f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
->>> print f['language']
-
-Python
-Java
-
-
-When passing a custom widget instance to ChoiceField, note that setting
-'choices' on the widget is meaningless. The widget will use the choices
-defined on the Field, not the ones defined on the Widget.
->>> class FrameworkForm(Form):
-... name = CharField()
-... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=Select(choices=[('R', 'Ruby'), ('P', 'Perl')], attrs={'class': 'foo'}))
->>> f = FrameworkForm(auto_id=False)
->>> print f['language']
-
-Python
-Java
-
->>> f = FrameworkForm({'name': 'Django', 'language': 'P'}, auto_id=False)
->>> print f['language']
-
-Python
-Java
-
-
-You can set a ChoiceField's choices after the fact.
->>> class FrameworkForm(Form):
-... name = CharField()
-... language = ChoiceField()
->>> f = FrameworkForm(auto_id=False)
->>> print f['language']
-
-
->>> f.fields['language'].choices = [('P', 'Python'), ('J', 'Java')]
->>> print f['language']
-
-Python
-Java
-
-
-Add widget=RadioSelect to use that widget with a ChoiceField.
->>> class FrameworkForm(Form):
-... name = CharField()
-... language = ChoiceField(choices=[('P', 'Python'), ('J', 'Java')], widget=RadioSelect)
->>> f = FrameworkForm(auto_id=False)
->>> print f['language']
-
->>> print f
-Name:
-Language:
->>> print f.as_ul()
-Name:
-Language:
-
-Regarding auto_id and , RadioSelect is a special case. Each radio button
-gets a distinct ID, formed by appending an underscore plus the button's
-zero-based index.
->>> f = FrameworkForm(auto_id='id_%s')
->>> print f['language']
-
-
-When RadioSelect is used with auto_id, and the whole form is printed using
-either as_table() or as_ul(), the label for the RadioSelect will point to the
-ID of the *first* radio button.
->>> print f
-Name:
-Language:
->>> print f.as_ul()
-Name:
-Language:
->>> print f.as_p()
-Name:
-Language:
-
-MultipleChoiceField is a special case, as its data is required to be a list:
->>> class SongForm(Form):
-... name = CharField()
-... composers = MultipleChoiceField()
->>> f = SongForm(auto_id=False)
->>> print f['composers']
-
-
->>> class SongForm(Form):
-... name = CharField()
-... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')])
->>> f = SongForm(auto_id=False)
->>> print f['composers']
-
-John Lennon
-Paul McCartney
-
->>> f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False)
->>> print f['name']
-
->>> print f['composers']
-
-John Lennon
-Paul McCartney
-
-
-MultipleChoiceField rendered as_hidden() is a special case. Because it can
-have multiple values, its as_hidden() renders multiple
-tags.
->>> f = SongForm({'name': 'Yesterday', 'composers': ['P']}, auto_id=False)
->>> print f['composers'].as_hidden()
-
->>> f = SongForm({'name': 'From Me To You', 'composers': ['P', 'J']}, auto_id=False)
->>> print f['composers'].as_hidden()
-
-
-
-MultipleChoiceField can also be used with the CheckboxSelectMultiple widget.
->>> class SongForm(Form):
-... name = CharField()
-... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=CheckboxSelectMultiple)
->>> f = SongForm(auto_id=False)
->>> print f['composers']
-
->>> f = SongForm({'composers': ['J']}, auto_id=False)
->>> print f['composers']
-
->>> f = SongForm({'composers': ['J', 'P']}, auto_id=False)
->>> print f['composers']
-
-
-Regarding auto_id, CheckboxSelectMultiple is a special case. Each checkbox
-gets a distinct ID, formed by appending an underscore plus the checkbox's
-zero-based index.
->>> f = SongForm(auto_id='%s_id')
->>> print f['composers']
-
-
-Data for a MultipleChoiceField should be a list. QueryDict and MultiValueDict
-conveniently work with this.
->>> data = {'name': 'Yesterday', 'composers': ['J', 'P']}
->>> f = SongForm(data)
->>> f.errors
-{}
->>> from django.http import QueryDict
->>> data = QueryDict('name=Yesterday&composers=J&composers=P')
->>> f = SongForm(data)
->>> f.errors
-{}
->>> from django.utils.datastructures import MultiValueDict
->>> data = MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P']))
->>> f = SongForm(data)
->>> f.errors
-{}
-
-The MultipleHiddenInput widget renders multiple values as hidden fields.
->>> class SongFormHidden(Form):
-... name = CharField()
-... composers = MultipleChoiceField(choices=[('J', 'John Lennon'), ('P', 'Paul McCartney')], widget=MultipleHiddenInput)
->>> f = SongFormHidden(MultiValueDict(dict(name=['Yesterday'], composers=['J', 'P'])), auto_id=False)
->>> print f.as_ul()
-Name:
-
-
-When using CheckboxSelectMultiple, the framework expects a list of input and
-returns a list of input.
->>> f = SongForm({'name': 'Yesterday'}, auto_id=False)
->>> f.errors
-{'composers': [u'This field is required.']}
->>> f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False)
->>> f.errors
-{}
->>> f.cleaned_data
-{'composers': [u'J'], 'name': u'Yesterday'}
->>> f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False)
->>> f.errors
-{}
->>> f.cleaned_data
-{'composers': [u'J', u'P'], 'name': u'Yesterday'}
-
-Validation errors are HTML-escaped when output as HTML.
->>> class EscapingForm(Form):
-... special_name = CharField()
-... def clean_special_name(self):
-... raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name'])
-
->>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False)
->>> print f
-Special name: Something's wrong with 'Nothing to escape'
->>> f = EscapingForm({'special_name': "Should escape < & > and "}, auto_id=False)
->>> print f
-Special name: Something's wrong with 'Should escape < & > and <script>alert('xss')</script>'
-
-# Validating multiple fields in relation to another ###########################
-
-There are a couple of ways to do multiple-field validation. If you want the
-validation message to be associated with a particular field, implement the
-clean_XXX() method on the Form, where XXX is the field name. As in
-Field.clean(), the clean_XXX() method should return the cleaned value. In the
-clean_XXX() method, you have access to self.cleaned_data, which is a dictionary
-of all the data that has been cleaned *so far*, in order by the fields,
-including the current field (e.g., the field XXX if you're in clean_XXX()).
->>> class UserRegistration(Form):
-... username = CharField(max_length=10)
-... password1 = CharField(widget=PasswordInput)
-... password2 = CharField(widget=PasswordInput)
-... def clean_password2(self):
-... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
-... raise ValidationError(u'Please make sure your passwords match.')
-... return self.cleaned_data['password2']
->>> f = UserRegistration(auto_id=False)
->>> f.errors
-{}
->>> f = UserRegistration({}, auto_id=False)
->>> f.errors
-{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']}
->>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
->>> f.errors
-{'password2': [u'Please make sure your passwords match.']}
->>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
->>> f.errors
-{}
->>> f.cleaned_data
-{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
-
-Another way of doing multiple-field validation is by implementing the
-Form's clean() method. If you do this, any ValidationError raised by that
-method will not be associated with a particular field; it will have a
-special-case association with the field named '__all__'.
-Note that in Form.clean(), you have access to self.cleaned_data, a dictionary of
-all the fields/values that have *not* raised a ValidationError. Also note
-Form.clean() is required to return a dictionary of all clean data.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10)
-... password1 = CharField(widget=PasswordInput)
-... password2 = CharField(widget=PasswordInput)
-... def clean(self):
-... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
-... raise ValidationError(u'Please make sure your passwords match.')
-... return self.cleaned_data
->>> f = UserRegistration(auto_id=False)
->>> f.errors
-{}
->>> f = UserRegistration({}, auto_id=False)
->>> print f.as_table()
-Username:
-Password1:
-Password2:
->>> f.errors
-{'username': [u'This field is required.'], 'password1': [u'This field is required.'], 'password2': [u'This field is required.']}
->>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)
->>> f.errors
-{'__all__': [u'Please make sure your passwords match.']}
->>> print f.as_table()
-Please make sure your passwords match.
-Username:
-Password1:
-Password2:
->>> print f.as_ul()
-Please make sure your passwords match.
-Username:
-Password1:
-Password2:
->>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
->>> f.errors
-{}
->>> f.cleaned_data
-{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
-
-# Dynamic construction ########################################################
-
-It's possible to construct a Form dynamically by adding to the self.fields
-dictionary in __init__(). Don't forget to call Form.__init__() within the
-subclass' __init__().
->>> class Person(Form):
-... first_name = CharField()
-... last_name = CharField()
-... def __init__(self, *args, **kwargs):
-... super(Person, self).__init__(*args, **kwargs)
-... self.fields['birthday'] = DateField()
->>> p = Person(auto_id=False)
->>> print p
-First name:
-Last name:
-Birthday:
-
-Instances of a dynamic Form do not persist fields from one Form instance to
-the next.
->>> class MyForm(Form):
-... def __init__(self, data=None, auto_id=False, field_list=[]):
-... Form.__init__(self, data, auto_id=auto_id)
-... for field in field_list:
-... self.fields[field[0]] = field[1]
->>> field_list = [('field1', CharField()), ('field2', CharField())]
->>> my_form = MyForm(field_list=field_list)
->>> print my_form
-Field1:
-Field2:
->>> field_list = [('field3', CharField()), ('field4', CharField())]
->>> my_form = MyForm(field_list=field_list)
->>> print my_form
-Field3:
-Field4:
-
->>> class MyForm(Form):
-... default_field_1 = CharField()
-... default_field_2 = CharField()
-... def __init__(self, data=None, auto_id=False, field_list=[]):
-... Form.__init__(self, data, auto_id=auto_id)
-... for field in field_list:
-... self.fields[field[0]] = field[1]
->>> field_list = [('field1', CharField()), ('field2', CharField())]
->>> my_form = MyForm(field_list=field_list)
->>> print my_form
-Default field 1:
-Default field 2:
-Field1:
-Field2:
->>> field_list = [('field3', CharField()), ('field4', CharField())]
->>> my_form = MyForm(field_list=field_list)
->>> print my_form
-Default field 1:
-Default field 2:
-Field3:
-Field4:
-
-Similarly, changes to field attributes do not persist from one Form instance
-to the next.
->>> class Person(Form):
-... first_name = CharField(required=False)
-... last_name = CharField(required=False)
-... def __init__(self, names_required=False, *args, **kwargs):
-... super(Person, self).__init__(*args, **kwargs)
-... if names_required:
-... self.fields['first_name'].required = True
-... self.fields['first_name'].widget.attrs['class'] = 'required'
-... self.fields['last_name'].required = True
-... self.fields['last_name'].widget.attrs['class'] = 'required'
->>> f = Person(names_required=False)
->>> f['first_name'].field.required, f['last_name'].field.required
-(False, False)
->>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
-({}, {})
->>> f = Person(names_required=True)
->>> f['first_name'].field.required, f['last_name'].field.required
-(True, True)
->>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
-({'class': 'required'}, {'class': 'required'})
->>> f = Person(names_required=False)
->>> f['first_name'].field.required, f['last_name'].field.required
-(False, False)
->>> f['first_name'].field.widget.attrs, f['last_name'].field.widget.attrs
-({}, {})
->>> class Person(Form):
-... first_name = CharField(max_length=30)
-... last_name = CharField(max_length=30)
-... def __init__(self, name_max_length=None, *args, **kwargs):
-... super(Person, self).__init__(*args, **kwargs)
-... if name_max_length:
-... self.fields['first_name'].max_length = name_max_length
-... self.fields['last_name'].max_length = name_max_length
->>> f = Person(name_max_length=None)
->>> f['first_name'].field.max_length, f['last_name'].field.max_length
-(30, 30)
->>> f = Person(name_max_length=20)
->>> f['first_name'].field.max_length, f['last_name'].field.max_length
-(20, 20)
->>> f = Person(name_max_length=None)
->>> f['first_name'].field.max_length, f['last_name'].field.max_length
-(30, 30)
-
-HiddenInput widgets are displayed differently in the as_table(), as_ul()
-and as_p() output of a Form -- their verbose names are not displayed, and a
-separate row is not displayed. They're displayed in the last row of the
-form, directly after that row's form element.
->>> class Person(Form):
-... first_name = CharField()
-... last_name = CharField()
-... hidden_text = CharField(widget=HiddenInput)
-... birthday = DateField()
->>> p = Person(auto_id=False)
->>> print p
-First name:
-Last name:
-Birthday:
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
->>> print p.as_p()
-First name:
-Last name:
-Birthday:
-
-With auto_id set, a HiddenInput still gets an ID, but it doesn't get a label.
->>> p = Person(auto_id='id_%s')
->>> print p
-First name:
-Last name:
-Birthday:
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
->>> print p.as_p()
-First name:
-Last name:
-Birthday:
-
-If a field with a HiddenInput has errors, the as_table() and as_ul() output
-will include the error message(s) with the text "(Hidden field [fieldname]) "
-prepended. This message is displayed at the top of the output, regardless of
-its field's order in the form.
->>> p = Person({'first_name': 'John', 'last_name': 'Lennon', 'birthday': '1940-10-9'}, auto_id=False)
->>> print p
-(Hidden field hidden_text) This field is required.
-First name:
-Last name:
-Birthday:
->>> print p.as_ul()
-(Hidden field hidden_text) This field is required.
-First name:
-Last name:
-Birthday:
->>> print p.as_p()
-(Hidden field hidden_text) This field is required.
-First name:
-Last name:
-Birthday:
-
-A corner case: It's possible for a form to have only HiddenInputs.
->>> class TestForm(Form):
-... foo = CharField(widget=HiddenInput)
-... bar = CharField(widget=HiddenInput)
->>> p = TestForm(auto_id=False)
->>> print p.as_table()
-
->>> print p.as_ul()
-
->>> print p.as_p()
-
-
-A Form's fields are displayed in the same order in which they were defined.
->>> class TestForm(Form):
-... field1 = CharField()
-... field2 = CharField()
-... field3 = CharField()
-... field4 = CharField()
-... field5 = CharField()
-... field6 = CharField()
-... field7 = CharField()
-... field8 = CharField()
-... field9 = CharField()
-... field10 = CharField()
-... field11 = CharField()
-... field12 = CharField()
-... field13 = CharField()
-... field14 = CharField()
->>> p = TestForm(auto_id=False)
->>> print p
-Field1:
-Field2:
-Field3:
-Field4:
-Field5:
-Field6:
-Field7:
-Field8:
-Field9:
-Field10:
-Field11:
-Field12:
-Field13:
-Field14:
-
-Some Field classes have an effect on the HTML attributes of their associated
-Widget. If you set max_length in a CharField and its associated widget is
-either a TextInput or PasswordInput, then the widget's rendered HTML will
-include the "maxlength" attribute.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10) # uses TextInput by default
-... password = CharField(max_length=10, widget=PasswordInput)
-... realname = CharField(max_length=10, widget=TextInput) # redundantly define widget, just to test
-... address = CharField() # no max_length defined here
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-Realname:
-Address:
-
-If you specify a custom "attrs" that includes the "maxlength" attribute,
-the Field's max_length attribute will override whatever "maxlength" you specify
-in "attrs".
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, widget=TextInput(attrs={'maxlength': 20}))
-... password = CharField(max_length=10, widget=PasswordInput)
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-# Specifying labels ###########################################################
-
-You can specify the label for a field by using the 'label' argument to a Field
-class. If you don't specify 'label', Django will use the field name with
-underscores converted to spaces, and the initial letter capitalized.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, label='Your username')
-... password1 = CharField(widget=PasswordInput)
-... password2 = CharField(widget=PasswordInput, label='Password (again)')
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-Your username:
-Password1:
-Password (again):
-
-Labels for as_* methods will only end in a colon if they don't end in other
-punctuation already.
->>> class Questions(Form):
-... q1 = CharField(label='The first question')
-... q2 = CharField(label='What is your name?')
-... q3 = CharField(label='The answer to life is:')
-... q4 = CharField(label='Answer this question!')
-... q5 = CharField(label='The last question. Period.')
->>> print Questions(auto_id=False).as_p()
-The first question:
-What is your name?
-The answer to life is:
-Answer this question!
-The last question. Period.
->>> print Questions().as_p()
-The first question:
-What is your name?
-The answer to life is:
-Answer this question!
-The last question. Period.
-
-A label can be a Unicode object or a bytestring with special characters.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, label='ŠĐĆŽćžšđ')
-... password = CharField(widget=PasswordInput, label=u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111')
->>> p = UserRegistration(auto_id=False)
->>> p.as_ul()
-u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111: \n\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111: '
-
-If a label is set to the empty string for a field, that field won't get a label.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, label='')
-... password = CharField(widget=PasswordInput)
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-
-Password:
->>> p = UserRegistration(auto_id='id_%s')
->>> print p.as_ul()
-
-Password:
-
-If label is None, Django will auto-create the label from the field name. This
-is default behavior.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, label=None)
-... password = CharField(widget=PasswordInput)
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration(auto_id='id_%s')
->>> print p.as_ul()
-Username:
-Password:
-
-
-# Label Suffix ################################################################
-
-You can specify the 'label_suffix' argument to a Form class to modify the
-punctuation symbol used at the end of a label. By default, the colon (:) is
-used, and is only appended to the label if the label doesn't already end with a
-punctuation symbol: ., !, ? or :. If you specify a different suffix, it will
-be appended regardless of the last character of the label.
-
->>> class FavoriteForm(Form):
-... color = CharField(label='Favorite color?')
-... animal = CharField(label='Favorite animal')
-...
->>> f = FavoriteForm(auto_id=False)
->>> print f.as_ul()
-Favorite color?
-Favorite animal:
->>> f = FavoriteForm(auto_id=False, label_suffix='?')
->>> print f.as_ul()
-Favorite color?
-Favorite animal?
->>> f = FavoriteForm(auto_id=False, label_suffix='')
->>> print f.as_ul()
-Favorite color?
-Favorite animal
->>> f = FavoriteForm(auto_id=False, label_suffix=u'\u2192')
->>> f.as_ul()
-u'Favorite color? \nFavorite animal\u2192 '
-
-
-
-# Initial data ################################################################
-
-You can specify initial data for a field by using the 'initial' argument to a
-Field class. This initial data is displayed when a Form is rendered with *no*
-data. It is not displayed when a Form is rendered with any data (including an
-empty dictionary). Also, the initial value is *not* used if data for a
-particular required field isn't provided.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, initial='django')
-... password = CharField(widget=PasswordInput)
-
-Here, we're not submitting any data, so the initial value will be displayed.
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-Here, we're submitting data, so the initial value will *not* be displayed.
->>> p = UserRegistration({}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration({'username': u''}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration({'username': u'foo'}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-An 'initial' value is *not* used as a fallback if data is not provided. In this
-example, we don't provide a value for 'username', and the form raises a
-validation error rather than using the initial value for 'username'.
->>> p = UserRegistration({'password': 'secret'})
->>> p.errors
-{'username': [u'This field is required.']}
->>> p.is_valid()
-False
-
-# Dynamic initial data ########################################################
-
-The previous technique dealt with "hard-coded" initial data, but it's also
-possible to specify initial data after you've already created the Form class
-(i.e., at runtime). Use the 'initial' parameter to the Form constructor. This
-should be a dictionary containing initial values for one or more fields in the
-form, keyed by field name.
-
->>> class UserRegistration(Form):
-... username = CharField(max_length=10)
-... password = CharField(widget=PasswordInput)
-
-Here, we're not submitting any data, so the initial value will be displayed.
->>> p = UserRegistration(initial={'username': 'django'}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration(initial={'username': 'stephane'}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-The 'initial' parameter is meaningless if you pass data.
->>> p = UserRegistration({}, initial={'username': 'django'}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration({'username': u''}, initial={'username': 'django'}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration({'username': u'foo'}, initial={'username': 'django'}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-A dynamic 'initial' value is *not* used as a fallback if data is not provided.
-In this example, we don't provide a value for 'username', and the form raises a
-validation error rather than using the initial value for 'username'.
->>> p = UserRegistration({'password': 'secret'}, initial={'username': 'django'})
->>> p.errors
-{'username': [u'This field is required.']}
->>> p.is_valid()
-False
-
-If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(),
-then the latter will get precedence.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, initial='django')
-... password = CharField(widget=PasswordInput)
->>> p = UserRegistration(initial={'username': 'babik'}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-# Callable initial data ########################################################
-
-The previous technique dealt with raw values as initial data, but it's also
-possible to specify callable data.
-
->>> class UserRegistration(Form):
-... username = CharField(max_length=10)
-... password = CharField(widget=PasswordInput)
-
-We need to define functions that get called later.
->>> def initial_django():
-... return 'django'
->>> def initial_stephane():
-... return 'stephane'
-
-Here, we're not submitting any data, so the initial value will be displayed.
->>> p = UserRegistration(initial={'username': initial_django}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-The 'initial' parameter is meaningless if you pass data.
->>> p = UserRegistration({}, initial={'username': initial_django}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration({'username': u''}, initial={'username': initial_django}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration({'username': u'foo'}, initial={'username': initial_django}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-A callable 'initial' value is *not* used as a fallback if data is not provided.
-In this example, we don't provide a value for 'username', and the form raises a
-validation error rather than using the initial value for 'username'.
->>> p = UserRegistration({'password': 'secret'}, initial={'username': initial_django})
->>> p.errors
-{'username': [u'This field is required.']}
->>> p.is_valid()
-False
-
-If a Form defines 'initial' *and* 'initial' is passed as a parameter to Form(),
-then the latter will get precedence.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, initial=initial_django)
-... password = CharField(widget=PasswordInput)
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
->>> p = UserRegistration(initial={'username': initial_stephane}, auto_id=False)
->>> print p.as_ul()
-Username:
-Password:
-
-# Help text ###################################################################
-
-You can specify descriptive text for a field by using the 'help_text' argument
-to a Field class. This help text is displayed when a Form is rendered.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, help_text='e.g., user@example.com')
-... password = CharField(widget=PasswordInput, help_text='Choose wisely.')
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-Username: e.g., user@example.com
-Password: Choose wisely.
->>> print p.as_p()
-Username: e.g., user@example.com
-Password: Choose wisely.
->>> print p.as_table()
-Username: e.g., user@example.com
-Password: Choose wisely.
-
-The help text is displayed whether or not data is provided for the form.
->>> p = UserRegistration({'username': u'foo'}, auto_id=False)
->>> print p.as_ul()
-Username: e.g., user@example.com
-Password: Choose wisely.
-
-help_text is not displayed for hidden fields. It can be used for documentation
-purposes, though.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, help_text='e.g., user@example.com')
-... password = CharField(widget=PasswordInput)
-... next = CharField(widget=HiddenInput, initial='/', help_text='Redirect destination')
->>> p = UserRegistration(auto_id=False)
->>> print p.as_ul()
-Username: e.g., user@example.com
-Password:
-
-Help text can include arbitrary Unicode characters.
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, help_text='ŠĐĆŽćžšđ')
->>> p = UserRegistration(auto_id=False)
->>> p.as_ul()
-u'Username: \u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111 '
-
-# Subclassing forms ###########################################################
-
-You can subclass a Form to add fields. The resulting form subclass will have
-all of the fields of the parent Form, plus whichever fields you define in the
-subclass.
->>> class Person(Form):
-... first_name = CharField()
-... last_name = CharField()
-... birthday = DateField()
->>> class Musician(Person):
-... instrument = CharField()
->>> p = Person(auto_id=False)
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
->>> m = Musician(auto_id=False)
->>> print m.as_ul()
-First name:
-Last name:
-Birthday:
-Instrument:
-
-Yes, you can subclass multiple forms. The fields are added in the order in
-which the parent classes are listed.
->>> class Person(Form):
-... first_name = CharField()
-... last_name = CharField()
-... birthday = DateField()
->>> class Instrument(Form):
-... instrument = CharField()
->>> class Beatle(Person, Instrument):
-... haircut_type = CharField()
->>> b = Beatle(auto_id=False)
->>> print b.as_ul()
-First name:
-Last name:
-Birthday:
-Instrument:
-Haircut type:
-
-# Forms with prefixes #########################################################
-
-Sometimes it's necessary to have multiple forms display on the same HTML page,
-or multiple copies of the same form. We can accomplish this with form prefixes.
-Pass the keyword argument 'prefix' to the Form constructor to use this feature.
-This value will be prepended to each HTML form field name. One way to think
-about this is "namespaces for HTML forms". Notice that in the data argument,
-each field's key has the prefix, in this case 'person1', prepended to the
-actual field name.
->>> class Person(Form):
-... first_name = CharField()
-... last_name = CharField()
-... birthday = DateField()
->>> data = {
-... 'person1-first_name': u'John',
-... 'person1-last_name': u'Lennon',
-... 'person1-birthday': u'1940-10-9'
-... }
->>> p = Person(data, prefix='person1')
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
->>> print p['first_name']
-
->>> print p['last_name']
-
->>> print p['birthday']
-
->>> p.errors
-{}
->>> p.is_valid()
-True
->>> p.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
-
-Let's try submitting some bad data to make sure form.errors and field.errors
-work as expected.
->>> data = {
-... 'person1-first_name': u'',
-... 'person1-last_name': u'',
-... 'person1-birthday': u''
-... }
->>> p = Person(data, prefix='person1')
->>> p.errors
-{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
->>> p['first_name'].errors
-[u'This field is required.']
->>> p['person1-first_name'].errors
-Traceback (most recent call last):
-...
-KeyError: "Key 'person1-first_name' not found in Form"
-
-In this example, the data doesn't have a prefix, but the form requires it, so
-the form doesn't "see" the fields.
->>> data = {
-... 'first_name': u'John',
-... 'last_name': u'Lennon',
-... 'birthday': u'1940-10-9'
-... }
->>> p = Person(data, prefix='person1')
->>> p.errors
-{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
-
-With prefixes, a single data dictionary can hold data for multiple instances
-of the same form.
->>> data = {
-... 'person1-first_name': u'John',
-... 'person1-last_name': u'Lennon',
-... 'person1-birthday': u'1940-10-9',
-... 'person2-first_name': u'Jim',
-... 'person2-last_name': u'Morrison',
-... 'person2-birthday': u'1943-12-8'
-... }
->>> p1 = Person(data, prefix='person1')
->>> p1.is_valid()
-True
->>> p1.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
->>> p2 = Person(data, prefix='person2')
->>> p2.is_valid()
-True
->>> p2.cleaned_data
-{'first_name': u'Jim', 'last_name': u'Morrison', 'birthday': datetime.date(1943, 12, 8)}
-
-By default, forms append a hyphen between the prefix and the field name, but a
-form can alter that behavior by implementing the add_prefix() method. This
-method takes a field name and returns the prefixed field, according to
-self.prefix.
->>> class Person(Form):
-... first_name = CharField()
-... last_name = CharField()
-... birthday = DateField()
-... def add_prefix(self, field_name):
-... return self.prefix and '%s-prefix-%s' % (self.prefix, field_name) or field_name
->>> p = Person(prefix='foo')
->>> print p.as_ul()
-First name:
-Last name:
-Birthday:
->>> data = {
-... 'foo-prefix-first_name': u'John',
-... 'foo-prefix-last_name': u'Lennon',
-... 'foo-prefix-birthday': u'1940-10-9'
-... }
->>> p = Person(data, prefix='foo')
->>> p.is_valid()
-True
->>> p.cleaned_data
-{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
-
-# Forms with NullBooleanFields ################################################
-
-NullBooleanField is a bit of a special case because its presentation (widget)
-is different than its data. This is handled transparently, though.
-
->>> class Person(Form):
-... name = CharField()
-... is_cool = NullBooleanField()
->>> p = Person({'name': u'Joe'}, auto_id=False)
->>> print p['is_cool']
-
-Unknown
-Yes
-No
-
->>> p = Person({'name': u'Joe', 'is_cool': u'1'}, auto_id=False)
->>> print p['is_cool']
-
-Unknown
-Yes
-No
-
->>> p = Person({'name': u'Joe', 'is_cool': u'2'}, auto_id=False)
->>> print p['is_cool']
-
-Unknown
-Yes
-No
-
->>> p = Person({'name': u'Joe', 'is_cool': u'3'}, auto_id=False)
->>> print p['is_cool']
-
-Unknown
-Yes
-No
-
->>> p = Person({'name': u'Joe', 'is_cool': True}, auto_id=False)
->>> print p['is_cool']
-
-Unknown
-Yes
-No
-
->>> p = Person({'name': u'Joe', 'is_cool': False}, auto_id=False)
->>> print p['is_cool']
-
-Unknown
-Yes
-No
-
-
-# Forms with FileFields ################################################
-
-FileFields are a special case because they take their data from the request.FILES,
-not request.POST.
-
->>> class FileForm(Form):
-... file1 = FileField()
->>> f = FileForm(auto_id=False)
->>> print f
-File1:
-
->>> f = FileForm(data={}, files={}, auto_id=False)
->>> print f
-File1:
-
->>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':''}}, auto_id=False)
->>> print f
-File1: The submitted file is empty.
-
->>> f = FileForm(data={}, files={'file1': 'something that is not a file'}, auto_id=False)
->>> print f
-File1: No file was submitted. Check the encoding type on the form.
-
->>> f = FileForm(data={}, files={'file1': {'filename': 'name', 'content':'some content'}}, auto_id=False)
->>> print f
-File1:
->>> f.is_valid()
-True
-
-# Basic form processing in a view #############################################
-
->>> from django.template import Template, Context
->>> class UserRegistration(Form):
-... username = CharField(max_length=10)
-... password1 = CharField(widget=PasswordInput)
-... password2 = CharField(widget=PasswordInput)
-... def clean(self):
-... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
-... raise ValidationError(u'Please make sure your passwords match.')
-... return self.cleaned_data
->>> def my_function(method, post_data):
-... if method == 'POST':
-... form = UserRegistration(post_data, auto_id=False)
-... else:
-... form = UserRegistration(auto_id=False)
-... if form.is_valid():
-... return 'VALID: %r' % form.cleaned_data
-... t = Template('')
-... return t.render(Context({'form': form}))
-
-Case 1: GET (an empty form, with no errors).
->>> print my_function('GET', {})
-
-
-Case 2: POST with erroneous data (a redisplayed form, with errors).
->>> print my_function('POST', {'username': 'this-is-a-long-username', 'password1': 'foo', 'password2': 'bar'})
-
-
-Case 3: POST with valid data (the success message).
->>> print my_function('POST', {'username': 'adrian', 'password1': 'secret', 'password2': 'secret'})
-VALID: {'username': u'adrian', 'password1': u'secret', 'password2': u'secret'}
-
-# Some ideas for using templates with forms ###################################
-
->>> class UserRegistration(Form):
-... username = CharField(max_length=10, help_text="Good luck picking a username that doesn't already exist.")
-... password1 = CharField(widget=PasswordInput)
-... password2 = CharField(widget=PasswordInput)
-... def clean(self):
-... if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_data['password2']:
-... raise ValidationError(u'Please make sure your passwords match.')
-... return self.cleaned_data
-
-You have full flexibility in displaying form fields in a template. Just pass a
-Form instance to the template, and use "dot" access to refer to individual
-fields. Note, however, that this flexibility comes with the responsibility of
-displaying all the errors, including any that might not be associated with a
-particular field.
->>> t = Template('''''')
->>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
-
->>> print t.render(Context({'form': UserRegistration({'username': 'django'}, auto_id=False)}))
-
-
-Use form.[field].label to output a field's label. You can specify the label for
-a field by using the 'label' argument to a Field class. If you don't specify
-'label', Django will use the field name with underscores converted to spaces,
-and the initial letter capitalized.
->>> t = Template('''''')
->>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
-
-
-User form.[field].label_tag to output a field's label with a tag
-wrapped around it, but *only* if the given field has an "id" attribute.
-Recall from above that passing the "auto_id" argument to a Form gives each
-field an "id" attribute.
->>> t = Template('''''')
->>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
-
->>> print t.render(Context({'form': UserRegistration(auto_id='id_%s')}))
-
-
-User form.[field].help_text to output a field's help text. If the given field
-does not have help text, nothing will be output.
->>> t = Template('''''')
->>> print t.render(Context({'form': UserRegistration(auto_id=False)}))
-
->>> Template('{{ form.password1.help_text }}').render(Context({'form': UserRegistration(auto_id=False)}))
-u''
-
-The label_tag() method takes an optional attrs argument: a dictionary of HTML
-attributes to add to the tag.
->>> f = UserRegistration(auto_id='id_%s')
->>> for bf in f:
-... print bf.label_tag(attrs={'class': 'pretty'})
-Username
-Password1
-Password2
-
-To display the errors that aren't associated with a particular field -- e.g.,
-the errors caused by Form.clean() -- use {{ form.non_field_errors }} in the
-template. If used on its own, it is displayed as a (or an empty string, if
-the list of errors is empty). You can also use it in {% if %} statements.
->>> t = Template(''' ''')
->>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)}))
-
->>> t = Template('''''')
->>> print t.render(Context({'form': UserRegistration({'username': 'django', 'password1': 'foo', 'password2': 'bar'}, auto_id=False)}))
-
-
-###############
-# Extra stuff #
-###############
-
-The newforms library comes with some extra, higher-level Field and Widget
-classes that demonstrate some of the library's abilities.
-
-# SelectDateWidget ############################################################
-
->>> from django.newforms.extras import SelectDateWidget
->>> w = SelectDateWidget(years=('2007','2008','2009','2010','2011','2012','2013','2014','2015','2016'))
->>> print w.render('mydate', '')
-
-January
-February
-March
-April
-May
-June
-July
-August
-September
-October
-November
-December
-
-
-1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-
-
-2007
-2008
-2009
-2010
-2011
-2012
-2013
-2014
-2015
-2016
-
->>> w.render('mydate', None) == w.render('mydate', '')
-True
->>> print w.render('mydate', '2010-04-15')
-
-January
-February
-March
-April
-May
-June
-July
-August
-September
-October
-November
-December
-
-
-1
-2
-3
-4
-5
-6
-7
-8
-9
-10
-11
-12
-13
-14
-15
-16
-17
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
-
-
-2007
-2008
-2009
-2010
-2011
-2012
-2013
-2014
-2015
-2016
-
-
-Using a SelectDateWidget in a form:
-
->>> class GetDate(Form):
-... mydate = DateField(widget=SelectDateWidget)
->>> a = GetDate({'mydate_month':'4', 'mydate_day':'1', 'mydate_year':'2008'})
->>> print a.is_valid()
-True
->>> print a.cleaned_data['mydate']
-2008-04-01
-
-As with any widget that implements get_value_from_datadict,
-we must be prepared to accept the input from the "as_hidden"
-rendering as well.
-
->>> print a['mydate'].as_hidden()
-
->>> b=GetDate({'mydate':'2008-4-1'})
->>> print b.is_valid()
-True
->>> print b.cleaned_data['mydate']
-2008-04-01
-
-
-# MultiWidget and MultiValueField #############################################
-# MultiWidgets are widgets composed of other widgets. They are usually
-# combined with MultiValueFields - a field that is composed of other fields.
-# MulitWidgets can themselved be composed of other MultiWidgets.
-# SplitDateTimeWidget is one example of a MultiWidget.
-
->>> class ComplexMultiWidget(MultiWidget):
-... def __init__(self, attrs=None):
-... widgets = (
-... TextInput(),
-... SelectMultiple(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
-... SplitDateTimeWidget(),
-... )
-... super(ComplexMultiWidget, self).__init__(widgets, attrs)
-...
-... def decompress(self, value):
-... if value:
-... data = value.split(',')
-... return [data[0], data[1], datetime.datetime(*time.strptime(data[2], "%Y-%m-%d %H:%M:%S")[0:6])]
-... return [None, None, None]
-... def format_output(self, rendered_widgets):
-... return u'\n'.join(rendered_widgets)
->>> w = ComplexMultiWidget()
->>> print w.render('name', 'some text,JP,2007-04-25 06:24:00')
-
-
-John
-Paul
-George
-Ringo
-
-
-
->>> class ComplexField(MultiValueField):
-... def __init__(self, required=True, widget=None, label=None, initial=None):
-... fields = (
-... CharField(),
-... MultipleChoiceField(choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo'))),
-... SplitDateTimeField()
-... )
-... super(ComplexField, self).__init__(fields, required, widget, label, initial)
-...
-... def compress(self, data_list):
-... if data_list:
-... return '%s,%s,%s' % (data_list[0],''.join(data_list[1]),data_list[2])
-... return None
-
->>> f = ComplexField(widget=w)
->>> f.clean(['some text', ['J','P'], ['2007-04-25','6:24:00']])
-u'some text,JP,2007-04-25 06:24:00'
->>> f.clean(['some text',['X'], ['2007-04-25','6:24:00']])
-Traceback (most recent call last):
-...
-ValidationError: [u'Select a valid choice. X is not one of the available choices.']
-
-# If insufficient data is provided, None is substituted
->>> f.clean(['some text',['JP']])
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
-
->>> class ComplexFieldForm(Form):
-... field1 = ComplexField(widget=w)
->>> f = ComplexFieldForm()
->>> print f
-Field1:
-
-John
-Paul
-George
-Ringo
-
-
-
->>> f = ComplexFieldForm({'field1_0':'some text','field1_1':['J','P'], 'field1_2_0':'2007-04-25', 'field1_2_1':'06:24:00'})
->>> print f
-Field1:
-
-John
-Paul
-George
-Ringo
-
-
-
->>> f.cleaned_data
-{'field1': u'some text,JP,2007-04-25 06:24:00'}
-
-
-# IPAddressField ##################################################################
-
->>> f = IPAddressField()
->>> f.clean('')
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean(None)
-Traceback (most recent call last):
-...
-ValidationError: [u'This field is required.']
->>> f.clean('127.0.0.1')
-u'127.0.0.1'
->>> f.clean('foo')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid IPv4 address.']
->>> f.clean('127.0.0.')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid IPv4 address.']
->>> f.clean('1.2.3.4.5')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid IPv4 address.']
->>> f.clean('256.125.1.5')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid IPv4 address.']
-
->>> f = IPAddressField(required=False)
->>> f.clean('')
-u''
->>> f.clean(None)
-u''
->>> f.clean('127.0.0.1')
-u'127.0.0.1'
->>> f.clean('foo')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid IPv4 address.']
->>> f.clean('127.0.0.')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid IPv4 address.']
->>> f.clean('1.2.3.4.5')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid IPv4 address.']
->>> f.clean('256.125.1.5')
-Traceback (most recent call last):
-...
-ValidationError: [u'Enter a valid IPv4 address.']
-
-#################################
-# Tests of underlying functions #
-#################################
-
-# smart_unicode tests
->>> from django.utils.encoding import smart_unicode
->>> class Test:
-... def __str__(self):
-... return 'ŠĐĆŽćžšđ'
->>> class TestU:
-... def __str__(self):
-... return 'Foo'
-... def __unicode__(self):
-... return u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
->>> smart_unicode(Test())
-u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
->>> smart_unicode(TestU())
-u'\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111'
->>> smart_unicode(1)
-u'1'
->>> smart_unicode('foo')
-u'foo'
-
-
-####################################
-# Test accessing errors in clean() #
-####################################
-
->>> class UserForm(Form):
-... username = CharField(max_length=10)
-... password = CharField(widget=PasswordInput)
-... def clean(self):
-... data = self.cleaned_data
-... if not self.errors:
-... data['username'] = data['username'].lower()
-... return data
-
->>> f = UserForm({'username': 'SirRobin', 'password': 'blue'})
->>> f.is_valid()
-True
->>> f.cleaned_data['username']
-u'sirrobin'
-
-#######################################
-# Test overriding ErrorList in a form #
-#######################################
-
->>> from django.newforms.util import ErrorList
->>> class DivErrorList(ErrorList):
-... def __unicode__(self):
-... return self.as_divs()
-... def as_divs(self):
-... if not self: return u''
-... return u'%s
' % ''.join([u'%s
' % e for e in self])
->>> class CommentForm(Form):
-... name = CharField(max_length=50, required=False)
-... email = EmailField()
-... comment = CharField()
->>> data = dict(email='invalid')
->>> f = CommentForm(data, auto_id=False, error_class=DivErrorList)
->>> print f.as_p()
-Name:
-Enter a valid e-mail address.
-Email:
-
-Comment:
-
-#################################
-# Test multipart-encoded form #
-#################################
-
->>> class FormWithoutFile(Form):
-... username = CharField()
->>> class FormWithFile(Form):
-... username = CharField()
-... file = FileField()
->>> class FormWithImage(Form):
-... image = ImageField()
-
->>> FormWithoutFile().is_multipart()
-False
->>> FormWithFile().is_multipart()
-True
->>> FormWithImage().is_multipart()
-True
-
-"""
+from extra import tests as extra_tests
+from fields import tests as fields_tests
+from forms import tests as form_tests
+from localflavor.ar import tests as localflavor_ar_tests
+from localflavor.au import tests as localflavor_au_tests
+from localflavor.br import tests as localflavor_br_tests
+from localflavor.ca import tests as localflavor_ca_tests
+from localflavor.ch import tests as localflavor_ch_tests
+from localflavor.cl import tests as localflavor_cl_tests
+from localflavor.de import tests as localflavor_de_tests
+from localflavor.fi import tests as localflavor_fi_tests
+from localflavor.fr import tests as localflavor_fr_tests
+from localflavor.generic import tests as localflavor_generic_tests
+from localflavor.is_ import tests as localflavor_is_tests
+from localflavor.it import tests as localflavor_it_tests
+from localflavor.jp import tests as localflavor_jp_tests
+from localflavor.nl import tests as localflavor_nl_tests
+from localflavor.pl import tests as localflavor_pl_tests
+from localflavor.sk import tests as localflavor_sk_tests
+from localflavor.uk import tests as localflavor_uk_tests
+from localflavor.us import tests as localflavor_us_tests
+from regressions import tests as regression_tests
+from util import tests as util_tests
+from widgets import tests as widgets_tests
__test__ = {
+ 'extra_tests': extra_tests,
+ 'fields_tests': fields_tests,
'form_tests': form_tests,
- 'localflavor': localflavor_tests,
- 'regressions': regression_tests,
+ 'localflavor_ar_tests': localflavor_ar_tests,
+ 'localflavor_au_tests': localflavor_au_tests,
+ 'localflavor_br_tests': localflavor_br_tests,
+ 'localflavor_ca_tests': localflavor_ca_tests,
+ 'localflavor_ch_tests': localflavor_ch_tests,
+ 'localflavor_cl_tests': localflavor_cl_tests,
+ 'localflavor_de_tests': localflavor_de_tests,
+ 'localflavor_fi_tests': localflavor_fi_tests,
+ 'localflavor_fr_tests': localflavor_fr_tests,
+ 'localflavor_generic_tests': localflavor_generic_tests,
+ 'localflavor_is_tests': localflavor_is_tests,
+ 'localflavor_it_tests': localflavor_it_tests,
+ 'localflavor_jp_tests': localflavor_jp_tests,
+ 'localflavor_nl_tests': localflavor_nl_tests,
+ 'localflavor_pl_tests': localflavor_pl_tests,
+ 'localflavor_sk_tests': localflavor_sk_tests,
+ 'localflavor_uk_tests': localflavor_uk_tests,
+ 'localflavor_us_tests': localflavor_us_tests,
+ 'regressions_tests': regression_tests,
'util_tests': util_tests,
+ 'widgets_tests': widgets_tests,
}
if __name__ == "__main__":
diff --git a/tests/regressiontests/forms/util.py b/tests/regressiontests/forms/util.py
index 1a02b7e55b..4f81709082 100644
--- a/tests/regressiontests/forms/util.py
+++ b/tests/regressiontests/forms/util.py
@@ -3,7 +3,7 @@
Tests for newforms/util.py module.
"""
-util_tests = r"""
+tests = r"""
>>> from django.newforms.util import *
>>> from django.utils.translation import ugettext_lazy
diff --git a/tests/regressiontests/forms/widgets.py b/tests/regressiontests/forms/widgets.py
new file mode 100644
index 0000000000..1c3e873963
--- /dev/null
+++ b/tests/regressiontests/forms/widgets.py
@@ -0,0 +1,848 @@
+# -*- coding: utf-8 -*-
+tests = r"""
+>>> from django.newforms import *
+>>> from django.newforms.widgets import RadioFieldRenderer
+>>> import datetime
+>>> import time
+>>> import re
+>>> try:
+... from decimal import Decimal
+... except ImportError:
+... from django.utils._decimal import Decimal
+
+###########
+# Widgets #
+###########
+
+Each Widget class corresponds to an HTML form widget. A Widget knows how to
+render itself, given a field name and some data. Widgets don't perform
+validation.
+
+# TextInput Widget ############################################################
+
+>>> w = TextInput()
+>>> w.render('email', '')
+u' '
+>>> w.render('email', None)
+u' '
+>>> w.render('email', 'test@example.com')
+u' '
+>>> w.render('email', 'some "quoted" & ampersanded value')
+u' '
+>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
+u' '
+
+# Note that doctest in Python 2.4 (and maybe 2.5?) doesn't support non-ascii
+# characters in output, so we're displaying the repr() here.
+>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
+u' '
+
+You can also pass 'attrs' to the constructor:
+>>> w = TextInput(attrs={'class': 'fun'})
+>>> w.render('email', '')
+u' '
+>>> w.render('email', 'foo@example.com')
+u' '
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = TextInput(attrs={'class': 'pretty'})
+>>> w.render('email', '', attrs={'class': 'special'})
+u' '
+
+# PasswordInput Widget ############################################################
+
+>>> w = PasswordInput()
+>>> w.render('email', '')
+u' '
+>>> w.render('email', None)
+u' '
+>>> w.render('email', 'test@example.com')
+u' '
+>>> w.render('email', 'some "quoted" & ampersanded value')
+u' '
+>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
+u' '
+
+You can also pass 'attrs' to the constructor:
+>>> w = PasswordInput(attrs={'class': 'fun'})
+>>> w.render('email', '')
+u' '
+>>> w.render('email', 'foo@example.com')
+u' '
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = PasswordInput(attrs={'class': 'pretty'})
+>>> w.render('email', '', attrs={'class': 'special'})
+u' '
+
+>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
+u' '
+
+The render_value argument lets you specify whether the widget should render
+its value. You may want to do this for security reasons.
+>>> w = PasswordInput(render_value=True)
+>>> w.render('email', 'secret')
+u' '
+>>> w = PasswordInput(render_value=False)
+>>> w.render('email', '')
+u' '
+>>> w.render('email', None)
+u' '
+>>> w.render('email', 'secret')
+u' '
+>>> w = PasswordInput(attrs={'class': 'fun'}, render_value=False)
+>>> w.render('email', 'secret')
+u' '
+
+# HiddenInput Widget ############################################################
+
+>>> w = HiddenInput()
+>>> w.render('email', '')
+u' '
+>>> w.render('email', None)
+u' '
+>>> w.render('email', 'test@example.com')
+u' '
+>>> w.render('email', 'some "quoted" & ampersanded value')
+u' '
+>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
+u' '
+
+You can also pass 'attrs' to the constructor:
+>>> w = HiddenInput(attrs={'class': 'fun'})
+>>> w.render('email', '')
+u' '
+>>> w.render('email', 'foo@example.com')
+u' '
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = HiddenInput(attrs={'class': 'pretty'})
+>>> w.render('email', '', attrs={'class': 'special'})
+u' '
+
+>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
+u' '
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = HiddenInput(attrs={'class': 'pretty'})
+>>> w.render('email', '', attrs={'class': 'special'})
+u' '
+
+# MultipleHiddenInput Widget ##################################################
+
+>>> w = MultipleHiddenInput()
+>>> w.render('email', [])
+u''
+>>> w.render('email', None)
+u''
+>>> w.render('email', ['test@example.com'])
+u' '
+>>> w.render('email', ['some "quoted" & ampersanded value'])
+u' '
+>>> w.render('email', ['test@example.com', 'foo@example.com'])
+u' \n '
+>>> w.render('email', ['test@example.com'], attrs={'class': 'fun'})
+u' '
+>>> w.render('email', ['test@example.com', 'foo@example.com'], attrs={'class': 'fun'})
+u' \n '
+
+You can also pass 'attrs' to the constructor:
+>>> w = MultipleHiddenInput(attrs={'class': 'fun'})
+>>> w.render('email', [])
+u''
+>>> w.render('email', ['foo@example.com'])
+u' '
+>>> w.render('email', ['foo@example.com', 'test@example.com'])
+u' \n '
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
+>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
+u' '
+
+>>> w.render('email', ['ŠĐĆŽćžšđ'], attrs={'class': 'fun'})
+u' '
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = MultipleHiddenInput(attrs={'class': 'pretty'})
+>>> w.render('email', ['foo@example.com'], attrs={'class': 'special'})
+u' '
+
+# FileInput Widget ############################################################
+
+FileInput widgets don't ever show the value, because the old value is of no use
+if you are updating the form or if the provided file generated an error.
+>>> w = FileInput()
+>>> w.render('email', '')
+u' '
+>>> w.render('email', None)
+u' '
+>>> w.render('email', 'test@example.com')
+u' '
+>>> w.render('email', 'some "quoted" & ampersanded value')
+u' '
+>>> w.render('email', 'test@example.com', attrs={'class': 'fun'})
+u' '
+
+You can also pass 'attrs' to the constructor:
+>>> w = FileInput(attrs={'class': 'fun'})
+>>> w.render('email', '')
+u' '
+>>> w.render('email', 'foo@example.com')
+u' '
+
+>>> w.render('email', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
+u' '
+
+# Textarea Widget #############################################################
+
+>>> w = Textarea()
+>>> w.render('msg', '')
+u''
+>>> w.render('msg', None)
+u''
+>>> w.render('msg', 'value')
+u''
+>>> w.render('msg', 'some "quoted" & ampersanded value')
+u''
+>>> w.render('msg', 'value', attrs={'class': 'pretty', 'rows': 20})
+u''
+
+You can also pass 'attrs' to the constructor:
+>>> w = Textarea(attrs={'class': 'pretty'})
+>>> w.render('msg', '')
+u''
+>>> w.render('msg', 'example')
+u''
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = Textarea(attrs={'class': 'pretty'})
+>>> w.render('msg', '', attrs={'class': 'special'})
+u''
+
+>>> w.render('msg', 'ŠĐĆŽćžšđ', attrs={'class': 'fun'})
+u''
+
+# CheckboxInput Widget ########################################################
+
+>>> w = CheckboxInput()
+>>> w.render('is_cool', '')
+u' '
+>>> w.render('is_cool', None)
+u' '
+>>> w.render('is_cool', False)
+u' '
+>>> w.render('is_cool', True)
+u' '
+
+Using any value that's not in ('', None, False, True) will check the checkbox
+and set the 'value' attribute.
+>>> w.render('is_cool', 'foo')
+u' '
+
+>>> w.render('is_cool', False, attrs={'class': 'pretty'})
+u' '
+
+You can also pass 'attrs' to the constructor:
+>>> w = CheckboxInput(attrs={'class': 'pretty'})
+>>> w.render('is_cool', '')
+u' '
+
+'attrs' passed to render() get precedence over those passed to the constructor:
+>>> w = CheckboxInput(attrs={'class': 'pretty'})
+>>> w.render('is_cool', '', attrs={'class': 'special'})
+u' '
+
+You can pass 'check_test' to the constructor. This is a callable that takes the
+value and returns True if the box should be checked.
+>>> w = CheckboxInput(check_test=lambda value: value.startswith('hello'))
+>>> w.render('greeting', '')
+u' '
+>>> w.render('greeting', 'hello')
+u' '
+>>> w.render('greeting', 'hello there')
+u' '
+>>> w.render('greeting', 'hello & goodbye')
+u' '
+
+A subtlety: If the 'check_test' argument cannot handle a value and raises any
+exception during its __call__, then the exception will be swallowed and the box
+will not be checked. In this example, the 'check_test' assumes the value has a
+startswith() method, which fails for the values True, False and None.
+>>> w.render('greeting', True)
+u' '
+>>> w.render('greeting', False)
+u' '
+>>> w.render('greeting', None)
+u' '
+
+# Select Widget ###############################################################
+
+>>> w = Select()
+>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+
+If the value is None, none of the options are selected:
+>>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+
+If the value corresponds to a label (but not to an option value), none of the options are selected:
+>>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+
+The value is compared to its str():
+>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
+
+1
+2
+3
+
+>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
+
+1
+2
+3
+
+>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
+
+1
+2
+3
+
+
+The 'choices' argument can be any iterable:
+>>> from itertools import chain
+>>> def get_choices():
+... for i in range(5):
+... yield (i, i)
+>>> print w.render('num', 2, choices=get_choices())
+
+0
+1
+2
+3
+4
+
+>>> things = ({'id': 1, 'name': 'And Boom'}, {'id': 2, 'name': 'One More Thing!'})
+>>> class SomeForm(Form):
+... somechoice = ChoiceField(choices=chain((('', '-'*9),), [(thing['id'], thing['name']) for thing in things]))
+>>> f = SomeForm()
+>>> f.as_table()
+u'Somechoice: \n--------- \nAnd Boom \nOne More Thing! \n '
+>>> f.as_table()
+u'Somechoice: \n--------- \nAnd Boom \nOne More Thing! \n '
+>>> f = SomeForm({'somechoice': 2})
+>>> f.as_table()
+u'Somechoice: \n--------- \nAnd Boom \nOne More Thing! \n '
+
+You can also pass 'choices' to the constructor:
+>>> w = Select(choices=[(1, 1), (2, 2), (3, 3)])
+>>> print w.render('num', 2)
+
+1
+2
+3
+
+
+If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
+>>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
+
+1
+2
+3
+4
+5
+
+
+>>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
+u'\n1 \n2 \n3 \n\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111 \nabc\u0107\u017e\u0161\u0111 \n '
+
+If choices is passed to the constructor and is a generator, it can be iterated
+over multiple times without getting consumed:
+>>> w = Select(choices=get_choices())
+>>> print w.render('num', 2)
+
+0
+1
+2
+3
+4
+
+>>> print w.render('num', 3)
+
+0
+1
+2
+3
+4
+
+
+# NullBooleanSelect Widget ####################################################
+
+>>> w = NullBooleanSelect()
+>>> print w.render('is_cool', True)
+
+Unknown
+Yes
+No
+
+>>> print w.render('is_cool', False)
+
+Unknown
+Yes
+No
+
+>>> print w.render('is_cool', None)
+
+Unknown
+Yes
+No
+
+>>> print w.render('is_cool', '2')
+
+Unknown
+Yes
+No
+
+>>> print w.render('is_cool', '3')
+
+Unknown
+Yes
+No
+
+
+""" + \
+r""" # [This concatenation is to keep the string below the jython's 32K limit].
+# SelectMultiple Widget #######################################################
+
+>>> w = SelectMultiple()
+>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+
+If the value is None, none of the options are selected:
+>>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+
+If the value corresponds to a label (but not to an option value), none of the options are selected:
+>>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+
+If multiple values are given, but some of them are not valid, the valid ones are selected:
+>>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+John
+Paul
+George
+Ringo
+
+
+The value is compared to its str():
+>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
+
+1
+2
+3
+
+>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
+
+1
+2
+3
+
+>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
+
+1
+2
+3
+
+
+The 'choices' argument can be any iterable:
+>>> def get_choices():
+... for i in range(5):
+... yield (i, i)
+>>> print w.render('nums', [2], choices=get_choices())
+
+0
+1
+2
+3
+4
+
+
+You can also pass 'choices' to the constructor:
+>>> w = SelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
+>>> print w.render('nums', [2])
+
+1
+2
+3
+
+
+If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
+>>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
+
+1
+2
+3
+4
+5
+
+
+>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
+u'\n1 \n2 \n3 \n\u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111 \nabc\u0107\u017e\u0161\u0111 \n '
+
+# RadioSelect Widget ##########################################################
+
+>>> w = RadioSelect()
+>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+If the value is None, none of the options are checked:
+>>> print w.render('beatle', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+If the value corresponds to a label (but not to an option value), none of the options are checked:
+>>> print w.render('beatle', 'John', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+The value is compared to its str():
+>>> print w.render('num', 2, choices=[('1', '1'), ('2', '2'), ('3', '3')])
+
+>>> print w.render('num', '2', choices=[(1, 1), (2, 2), (3, 3)])
+
+>>> print w.render('num', 2, choices=[(1, 1), (2, 2), (3, 3)])
+
+
+The 'choices' argument can be any iterable:
+>>> def get_choices():
+... for i in range(5):
+... yield (i, i)
+>>> print w.render('num', 2, choices=get_choices())
+
+
+You can also pass 'choices' to the constructor:
+>>> w = RadioSelect(choices=[(1, 1), (2, 2), (3, 3)])
+>>> print w.render('num', 2)
+
+
+If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
+>>> print w.render('num', 2, choices=[(4, 4), (5, 5)])
+
+
+RadioSelect uses a RadioFieldRenderer to render the individual radio inputs.
+You can manipulate that object directly to customize the way the RadioSelect
+is rendered.
+>>> w = RadioSelect()
+>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+>>> for inp in r:
+... print inp
+ John
+ Paul
+ George
+ Ringo
+>>> for inp in r:
+... print '%s ' % inp
+ John
+ Paul
+ George
+ Ringo
+>>> for inp in r:
+... print '%s %s
' % (inp.tag(), inp.choice_label)
+ John
+ Paul
+ George
+ Ringo
+>>> for inp in r:
+... print '%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())
+beatle J J John True
+beatle J P Paul False
+beatle J G George False
+beatle J R Ringo False
+
+You can create your own custom renderers for RadioSelect to use.
+>>> class MyRenderer(RadioFieldRenderer):
+... def render(self):
+... return u' \n'.join([unicode(choice) for choice in self])
+>>> w = RadioSelect(renderer=MyRenderer)
+>>> print w.render('beatle', 'G', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+ John
+ Paul
+ George
+ Ringo
+
+A RadioFieldRenderer object also allows index access to individual RadioInput
+objects.
+>>> w = RadioSelect()
+>>> r = w.get_renderer('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+>>> print r[1]
+ Paul
+>>> print r[0]
+ John
+>>> r[0].is_checked()
+True
+>>> r[1].is_checked()
+False
+>>> r[1].name, r[1].value, r[1].choice_value, r[1].choice_label
+('beatle', u'J', u'P', u'Paul')
+>>> r[10]
+Traceback (most recent call last):
+...
+IndexError: list index out of range
+
+# Unicode choices are correctly rendered as HTML
+>>> w = RadioSelect()
+>>> unicode(w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
+u''
+
+# Attributes provided at instantiation are passed to the constituent inputs
+>>> w = RadioSelect(attrs={'id':'foo'})
+>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+# Attributes provided at render-time are passed to the constituent inputs
+>>> w = RadioSelect()
+>>> print w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')), attrs={'id':'bar'})
+
+
+# CheckboxSelectMultiple Widget ###############################################
+
+>>> w = CheckboxSelectMultiple()
+>>> print w.render('beatles', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+>>> print w.render('beatles', ['J', 'P'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+>>> print w.render('beatles', ['J', 'P', 'R'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+If the value is None, none of the options are selected:
+>>> print w.render('beatles', None, choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+If the value corresponds to a label (but not to an option value), none of the options are selected:
+>>> print w.render('beatles', ['John'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+If multiple values are given, but some of them are not valid, the valid ones are selected:
+>>> print w.render('beatles', ['J', 'G', 'foo'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
+
+
+The value is compared to its str():
+>>> print w.render('nums', [2], choices=[('1', '1'), ('2', '2'), ('3', '3')])
+
+>>> print w.render('nums', ['2'], choices=[(1, 1), (2, 2), (3, 3)])
+
+>>> print w.render('nums', [2], choices=[(1, 1), (2, 2), (3, 3)])
+
+
+The 'choices' argument can be any iterable:
+>>> def get_choices():
+... for i in range(5):
+... yield (i, i)
+>>> print w.render('nums', [2], choices=get_choices())
+
+
+You can also pass 'choices' to the constructor:
+>>> w = CheckboxSelectMultiple(choices=[(1, 1), (2, 2), (3, 3)])
+>>> print w.render('nums', [2])
+
+
+If 'choices' is passed to both the constructor and render(), then they'll both be in the output:
+>>> print w.render('nums', [2], choices=[(4, 4), (5, 5)])
+
+
+>>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
+u''
+
+# MultiWidget #################################################################
+
+>>> class MyMultiWidget(MultiWidget):
+... def decompress(self, value):
+... if value:
+... return value.split('__')
+... return ['', '']
+... def format_output(self, rendered_widgets):
+... return u' '.join(rendered_widgets)
+>>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})))
+>>> w.render('name', ['john', 'lennon'])
+u' '
+>>> w.render('name', 'john__lennon')
+u' '
+>>> w.render('name', 'john__lennon', attrs={'id':'foo'})
+u' '
+>>> w = MyMultiWidget(widgets=(TextInput(attrs={'class': 'big'}), TextInput(attrs={'class': 'small'})), attrs={'id': 'bar'})
+>>> w.render('name', ['john', 'lennon'])
+u' '
+
+# SplitDateTimeWidget #########################################################
+
+>>> w = SplitDateTimeWidget()
+>>> w.render('date', '')
+u' '
+>>> w.render('date', None)
+u' '
+>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
+u' '
+>>> w.render('date', [datetime.date(2006, 1, 10), datetime.time(7, 30)])
+u' '
+
+You can also pass 'attrs' to the constructor. In this case, the attrs will be
+included on both widgets.
+>>> w = SplitDateTimeWidget(attrs={'class': 'pretty'})
+>>> w.render('date', datetime.datetime(2006, 1, 10, 7, 30))
+u' '
+"""