Changed the fix from [5231] so that the backwards-incompatibility is made more

obvious and everything still has nice names.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@5237 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2007-05-14 16:24:51 +00:00
parent 41fbd35613
commit b996e214c0
7 changed files with 81 additions and 78 deletions

View File

@ -24,7 +24,7 @@ Usage
Subclass FormPreview and define a done() method: Subclass FormPreview and define a done() method:
def done(self, request, clean_data): def done(self, request, cleaned_data):
# ... # ...
This method takes an HttpRequest object and a dictionary of the form data after This method takes an HttpRequest object and a dictionary of the form data after
@ -113,7 +113,7 @@ class FormPreview(object):
if f.is_valid(): if f.is_valid():
if self.security_hash(request, f) != request.POST.get(self.unused_name('hash')): if self.security_hash(request, f) != request.POST.get(self.unused_name('hash')):
return self.failed_hash(request) # Security hash failed. return self.failed_hash(request) # Security hash failed.
return self.done(request, f.clean_data) return self.done(request, f.cleaned_data)
else: else:
return render_to_response(self.form_template, return render_to_response(self.form_template,
{'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state}, {'form': f, 'stage_field': self.unused_name('stage'), 'state': self.state},
@ -160,6 +160,9 @@ class FormPreview(object):
# METHODS SUBCLASSES MUST OVERRIDE ######################################## # METHODS SUBCLASSES MUST OVERRIDE ########################################
def done(self, request, clean_data): def done(self, request, cleaned_data):
"Does something with the clean_data and returns an HttpResponseRedirect." """
Does something with the cleaned_data and returns an
HttpResponseRedirect.
"""
raise NotImplementedError('You must define a done() method on your %s subclass.' % self.__class__.__name__) raise NotImplementedError('You must define a done() method on your %s subclass.' % self.__class__.__name__)

View File

@ -169,13 +169,13 @@ class BaseForm(StrAndUnicode):
def full_clean(self): def full_clean(self):
""" """
Cleans all of self.data and populates self.__errors and self.clean_data. Cleans all of self.data and populates self.__errors and self.cleaned_data.
""" """
errors = ErrorDict() errors = ErrorDict()
if not self.is_bound: # Stop further processing. if not self.is_bound: # Stop further processing.
self.__errors = errors self.__errors = errors
return return
self.clean_data = {} self.cleaned_data = {}
for name, field in self.fields.items(): for name, field in self.fields.items():
# value_from_datadict() gets the data from the dictionary. # value_from_datadict() gets the data from the dictionary.
# Each widget type knows how to retrieve its own data, because some # Each widget type knows how to retrieve its own data, because some
@ -183,18 +183,18 @@ class BaseForm(StrAndUnicode):
value = field.widget.value_from_datadict(self.data, self.add_prefix(name)) value = field.widget.value_from_datadict(self.data, self.add_prefix(name))
try: try:
value = field.clean(value) value = field.clean(value)
self.clean_data[name] = value self.cleaned_data[name] = value
if hasattr(self, 'do_clean_%s' % name): if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'do_clean_%s' % name)() value = getattr(self, 'clean_%s' % name)()
self.clean_data[name] = value self.cleaned_data[name] = value
except ValidationError, e: except ValidationError, e:
errors[name] = e.messages errors[name] = e.messages
try: try:
self.clean_data = self.clean() self.cleaned_data = self.clean()
except ValidationError, e: except ValidationError, e:
errors[NON_FIELD_ERRORS] = e.messages errors[NON_FIELD_ERRORS] = e.messages
if errors: if errors:
delattr(self, 'clean_data') delattr(self, 'cleaned_data')
self.__errors = errors self.__errors = errors
def clean(self): def clean(self):
@ -204,7 +204,7 @@ class BaseForm(StrAndUnicode):
not be associated with a particular field; it will have a special-case not be associated with a particular field; it will have a special-case
association with the field named '__all__'. association with the field named '__all__'.
""" """
return self.clean_data return self.cleaned_data
class Form(BaseForm): class Form(BaseForm):
"A collection of Fields, plus their associated data." "A collection of Fields, plus their associated data."

View File

@ -14,7 +14,7 @@ __all__ = ('save_instance', 'form_for_model', 'form_for_instance', 'form_for_fie
def save_instance(form, instance, fields=None, fail_message='saved', commit=True): def save_instance(form, instance, fields=None, fail_message='saved', commit=True):
""" """
Saves bound Form ``form``'s clean_data into model instance ``instance``. Saves bound Form ``form``'s cleaned_data into model instance ``instance``.
Assumes ``form`` has a field for every non-AutoField database field in Assumes ``form`` has a field for every non-AutoField database field in
``instance``. If commit=True, then the changes to ``instance`` will be ``instance``. If commit=True, then the changes to ``instance`` will be
@ -24,20 +24,20 @@ def save_instance(form, instance, fields=None, fail_message='saved', commit=True
opts = instance.__class__._meta opts = instance.__class__._meta
if form.errors: if form.errors:
raise ValueError("The %s could not be %s because the data didn't validate." % (opts.object_name, fail_message)) raise ValueError("The %s could not be %s because the data didn't validate." % (opts.object_name, fail_message))
clean_data = form.clean_data cleaned_data = form.cleaned_data
for f in opts.fields: for f in opts.fields:
if not f.editable or isinstance(f, models.AutoField) or not f.name in clean_data: if not f.editable or isinstance(f, models.AutoField) or not f.name in cleaned_data:
continue continue
if fields and f.name not in fields: if fields and f.name not in fields:
continue continue
setattr(instance, f.name, clean_data[f.name]) setattr(instance, f.name, cleaned_data[f.name])
if commit: if commit:
instance.save() instance.save()
for f in opts.many_to_many: for f in opts.many_to_many:
if fields and f.name not in fields: if fields and f.name not in fields:
continue continue
if f.name in clean_data: if f.name in cleaned_data:
setattr(instance, f.attname, clean_data[f.name]) setattr(instance, f.attname, cleaned_data[f.name])
# GOTCHA: If many-to-many data is given and commit=False, the many-to-many # GOTCHA: If many-to-many data is given and commit=False, the many-to-many
# data will be lost. This happens because a many-to-many options cannot be # data will be lost. This happens because a many-to-many options cannot be
# set on an object until after it's saved. Maybe we should raise an # set on an object until after it's saved. Maybe we should raise an

View File

@ -230,7 +230,7 @@ object. Regardless of whether you pass it a string in the format
it's valid. it's valid.
Once you've created a ``Form`` instance with a set of data and validated it, Once you've created a ``Form`` instance with a set of data and validated it,
you can access the clean data via the ``clean_data`` attribute of the ``Form`` you can access the clean data via the ``cleaned_data`` attribute of the ``Form``
object:: object::
>>> data = {'subject': 'hello', >>> data = {'subject': 'hello',
@ -240,7 +240,7 @@ object::
>>> f = ContactForm(data) >>> f = ContactForm(data)
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
Note that any text-based field -- such as ``CharField`` or ``EmailField`` -- Note that any text-based field -- such as ``CharField`` or ``EmailField`` --
@ -248,7 +248,7 @@ always cleans the input into a Unicode string. We'll cover the encoding
implications later in this document. implications later in this document.
If your data does *not* validate, your ``Form`` instance will not have a If your data does *not* validate, your ``Form`` instance will not have a
``clean_data`` attribute:: ``cleaned_data`` attribute::
>>> data = {'subject': '', >>> data = {'subject': '',
... 'message': 'Hi there', ... 'message': 'Hi there',
@ -257,15 +257,15 @@ If your data does *not* validate, your ``Form`` instance will not have a
>>> f = ContactForm(data) >>> f = ContactForm(data)
>>> f.is_valid() >>> f.is_valid()
False False
>>> f.clean_data >>> f.cleaned_data
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: 'ContactForm' object has no attribute 'clean_data' AttributeError: 'ContactForm' object has no attribute 'cleaned_data'
``clean_data`` will always *only* contain a key for fields defined in the ``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 ``Form``, even if you pass extra data when you define the ``Form``. In this
example, we pass a bunch of extra fields to the ``ContactForm`` constructor, example, we pass a bunch of extra fields to the ``ContactForm`` constructor,
but ``clean_data`` contains only the form's fields:: but ``cleaned_data`` contains only the form's fields::
>>> data = {'subject': 'hello', >>> data = {'subject': 'hello',
... 'message': 'Hi there', ... 'message': 'Hi there',
@ -277,13 +277,13 @@ but ``clean_data`` contains only the form's fields::
>>> f = ContactForm(data) >>> f = ContactForm(data)
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data # Doesn't contain extra_field_1, etc. >>> f.cleaned_data # Doesn't contain extra_field_1, etc.
{'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'} {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
``clean_data`` will include a key and value for *all* fields defined in the ``cleaned_data`` will include a key and value for *all* fields defined in the
``Form``, even if the data didn't include a value for fields that are not ``Form``, even if the 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 required. In this example, the data dictionary doesn't include a value for the
``nick_name`` field, but ``clean_data`` includes it, with an empty value:: ``nick_name`` field, but ``cleaned_data`` includes it, with an empty value::
>>> class OptionalPersonForm(Form): >>> class OptionalPersonForm(Form):
... first_name = CharField() ... first_name = CharField()
@ -293,10 +293,10 @@ required. In this example, the data dictionary doesn't include a value for the
>>> f = OptionalPersonForm(data) >>> f = OptionalPersonForm(data)
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}
In this above example, the ``clean_data`` value for ``nick_name`` is set to an In this above example, the ``cleaned_data`` value for ``nick_name`` is set to an
empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat empty string, because ``nick_name`` is ``CharField``, and ``CharField``\s treat
empty values as an empty string. Each field type knows what its "blank" value empty values as an empty string. Each field type knows what its "blank" value
is -- e.g., for ``DateField``, it's ``None`` instead of the empty string. is -- e.g., for ``DateField``, it's ``None`` instead of the empty string.
@ -308,10 +308,10 @@ It's meaningless to request "clean" data in a form with no data, but, for the
record, here's what happens with unbound forms:: record, here's what happens with unbound forms::
>>> f = ContactForm() >>> f = ContactForm()
>>> f.clean_data >>> f.cleaned_data
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: 'ContactForm' object has no attribute 'clean_data' AttributeError: 'ContactForm' object has no attribute 'cleaned_data'
Outputting forms as HTML Outputting forms as HTML
------------------------ ------------------------

View File

@ -18,7 +18,7 @@ other Form, with one additional method: save(). The save()
method updates the model instance. It also takes a commit=True parameter. method updates the model instance. It also takes a commit=True parameter.
The function django.newforms.save_instance() takes a bound form instance and a The function django.newforms.save_instance() takes a bound form instance and a
model instance and saves the form's clean_data into the instance. It also takes model instance and saves the form's cleaned_data into the instance. It also takes
a commit=True parameter. a commit=True parameter.
""" """
@ -94,7 +94,7 @@ __test__ = {'API_TESTS': """
>>> f = CategoryForm({'name': 'Entertainment', 'url': 'entertainment'}) >>> f = CategoryForm({'name': 'Entertainment', 'url': 'entertainment'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'url': u'entertainment', 'name': u'Entertainment'} {'url': u'entertainment', 'name': u'Entertainment'}
>>> obj = f.save() >>> obj = f.save()
>>> obj >>> obj
@ -105,7 +105,7 @@ True
>>> f = CategoryForm({'name': "It's a test", 'url': 'test'}) >>> f = CategoryForm({'name': "It's a test", 'url': 'test'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'url': u'test', 'name': u"It's a test"} {'url': u'test', 'name': u"It's a test"}
>>> obj = f.save() >>> obj = f.save()
>>> obj >>> obj
@ -119,7 +119,7 @@ save() on the resulting model instance.
>>> f = CategoryForm({'name': 'Third test', 'url': 'third'}) >>> f = CategoryForm({'name': 'Third test', 'url': 'third'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'url': u'third', 'name': u'Third test'} {'url': u'third', 'name': u'Third test'}
>>> obj = f.save(commit=False) >>> obj = f.save(commit=False)
>>> obj >>> obj
@ -134,10 +134,10 @@ If you call save() with invalid data, you'll get a ValueError.
>>> f = CategoryForm({'name': '', 'url': 'foo'}) >>> f = CategoryForm({'name': '', 'url': 'foo'})
>>> f.errors >>> f.errors
{'name': [u'This field is required.']} {'name': [u'This field is required.']}
>>> f.clean_data >>> f.cleaned_data
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: 'CategoryForm' object has no attribute 'clean_data' AttributeError: 'CategoryForm' object has no attribute 'cleaned_data'
>>> f.save() >>> f.save()
Traceback (most recent call last): Traceback (most recent call last):
... ...
@ -524,6 +524,6 @@ ValidationError: [u'Select a valid choice. 10 is not one of the available choice
>>> f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'}) >>> f = PhoneNumberForm({'phone': '(312) 555-1212', 'description': 'Assistance'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'phone': u'312-555-1212', 'description': u'Assistance'} {'phone': u'312-555-1212', 'description': u'Assistance'}
"""} """}

View File

@ -46,6 +46,6 @@ doesn't come back.
>>> f = DataForm({'data': 'xyzzy'}) >>> f = DataForm({'data': 'xyzzy'})
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'data': u'xyzzy'} {'data': u'xyzzy'}
""" """

View File

@ -1774,7 +1774,7 @@ True
u'' u''
>>> p.errors.as_text() >>> p.errors.as_text()
u'' u''
>>> p.clean_data >>> p.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
>>> print p['first_name'] >>> print p['first_name']
<input type="text" name="first_name" value="John" id="id_first_name" /> <input type="text" name="first_name" value="John" id="id_first_name" />
@ -1810,10 +1810,10 @@ True
{'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']} {'first_name': [u'This field is required.'], 'last_name': [u'This field is required.'], 'birthday': [u'This field is required.']}
>>> p.is_valid() >>> p.is_valid()
False False
>>> p.clean_data >>> p.cleaned_data
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: 'Person' object has no attribute 'clean_data' AttributeError: 'Person' object has no attribute 'cleaned_data'
>>> print p >>> print p
<tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="first_name" id="id_first_name" /></td></tr> <tr><th><label for="id_first_name">First name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="first_name" id="id_first_name" /></td></tr>
<tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="last_name" id="id_last_name" /></td></tr> <tr><th><label for="id_last_name">Last name:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="last_name" id="id_last_name" /></td></tr>
@ -1844,10 +1844,10 @@ False
{} {}
>>> p.is_valid() >>> p.is_valid()
False False
>>> p.clean_data >>> p.cleaned_data
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: 'Person' object has no attribute 'clean_data' AttributeError: 'Person' object has no attribute 'cleaned_data'
>>> print p >>> print p
<tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" id="id_first_name" /></td></tr> <tr><th><label for="id_first_name">First name:</label></th><td><input type="text" name="first_name" id="id_first_name" /></td></tr>
<tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" id="id_last_name" /></td></tr> <tr><th><label for="id_last_name">Last name:</label></th><td><input type="text" name="last_name" id="id_last_name" /></td></tr>
@ -1886,10 +1886,10 @@ u'<ul class="errorlist"><li>first_name<ul class="errorlist"><li>This field is re
* This field is required. * This field is required.
* birthday * birthday
* This field is required. * This field is required.
>>> p.clean_data >>> p.cleaned_data
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: 'Person' object has no attribute 'clean_data' AttributeError: 'Person' object has no attribute 'cleaned_data'
>>> p['first_name'].errors >>> p['first_name'].errors
[u'This field is required.'] [u'This field is required.']
>>> p['first_name'].errors.as_ul() >>> p['first_name'].errors.as_ul()
@ -1905,21 +1905,21 @@ u'* This field is required.'
>>> print p['birthday'] >>> print p['birthday']
<input type="text" name="birthday" id="id_birthday" /> <input type="text" name="birthday" id="id_birthday" />
clean_data will always *only* contain a key for fields defined in the 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 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, example, we pass a bunch of extra fields to the form constructor,
but clean_data contains only the form's fields. 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'} >>> data = {'first_name': u'John', 'last_name': u'Lennon', 'birthday': u'1940-10-9', 'extra1': 'hello', 'extra2': 'hello'}
>>> p = Person(data) >>> p = Person(data)
>>> p.is_valid() >>> p.is_valid()
True True
>>> p.clean_data >>> p.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
clean_data will include a key and value for *all* fields defined in the Form, 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 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 required. In this example, the data dictionary doesn't include a value for the
"nick_name" field, but clean_data includes it. For CharFields, it's set to the "nick_name" field, but cleaned_data includes it. For CharFields, it's set to the
empty string. empty string.
>>> class OptionalPersonForm(Form): >>> class OptionalPersonForm(Form):
... first_name = CharField() ... first_name = CharField()
@ -1929,7 +1929,7 @@ empty string.
>>> f = OptionalPersonForm(data) >>> f = OptionalPersonForm(data)
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'} {'nick_name': u'', 'first_name': u'John', 'last_name': u'Lennon'}
For DateFields, it's set to None. For DateFields, it's set to None.
@ -1941,7 +1941,7 @@ For DateFields, it's set to None.
>>> f = OptionalPersonForm(data) >>> f = OptionalPersonForm(data)
>>> f.is_valid() >>> f.is_valid()
True True
>>> f.clean_data >>> f.cleaned_data
{'birth_date': None, 'first_name': u'John', 'last_name': u'Lennon'} {'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. "auto_id" tells the Form to add an "id" attribute to each form element.
@ -2292,19 +2292,19 @@ returns a list of input.
>>> f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False) >>> f = SongForm({'name': 'Yesterday', 'composers': ['J']}, auto_id=False)
>>> f.errors >>> f.errors
{} {}
>>> f.clean_data >>> f.cleaned_data
{'composers': [u'J'], 'name': u'Yesterday'} {'composers': [u'J'], 'name': u'Yesterday'}
>>> f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False) >>> f = SongForm({'name': 'Yesterday', 'composers': ['J', 'P']}, auto_id=False)
>>> f.errors >>> f.errors
{} {}
>>> f.clean_data >>> f.cleaned_data
{'composers': [u'J', u'P'], 'name': u'Yesterday'} {'composers': [u'J', u'P'], 'name': u'Yesterday'}
Validation errors are HTML-escaped when output as HTML. Validation errors are HTML-escaped when output as HTML.
>>> class EscapingForm(Form): >>> class EscapingForm(Form):
... special_name = CharField() ... special_name = CharField()
... def do_clean_special_name(self): ... def clean_special_name(self):
... raise ValidationError("Something's wrong with '%s'" % self.clean_data['special_name']) ... raise ValidationError("Something's wrong with '%s'" % self.cleaned_data['special_name'])
>>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False) >>> f = EscapingForm({'special_name': "Nothing to escape"}, auto_id=False)
>>> print f >>> print f
@ -2319,17 +2319,17 @@ 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 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 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 Field.clean(), the clean_XXX() method should return the cleaned value. In the
clean_XXX() method, you have access to self.clean_data, which is a dictionary 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, 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()). including the current field (e.g., the field XXX if you're in clean_XXX()).
>>> class UserRegistration(Form): >>> class UserRegistration(Form):
... username = CharField(max_length=10) ... username = CharField(max_length=10)
... password1 = CharField(widget=PasswordInput) ... password1 = CharField(widget=PasswordInput)
... password2 = CharField(widget=PasswordInput) ... password2 = CharField(widget=PasswordInput)
... def do_clean_password2(self): ... def clean_password2(self):
... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']: ... 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.') ... raise ValidationError(u'Please make sure your passwords match.')
... return self.clean_data['password2'] ... return self.cleaned_data['password2']
>>> f = UserRegistration(auto_id=False) >>> f = UserRegistration(auto_id=False)
>>> f.errors >>> f.errors
{} {}
@ -2342,14 +2342,14 @@ including the current field (e.g., the field XXX if you're in clean_XXX()).
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False) >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
>>> f.errors >>> f.errors
{} {}
>>> f.clean_data >>> f.cleaned_data
{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'} {'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
Another way of doing multiple-field validation is by implementing the Another way of doing multiple-field validation is by implementing the
Form's clean() method. If you do this, any ValidationError raised by that 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 method will not be associated with a particular field; it will have a
special-case association with the field named '__all__'. special-case association with the field named '__all__'.
Note that in Form.clean(), you have access to self.clean_data, a dictionary of 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 all the fields/values that have *not* raised a ValidationError. Also note
Form.clean() is required to return a dictionary of all clean data. Form.clean() is required to return a dictionary of all clean data.
>>> class UserRegistration(Form): >>> class UserRegistration(Form):
@ -2357,9 +2357,9 @@ Form.clean() is required to return a dictionary of all clean data.
... password1 = CharField(widget=PasswordInput) ... password1 = CharField(widget=PasswordInput)
... password2 = CharField(widget=PasswordInput) ... password2 = CharField(widget=PasswordInput)
... def clean(self): ... def clean(self):
... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']: ... 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.') ... raise ValidationError(u'Please make sure your passwords match.')
... return self.clean_data ... return self.cleaned_data
>>> f = UserRegistration(auto_id=False) >>> f = UserRegistration(auto_id=False)
>>> f.errors >>> f.errors
{} {}
@ -2386,7 +2386,7 @@ Form.clean() is required to return a dictionary of all clean data.
>>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False) >>> f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False)
>>> f.errors >>> f.errors
{} {}
>>> f.clean_data >>> f.cleaned_data
{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'} {'username': u'adrian', 'password1': u'foo', 'password2': u'foo'}
# Dynamic construction ######################################################## # Dynamic construction ########################################################
@ -2954,7 +2954,7 @@ actual field name.
{} {}
>>> p.is_valid() >>> p.is_valid()
True True
>>> p.clean_data >>> p.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} {'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 Let's try submitting some bad data to make sure form.errors and field.errors
@ -2998,12 +2998,12 @@ of the same form.
>>> p1 = Person(data, prefix='person1') >>> p1 = Person(data, prefix='person1')
>>> p1.is_valid() >>> p1.is_valid()
True True
>>> p1.clean_data >>> p1.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
>>> p2 = Person(data, prefix='person2') >>> p2 = Person(data, prefix='person2')
>>> p2.is_valid() >>> p2.is_valid()
True True
>>> p2.clean_data >>> p2.cleaned_data
{'first_name': u'Jim', 'last_name': u'Morrison', 'birthday': datetime.date(1943, 12, 8)} {'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 By default, forms append a hyphen between the prefix and the field name, but a
@ -3029,7 +3029,7 @@ self.prefix.
>>> p = Person(data, prefix='foo') >>> p = Person(data, prefix='foo')
>>> p.is_valid() >>> p.is_valid()
True True
>>> p.clean_data >>> p.cleaned_data
{'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)} {'first_name': u'John', 'last_name': u'Lennon', 'birthday': datetime.date(1940, 10, 9)}
# Forms with NullBooleanFields ################################################ # Forms with NullBooleanFields ################################################
@ -3091,16 +3091,16 @@ is different than its data. This is handled transparently, though.
... password1 = CharField(widget=PasswordInput) ... password1 = CharField(widget=PasswordInput)
... password2 = CharField(widget=PasswordInput) ... password2 = CharField(widget=PasswordInput)
... def clean(self): ... def clean(self):
... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']: ... 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.') ... raise ValidationError(u'Please make sure your passwords match.')
... return self.clean_data ... return self.cleaned_data
>>> def my_function(method, post_data): >>> def my_function(method, post_data):
... if method == 'POST': ... if method == 'POST':
... form = UserRegistration(post_data, auto_id=False) ... form = UserRegistration(post_data, auto_id=False)
... else: ... else:
... form = UserRegistration(auto_id=False) ... form = UserRegistration(auto_id=False)
... if form.is_valid(): ... if form.is_valid():
... return 'VALID: %r' % form.clean_data ... return 'VALID: %r' % form.cleaned_data
... t = Template('<form action="" method="post">\n<table>\n{{ form }}\n</table>\n<input type="submit" />\n</form>') ... t = Template('<form action="" method="post">\n<table>\n{{ form }}\n</table>\n<input type="submit" />\n</form>')
... return t.render(Context({'form': form})) ... return t.render(Context({'form': form}))
@ -3138,9 +3138,9 @@ VALID: {'username': u'adrian', 'password1': u'secret', 'password2': u'secret'}
... password1 = CharField(widget=PasswordInput) ... password1 = CharField(widget=PasswordInput)
... password2 = CharField(widget=PasswordInput) ... password2 = CharField(widget=PasswordInput)
... def clean(self): ... def clean(self):
... if self.clean_data.get('password1') and self.clean_data.get('password2') and self.clean_data['password1'] != self.clean_data['password2']: ... 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.') ... raise ValidationError(u'Please make sure your passwords match.')
... return self.clean_data ... return self.cleaned_data
You have full flexibility in displaying form fields in a template. Just pass a 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 Form instance to the template, and use "dot" access to refer to individual
@ -3490,7 +3490,7 @@ ValidationError: [u'This field is required.']
</select> </select>
<input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr> <input type="text" name="field1_2_0" value="2007-04-25" id="id_field1_2_0" /><input type="text" name="field1_2_1" value="06:24:00" id="id_field1_2_1" /></td></tr>
>>> f.clean_data >>> f.cleaned_data
{'field1': u'some text,JP,2007-04-25 06:24:00'} {'field1': u'some text,JP,2007-04-25 06:24:00'}
################################# #################################