# -*- coding: utf-8 -*- from localflavor import localflavor_tests from regressions import regression_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'))) 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'))) 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'))) 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: >>> from itertools import chain >>> def get_choices(): ... for i in range(5): ... yield (i, i) >>> print w.render('num', 2, choices=get_choices()) >>> 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'' >>> f.as_table() u'' >>> f = SomeForm({'somechoice': 2}) >>> f.as_table() u'' You can also pass 'choices' to the constructor: >>> w = Select(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)]) >>> w.render('email', 'ŠĐĆŽćžšđ', choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]) u'' 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) >>> print w.render('num', 3) # NullBooleanSelect Widget #################################################### >>> w = NullBooleanSelect() >>> print w.render('is_cool', True) >>> print w.render('is_cool', False) >>> print w.render('is_cool', None) >>> print w.render('is_cool', '2') >>> print w.render('is_cool', '3') # SelectMultiple Widget ####################################################### >>> w = SelectMultiple() >>> 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 = SelectMultiple(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'' # 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 >>> for inp in r: ... print '%s
' % inp



>>> 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')))


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] >>> print r[0] >>> 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('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('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('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 = 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://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('example.com') 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('example.com') 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).'] # 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 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 >>> print p.as_table() >>> print p.as_ul()
  • >>> print p.as_p()

    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 >>> print p.as_table() >>> print p.as_ul()
  • >>> print p.as_p()

    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'\n\n' >>> p.as_ul() u'
  • \n
  • \n
  • ' >>> p.as_p() u'

    \n

    \n

    ' >>> 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