Ticket #5524: 5524-new-3.diff

File 5524-new-3.diff, 12.5 KB (added by Aymeric Augustin, 12 years ago)
  • docs/releases/1.4.txt

     
    854854If you are using PUT or DELETE methods in AJAX applications, please see the
    855855:ref:`instructions about using AJAX and CSRF <csrf-ajax>`.
    856856
     857`cleaned_data` dictionary kept for invalid forms
     858~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     859
     860The :attr:`~django.forms.Form.cleaned_data` dictionary is now always present
     861after form validation. When the form doesn't validate, it contains only the
     862fields that passed validation. You should test the success of the validation
     863with the :meth:`~django.forms.Form.is_valid()` method and not with the
     864presence or absence of the :attr:`~django.forms.Form.cleaned_data` attribute
     865on the form.
     866
    857867``django.core.template_loaders``
    858868~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    859869
  • docs/ref/forms/api.txt

     
    199199always cleans the input into a Unicode string. We'll cover the encoding
    200200implications later in this document.
    201201
    202 If your data does *not* validate, your ``Form`` instance will not have a
    203 ``cleaned_data`` attribute::
     202If your data does *not* validate, the ``cleaned_data`` dictionary contains
     203only the valid fields::
    204204
    205205    >>> data = {'subject': '',
    206206    ...         'message': 'Hi there',
     
    210210    >>> f.is_valid()
    211211    False
    212212    >>> f.cleaned_data
    213     Traceback (most recent call last):
    214     ...
    215     AttributeError: 'ContactForm' object has no attribute 'cleaned_data'
     213    {'cc_myself': True, 'message': u'Hi there'}
    216214
     215.. versionchanged:: 1.4
     216
     217Until Django 1.4, the ``cleaned_data`` attribute wasn't defined at all when
     218the ``Form`` didn't validate.
     219
    217220``cleaned_data`` will always *only* contain a key for fields defined in the
    218221``Form``, even if you pass extra data when you define the ``Form``. In this
    219222example, we pass a bunch of extra fields to the ``ContactForm`` constructor,
     
    232235    >>> f.cleaned_data # Doesn't contain extra_field_1, etc.
    233236    {'cc_myself': True, 'message': u'Hi there', 'sender': u'foo@example.com', 'subject': u'hello'}
    234237
    235 ``cleaned_data`` will include a key and value for *all* fields defined in the
    236 ``Form``, even if the data didn't include a value for fields that are not
    237 required. In this example, the data dictionary doesn't include a value for the
     238When the ``Form`` is valid, ``cleaned_data`` will include a key and value for
     239*all* its fields, even if the data didn't include a value for some optional
     240fields. In this example, the data dictionary doesn't include a value for the
    238241``nick_name`` field, but ``cleaned_data`` includes it, with an empty value::
    239242
    240243    >>> class OptionalPersonForm(Form):
     
    585588
    586589   Used to display HTML or access attributes for a single field of a
    587590   :class:`Form` instance.
    588    
     591
    589592   The :meth:`__unicode__` and :meth:`__str__` methods of this object displays
    590593   the HTML for this field.
    591594
  • docs/ref/forms/validation.txt

     
    360360considering aren't valid, we must remember to remove them from the
    361361``cleaned_data``.
    362362
    363 In fact, Django will currently completely wipe out the ``cleaned_data``
    364 dictionary if there are any errors in the form. However, this behavior may
    365 change in the future, so it's not a bad idea to clean up after yourself in the
    366 first place.
     363.. versionchanged:: 1.4
     364
     365Django used to remove the ``cleaned_data`` attribute entirely if there were
     366any errors in the form. Since version 1.4, ``cleaned_data`` is present even if
     367the form doesn't validate, but it contains only field values that did
     368validate.
  • django/forms/models.py

     
    497497        all_unique_checks = set()
    498498        all_date_checks = set()
    499499        for form in self.forms:
    500             if not hasattr(form, 'cleaned_data'):
     500            if not form.is_valid():
    501501                continue
    502502            exclude = form._get_validation_exclusions()
    503503            unique_checks, date_checks = form.instance._get_unique_checks(exclude=exclude)
     
    509509        for uclass, unique_check in all_unique_checks:
    510510            seen_data = set()
    511511            for form in self.forms:
    512                 # if the form doesn't have cleaned_data then we ignore it,
    513                 # it's already invalid
    514                 if not hasattr(form, "cleaned_data"):
     512                if not form.is_valid():
    515513                    continue
    516514                # get data for each field of each of unique_check
    517515                row_data = tuple([form.cleaned_data[field] for field in unique_check if field in form.cleaned_data])
    518516                if row_data and not None in row_data:
    519                     # if we've aready seen it then we have a uniqueness failure
     517                    # if we've already seen it then we have a uniqueness failure
    520518                    if row_data in seen_data:
    521519                        # poke error messages into the right places and mark
    522520                        # the form as invalid
    523521                        errors.append(self.get_unique_error_message(unique_check))
    524522                        form._errors[NON_FIELD_ERRORS] = self.error_class([self.get_form_error()])
    525                         del form.cleaned_data
    526                         break
     523                        # remove the data from the cleaned_data dict since it was invalid
     524                        for field in unique_check:
     525                            if field in form.cleaned_data:
     526                                del form.cleaned_data[field]
    527527                    # mark the data as seen
    528528                    seen_data.add(row_data)
    529529        # iterate over each of the date checks now
     
    531531            seen_data = set()
    532532            uclass, lookup, field, unique_for = date_check
    533533            for form in self.forms:
    534                 # if the form doesn't have cleaned_data then we ignore it,
    535                 # it's already invalid
    536                 if not hasattr(self, 'cleaned_data'):
     534                if not form.is_valid():
    537535                    continue
    538536                # see if we have data for both fields
    539537                if (form.cleaned_data and form.cleaned_data[field] is not None
     
    547545                    else:
    548546                        date_data = (getattr(form.cleaned_data[unique_for], lookup),)
    549547                    data = (form.cleaned_data[field],) + date_data
    550                     # if we've aready seen it then we have a uniqueness failure
     548                    # if we've already seen it then we have a uniqueness failure
    551549                    if data in seen_data:
    552550                        # poke error messages into the right places and mark
    553551                        # the form as invalid
    554552                        errors.append(self.get_date_error_message(date_check))
    555553                        form._errors[NON_FIELD_ERRORS] = self.error_class([self.get_form_error()])
    556                         del form.cleaned_data
    557                         break
     554                        # remove the data from the cleaned_data dict since it was invalid
     555                        del form.cleaned_data[field]
     556                    # mark the data as seen
    558557                    seen_data.add(data)
    559558        if errors:
    560559            raise ValidationError(errors)
  • django/forms/forms.py

     
    270270        self._clean_fields()
    271271        self._clean_form()
    272272        self._post_clean()
    273         if self._errors:
    274             del self.cleaned_data
    275273
    276274    def _clean_fields(self):
    277275        for name, field in self.fields.items():
  • django/contrib/formtools/tests/__init__.py

     
    362362
    363363        class WizardWithProcessStep(TestWizardClass):
    364364            def process_step(self, request, form, step):
    365                 that.assertTrue(hasattr(form, 'cleaned_data'))
     365                that.assertTrue(form.is_valid())
    366366                reached[0] = True
    367367
    368368        wizard = WizardWithProcessStep([WizardPageOneForm,
  • tests/modeltests/model_forms/tests.py

     
    637637        f = BaseCategoryForm({'name': '', 'slug': 'not a slug!', 'url': 'foo'})
    638638        self.assertEqual(f.errors['name'], [u'This field is required.'])
    639639        self.assertEqual(f.errors['slug'], [u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens."])
    640         with self.assertRaises(AttributeError):
    641             f.cleaned_data
     640        self.assertEqual(f.cleaned_data, {'url': u'foo'})
    642641        with self.assertRaises(ValueError):
    643642            f.save()
    644643        f = BaseCategoryForm({'name': '', 'slug': '', 'url': 'foo'})
  • tests/regressiontests/forms/tests/forms.py

     
    7979        self.assertEqual(p.errors['last_name'], [u'This field is required.'])
    8080        self.assertEqual(p.errors['birthday'], [u'This field is required.'])
    8181        self.assertFalse(p.is_valid())
    82         try:
    83             p.cleaned_data
    84             self.fail('Attempts to access cleaned_data when validation fails should fail.')
    85         except AttributeError:
    86             pass
     82        self.assertEqual(p.cleaned_data, {})
    8783        self.assertEqual(str(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>
    8884<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>
    8985<tr><th><label for="id_birthday">Birthday:</label></th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="birthday" id="id_birthday" /></td></tr>""")
     
    142138  * This field is required.
    143139* birthday
    144140  * This field is required.""")
    145         try:
    146             p.cleaned_data
    147             self.fail('Attempts to access cleaned_data when validation fails should fail.')
    148         except AttributeError:
    149             pass
     141        self.assertEqual(p.cleaned_data, {'last_name': u'Lennon'})
    150142        self.assertEqual(p['first_name'].errors, [u'This field is required.'])
    151143        self.assertEqual(p['first_name'].errors.as_ul(), u'<ul class="errorlist"><li>This field is required.</li></ul>')
    152144        self.assertEqual(p['first_name'].errors.as_text(), u'* This field is required.')
     
    16721664        form = SongForm(data, empty_permitted=False)
    16731665        self.assertFalse(form.is_valid())
    16741666        self.assertEqual(form.errors, {'name': [u'This field is required.'], 'artist': [u'This field is required.']})
    1675         try:
    1676             form.cleaned_data
    1677             self.fail('Attempts to access cleaned_data when validation fails should fail.')
    1678         except AttributeError:
    1679             pass
     1667        self.assertEqual(form.cleaned_data, {})
    16801668
    16811669        # Now let's show what happens when empty_permitted=True and the form is empty.
    16821670        form = SongForm(data, empty_permitted=True)
     
    16901678        form = SongForm(data, empty_permitted=False)
    16911679        self.assertFalse(form.is_valid())
    16921680        self.assertEqual(form.errors, {'name': [u'This field is required.']})
    1693         try:
    1694             form.cleaned_data
    1695             self.fail('Attempts to access cleaned_data when validation fails should fail.')
    1696         except AttributeError:
    1697             pass
     1681        self.assertEqual(form.cleaned_data, {'artist': u'The Doors'})
    16981682
    16991683        # If a field is not given in the data then None is returned for its data. Lets
    17001684        # make sure that when checking for empty_permitted that None is treated
Back to Top