mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #20867 -- Added the Form.add_error() method.
Refs #20199 #16986. Thanks @akaariai, @bmispelon, @mjtamlyn, @timgraham for the reviews.
This commit is contained in:
		| @@ -77,64 +77,78 @@ class ValidationError(Exception): | |||||||
|     """An error while validating data.""" |     """An error while validating data.""" | ||||||
|     def __init__(self, message, code=None, params=None): |     def __init__(self, message, code=None, params=None): | ||||||
|         """ |         """ | ||||||
|         ValidationError can be passed any object that can be printed (usually |         The `message` argument can be a single error, a list of errors, or a | ||||||
|         a string), a list of objects or a dictionary. |         dictionary that maps field names to lists of errors. What we define as | ||||||
|  |         an "error" can be either a simple string or an instance of | ||||||
|  |         ValidationError with its message attribute set, and what we define as | ||||||
|  |         list or dictionary can be an actual `list` or `dict` or an instance | ||||||
|  |         of ValidationError with its `error_list` or `error_dict` attribute set. | ||||||
|         """ |         """ | ||||||
|  |         if isinstance(message, ValidationError): | ||||||
|  |             if hasattr(message, 'error_dict'): | ||||||
|  |                 message = message.error_dict | ||||||
|  |             elif not hasattr(message, 'message'): | ||||||
|  |                 message = message.error_list | ||||||
|  |             else: | ||||||
|  |                 message, code, params = message.message, message.code, message.params | ||||||
|  |  | ||||||
|         if isinstance(message, dict): |         if isinstance(message, dict): | ||||||
|             self.error_dict = message |             self.error_dict = {} | ||||||
|  |             for field, messages in message.items(): | ||||||
|  |                 if not isinstance(messages, ValidationError): | ||||||
|  |                     messages = ValidationError(messages) | ||||||
|  |                 self.error_dict[field] = messages.error_list | ||||||
|  |  | ||||||
|         elif isinstance(message, list): |         elif isinstance(message, list): | ||||||
|             self.error_list = message |             self.error_list = [] | ||||||
|  |             for message in message: | ||||||
|  |                 # Normalize plain strings to instances of ValidationError. | ||||||
|  |                 if not isinstance(message, ValidationError): | ||||||
|  |                     message = ValidationError(message) | ||||||
|  |                 self.error_list.extend(message.error_list) | ||||||
|  |  | ||||||
|         else: |         else: | ||||||
|  |             self.message = message | ||||||
|             self.code = code |             self.code = code | ||||||
|             self.params = params |             self.params = params | ||||||
|             self.message = message |  | ||||||
|             self.error_list = [self] |             self.error_list = [self] | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def message_dict(self): |     def message_dict(self): | ||||||
|         message_dict = {} |         return dict(self) | ||||||
|         for field, messages in self.error_dict.items(): |  | ||||||
|             message_dict[field] = [] |  | ||||||
|             for message in messages: |  | ||||||
|                 if isinstance(message, ValidationError): |  | ||||||
|                     message_dict[field].extend(message.messages) |  | ||||||
|                 else: |  | ||||||
|                     message_dict[field].append(force_text(message)) |  | ||||||
|         return message_dict |  | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def messages(self): |     def messages(self): | ||||||
|         if hasattr(self, 'error_dict'): |         if hasattr(self, 'error_dict'): | ||||||
|             message_list = reduce(operator.add, self.error_dict.values()) |             return reduce(operator.add, dict(self).values()) | ||||||
|         else: |         return list(self) | ||||||
|             message_list = self.error_list |  | ||||||
|  |  | ||||||
|         messages = [] |  | ||||||
|         for message in message_list: |  | ||||||
|             if isinstance(message, ValidationError): |  | ||||||
|                 params = message.params |  | ||||||
|                 message = message.message |  | ||||||
|                 if params: |  | ||||||
|                     message %= params |  | ||||||
|             message = force_text(message) |  | ||||||
|             messages.append(message) |  | ||||||
|         return messages |  | ||||||
|  |  | ||||||
|     def __str__(self): |  | ||||||
|         if hasattr(self, 'error_dict'): |  | ||||||
|             return repr(self.message_dict) |  | ||||||
|         return repr(self.messages) |  | ||||||
|  |  | ||||||
|     def __repr__(self): |  | ||||||
|         return 'ValidationError(%s)' % self |  | ||||||
|  |  | ||||||
|     def update_error_dict(self, error_dict): |     def update_error_dict(self, error_dict): | ||||||
|         if hasattr(self, 'error_dict'): |         if hasattr(self, 'error_dict'): | ||||||
|             if error_dict: |             if error_dict: | ||||||
|                 for k, v in self.error_dict.items(): |                 for field, errors in self.error_dict.items(): | ||||||
|                     error_dict.setdefault(k, []).extend(v) |                     error_dict.setdefault(field, []).extend(errors) | ||||||
|             else: |             else: | ||||||
|                 error_dict = self.error_dict |                 error_dict = self.error_dict | ||||||
|         else: |         else: | ||||||
|             error_dict[NON_FIELD_ERRORS] = self.error_list |             error_dict[NON_FIELD_ERRORS] = self.error_list | ||||||
|         return error_dict |         return error_dict | ||||||
|  |  | ||||||
|  |     def __iter__(self): | ||||||
|  |         if hasattr(self, 'error_dict'): | ||||||
|  |             for field, errors in self.error_dict.items(): | ||||||
|  |                 yield field, list(ValidationError(errors)) | ||||||
|  |         else: | ||||||
|  |             for error in self.error_list: | ||||||
|  |                 message = error.message | ||||||
|  |                 if error.params: | ||||||
|  |                     message %= error.params | ||||||
|  |                 yield force_text(message) | ||||||
|  |  | ||||||
|  |     def __str__(self): | ||||||
|  |         if hasattr(self, 'error_dict'): | ||||||
|  |             return repr(dict(self)) | ||||||
|  |         return repr(list(self)) | ||||||
|  |  | ||||||
|  |     def __repr__(self): | ||||||
|  |         return 'ValidationError(%s)' % self | ||||||
|   | |||||||
| @@ -987,7 +987,7 @@ class Model(six.with_metaclass(ModelBase)): | |||||||
|  |  | ||||||
|     def clean_fields(self, exclude=None): |     def clean_fields(self, exclude=None): | ||||||
|         """ |         """ | ||||||
|         Cleans all fields and raises a ValidationError containing message_dict |         Cleans all fields and raises a ValidationError containing a dict | ||||||
|         of all validation errors if any occur. |         of all validation errors if any occur. | ||||||
|         """ |         """ | ||||||
|         if exclude is None: |         if exclude is None: | ||||||
|   | |||||||
| @@ -290,6 +290,51 @@ class BaseForm(object): | |||||||
|         prefix = self.add_prefix(fieldname) |         prefix = self.add_prefix(fieldname) | ||||||
|         return field.widget.value_from_datadict(self.data, self.files, prefix) |         return field.widget.value_from_datadict(self.data, self.files, prefix) | ||||||
|  |  | ||||||
|  |     def add_error(self, field, error): | ||||||
|  |         """ | ||||||
|  |         Update the content of `self._errors`. | ||||||
|  |  | ||||||
|  |         The `field` argument is the name of the field to which the errors | ||||||
|  |         should be added. If its value is None the errors will be treated as | ||||||
|  |         NON_FIELD_ERRORS. | ||||||
|  |  | ||||||
|  |         The `error` argument can be a single error, a list of errors, or a | ||||||
|  |         dictionary that maps field names to lists of errors. What we define as | ||||||
|  |         an "error" can be either a simple string or an instance of | ||||||
|  |         ValidationError with its message attribute set and what we define as | ||||||
|  |         list or dictionary can be an actual `list` or `dict` or an instance | ||||||
|  |         of ValidationError with its `error_list` or `error_dict` attribute set. | ||||||
|  |  | ||||||
|  |         If `error` is a dictionary, the `field` argument *must* be None and | ||||||
|  |         errors will be added to the fields that correspond to the keys of the | ||||||
|  |         dictionary. | ||||||
|  |         """ | ||||||
|  |         if not isinstance(error, ValidationError): | ||||||
|  |             # Normalize to ValidationError and let its constructor | ||||||
|  |             # do the hard work of making sense of the input. | ||||||
|  |             error = ValidationError(error) | ||||||
|  |  | ||||||
|  |         if hasattr(error, 'error_dict'): | ||||||
|  |             if field is not None: | ||||||
|  |                 raise TypeError( | ||||||
|  |                     "The argument `field` must be `None` when the `error` " | ||||||
|  |                     "argument contains errors for multiple fields." | ||||||
|  |                 ) | ||||||
|  |             else: | ||||||
|  |                 error = dict(error) | ||||||
|  |         else: | ||||||
|  |             error = {field or NON_FIELD_ERRORS: list(error)} | ||||||
|  |  | ||||||
|  |         for field, error_list in error.items(): | ||||||
|  |             if field not in self.errors: | ||||||
|  |                 if field != NON_FIELD_ERRORS and field not in self.fields: | ||||||
|  |                     raise ValueError( | ||||||
|  |                         "'%s' has no field named '%s'." % (self.__class__.__name__, field)) | ||||||
|  |                 self._errors[field] = self.error_class() | ||||||
|  |             self._errors[field].extend(error_list) | ||||||
|  |             if field in self.cleaned_data: | ||||||
|  |                 del self.cleaned_data[field] | ||||||
|  |  | ||||||
|     def full_clean(self): |     def full_clean(self): | ||||||
|         """ |         """ | ||||||
|         Cleans all of self.data and populates self._errors and |         Cleans all of self.data and populates self._errors and | ||||||
| @@ -303,6 +348,7 @@ class BaseForm(object): | |||||||
|         # changed from the initial data, short circuit any validation. |         # changed from the initial data, short circuit any validation. | ||||||
|         if self.empty_permitted and not self.has_changed(): |         if self.empty_permitted and not self.has_changed(): | ||||||
|             return |             return | ||||||
|  |  | ||||||
|         self._clean_fields() |         self._clean_fields() | ||||||
|         self._clean_form() |         self._clean_form() | ||||||
|         self._post_clean() |         self._post_clean() | ||||||
| @@ -324,15 +370,13 @@ class BaseForm(object): | |||||||
|                     value = getattr(self, 'clean_%s' % name)() |                     value = getattr(self, 'clean_%s' % name)() | ||||||
|                     self.cleaned_data[name] = value |                     self.cleaned_data[name] = value | ||||||
|             except ValidationError as e: |             except ValidationError as e: | ||||||
|                 self._errors[name] = self.error_class(e.messages) |                 self.add_error(name, e) | ||||||
|                 if name in self.cleaned_data: |  | ||||||
|                     del self.cleaned_data[name] |  | ||||||
|  |  | ||||||
|     def _clean_form(self): |     def _clean_form(self): | ||||||
|         try: |         try: | ||||||
|             cleaned_data = self.clean() |             cleaned_data = self.clean() | ||||||
|         except ValidationError as e: |         except ValidationError as e: | ||||||
|             self._errors[NON_FIELD_ERRORS] = self.error_class(e.messages) |             self.add_error(None, e) | ||||||
|         else: |         else: | ||||||
|             if cleaned_data is not None: |             if cleaned_data is not None: | ||||||
|                 self.cleaned_data = cleaned_data |                 self.cleaned_data = cleaned_data | ||||||
|   | |||||||
| @@ -326,27 +326,6 @@ class BaseModelForm(BaseForm): | |||||||
|         super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data, |         super(BaseModelForm, self).__init__(data, files, auto_id, prefix, object_data, | ||||||
|                                             error_class, label_suffix, empty_permitted) |                                             error_class, label_suffix, empty_permitted) | ||||||
|  |  | ||||||
|     def _update_errors(self, errors): |  | ||||||
|         for field, messages in errors.error_dict.items(): |  | ||||||
|             if field not in self.fields: |  | ||||||
|                 continue |  | ||||||
|             field = self.fields[field] |  | ||||||
|             for message in messages: |  | ||||||
|                 if isinstance(message, ValidationError): |  | ||||||
|                     if message.code in field.error_messages: |  | ||||||
|                         message.message = field.error_messages[message.code] |  | ||||||
|  |  | ||||||
|         message_dict = errors.message_dict |  | ||||||
|         for k, v in message_dict.items(): |  | ||||||
|             if k != NON_FIELD_ERRORS: |  | ||||||
|                 self._errors.setdefault(k, self.error_class()).extend(v) |  | ||||||
|                 # Remove the data from the cleaned_data dict since it was invalid |  | ||||||
|                 if k in self.cleaned_data: |  | ||||||
|                     del self.cleaned_data[k] |  | ||||||
|         if NON_FIELD_ERRORS in message_dict: |  | ||||||
|             messages = message_dict[NON_FIELD_ERRORS] |  | ||||||
|             self._errors.setdefault(NON_FIELD_ERRORS, self.error_class()).extend(messages) |  | ||||||
|  |  | ||||||
|     def _get_validation_exclusions(self): |     def _get_validation_exclusions(self): | ||||||
|         """ |         """ | ||||||
|         For backwards-compatibility, several types of fields need to be |         For backwards-compatibility, several types of fields need to be | ||||||
| @@ -393,6 +372,20 @@ class BaseModelForm(BaseForm): | |||||||
|         self._validate_unique = True |         self._validate_unique = True | ||||||
|         return self.cleaned_data |         return self.cleaned_data | ||||||
|  |  | ||||||
|  |     def _update_errors(self, errors): | ||||||
|  |         # Override any validation error messages defined at the model level | ||||||
|  |         # with those defined on the form fields. | ||||||
|  |         for field, messages in errors.error_dict.items(): | ||||||
|  |             if field not in self.fields: | ||||||
|  |                 continue | ||||||
|  |             field = self.fields[field] | ||||||
|  |             for message in messages: | ||||||
|  |                 if (isinstance(message, ValidationError) and | ||||||
|  |                         message.code in field.error_messages): | ||||||
|  |                     message.message = field.error_messages[message.code] | ||||||
|  |  | ||||||
|  |         self.add_error(None, errors) | ||||||
|  |  | ||||||
|     def _post_clean(self): |     def _post_clean(self): | ||||||
|         opts = self._meta |         opts = self._meta | ||||||
|         # Update the model instance with self.cleaned_data. |         # Update the model instance with self.cleaned_data. | ||||||
| @@ -407,13 +400,12 @@ class BaseModelForm(BaseForm): | |||||||
|         # object being referred to may not yet fully exist (#12749). |         # object being referred to may not yet fully exist (#12749). | ||||||
|         # However, these fields *must* be included in uniqueness checks, |         # However, these fields *must* be included in uniqueness checks, | ||||||
|         # so this can't be part of _get_validation_exclusions(). |         # so this can't be part of _get_validation_exclusions(). | ||||||
|         for f_name, field in self.fields.items(): |         for name, field in self.fields.items(): | ||||||
|             if isinstance(field, InlineForeignKeyField): |             if isinstance(field, InlineForeignKeyField): | ||||||
|                 exclude.append(f_name) |                 exclude.append(name) | ||||||
|  |  | ||||||
|         try: |         try: | ||||||
|             self.instance.full_clean(exclude=exclude, |             self.instance.full_clean(exclude=exclude, validate_unique=False) | ||||||
|                 validate_unique=False) |  | ||||||
|         except ValidationError as e: |         except ValidationError as e: | ||||||
|             self._update_errors(e) |             self._update_errors(e) | ||||||
|  |  | ||||||
| @@ -695,6 +687,7 @@ class BaseModelFormSet(BaseFormSet): | |||||||
|                         del form.cleaned_data[field] |                         del form.cleaned_data[field] | ||||||
|                     # mark the data as seen |                     # mark the data as seen | ||||||
|                     seen_data.add(data) |                     seen_data.add(data) | ||||||
|  |  | ||||||
|         if errors: |         if errors: | ||||||
|             raise ValidationError(errors) |             raise ValidationError(errors) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -117,6 +117,26 @@ The validation routines will only get called once, regardless of how many times | |||||||
| you access :attr:`~Form.errors` or call :meth:`~Form.is_valid`. This means that | you access :attr:`~Form.errors` or call :meth:`~Form.is_valid`. This means that | ||||||
| if validation has side effects, those side effects will only be triggered once. | if validation has side effects, those side effects will only be triggered once. | ||||||
|  |  | ||||||
|  | .. method:: Form.add_error(field, error) | ||||||
|  |  | ||||||
|  | .. versionadded:: 1.7 | ||||||
|  |  | ||||||
|  | This method allows adding errors to specific fields from within the | ||||||
|  | ``Form.clean()`` method, or from outside the form altogether; for instance | ||||||
|  | from a view. This is a better alternative to fiddling directly with | ||||||
|  | ``Form._errors`` as described in :ref:`modifying-field-errors`. | ||||||
|  |  | ||||||
|  | The ``field`` argument is the name of the field to which the errors | ||||||
|  | should be added. If its value is ``None`` the error will be treated as | ||||||
|  | a non-field error as returned by ``Form.non_field_errors()``. | ||||||
|  |  | ||||||
|  | The ``error`` argument can be a simple string, or preferably an instance of | ||||||
|  | ``ValidationError``. See :ref:`raising-validation-error` for best practices | ||||||
|  | when defining form errors. | ||||||
|  |  | ||||||
|  | Note that ``Form.add_error()`` automatically removes the relevant field from | ||||||
|  | ``cleaned_data``. | ||||||
|  |  | ||||||
| Behavior of unbound forms | Behavior of unbound forms | ||||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~ | ~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -464,3 +464,31 @@ Secondly, once we have decided that the combined data in the two fields we are | |||||||
| considering aren't valid, we must remember to remove them from the | considering aren't valid, we must remember to remove them from the | ||||||
| ``cleaned_data``. `cleaned_data`` is present even if the form doesn't | ``cleaned_data``. `cleaned_data`` is present even if the form doesn't | ||||||
| validate, but it contains only field values that did validate. | validate, but it contains only field values that did validate. | ||||||
|  |  | ||||||
|  | .. versionchanged:: 1.7 | ||||||
|  |  | ||||||
|  | In lieu of manipulating ``_errors`` directly, it's now possible to add errors | ||||||
|  | to specific fields with :meth:`django.forms.Form.add_error()`:: | ||||||
|  |  | ||||||
|  |     from django import forms | ||||||
|  |  | ||||||
|  |     class ContactForm(forms.Form): | ||||||
|  |         # Everything as before. | ||||||
|  |         ... | ||||||
|  |  | ||||||
|  |         def clean(self): | ||||||
|  |             cleaned_data = super(ContactForm, self).clean() | ||||||
|  |             cc_myself = cleaned_data.get("cc_myself") | ||||||
|  |             subject = cleaned_data.get("subject") | ||||||
|  |  | ||||||
|  |             if cc_myself and subject and "help" not in subject: | ||||||
|  |                 msg = u"Must put 'help' in subject when cc'ing yourself." | ||||||
|  |                 self.add_error('cc_myself', msg) | ||||||
|  |                 self.add_error('subject', msg) | ||||||
|  |  | ||||||
|  | The second argument of ``add_error()`` can be a simple string, or preferably | ||||||
|  | an instance of ``ValidationError``. See :ref:`raising-validation-error` for | ||||||
|  | more details. | ||||||
|  |  | ||||||
|  | Unlike the ``_errors`` approach, ``add_error()` automatically removes the field | ||||||
|  | from ``cleaned_data``. | ||||||
|   | |||||||
| @@ -350,6 +350,9 @@ Forms | |||||||
| * It's now possible to opt-out from a ``Form`` field declared in a parent class | * It's now possible to opt-out from a ``Form`` field declared in a parent class | ||||||
|   by shadowing it with a non-``Field`` value. |   by shadowing it with a non-``Field`` value. | ||||||
|  |  | ||||||
|  | * The new :meth:`~django.forms.Form.add_error()` method allows adding errors | ||||||
|  |   to specific form fields. | ||||||
|  |  | ||||||
| Internationalization | Internationalization | ||||||
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -657,25 +657,49 @@ class FormsTestCase(TestCase): | |||||||
|         self.assertEqual(f.cleaned_data['password2'], 'foo') |         self.assertEqual(f.cleaned_data['password2'], '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. Usually ValidationError raised by that method | ||||||
|         # method will not be associated with a particular field; it will have a |         # will not be associated with a particular field and will have a | ||||||
|         # special-case association with the field named '__all__'. |         # special-case association with the field named '__all__'. It's | ||||||
|         # Note that in Form.clean(), you have access to self.cleaned_data, a dictionary of |         # possible to associate the errors to particular field with the | ||||||
|         # all the fields/values that have *not* raised a ValidationError. Also note |         # Form.add_error() method or by passing a dictionary that maps each | ||||||
|         # Form.clean() is required to return a dictionary of all clean data. |         # field to one or more errors. | ||||||
|  |         # | ||||||
|  |         # Note that in Form.clean(), you have access to self.cleaned_data, a | ||||||
|  |         # dictionary of all the fields/values that have *not* raised a | ||||||
|  |         # ValidationError. Also note Form.clean() is required to return a | ||||||
|  |         # dictionary of all clean data. | ||||||
|         class UserRegistration(Form): |         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 clean(self): |             def clean(self): | ||||||
|  |                 # Test raising a ValidationError as NON_FIELD_ERRORS. | ||||||
|                 if self.cleaned_data.get('password1') and self.cleaned_data.get('password2') and self.cleaned_data['password1'] != self.cleaned_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('Please make sure your passwords match.') |                     raise ValidationError('Please make sure your passwords match.') | ||||||
|  |  | ||||||
|  |                 # Test raising ValidationError that targets multiple fields. | ||||||
|  |                 errors = {} | ||||||
|  |                 if self.cleaned_data.get('password1') == 'FORBIDDEN_VALUE': | ||||||
|  |                     errors['password1'] = 'Forbidden value.' | ||||||
|  |                 if self.cleaned_data.get('password2') == 'FORBIDDEN_VALUE': | ||||||
|  |                     errors['password2'] = ['Forbidden value.'] | ||||||
|  |                 if errors: | ||||||
|  |                     raise ValidationError(errors) | ||||||
|  |  | ||||||
|  |                 # Test Form.add_error() | ||||||
|  |                 if self.cleaned_data.get('password1') == 'FORBIDDEN_VALUE2': | ||||||
|  |                     self.add_error(None, 'Non-field error 1.') | ||||||
|  |                     self.add_error('password1', 'Forbidden value 2.') | ||||||
|  |                 if self.cleaned_data.get('password2') == 'FORBIDDEN_VALUE2': | ||||||
|  |                     self.add_error('password2', 'Forbidden value 2.') | ||||||
|  |                     raise ValidationError('Non-field error 2.') | ||||||
|  |  | ||||||
|                 return self.cleaned_data |                 return self.cleaned_data | ||||||
|  |  | ||||||
|         f = UserRegistration(auto_id=False) |         f = UserRegistration(auto_id=False) | ||||||
|         self.assertEqual(f.errors, {}) |         self.assertEqual(f.errors, {}) | ||||||
|  |  | ||||||
|         f = UserRegistration({}, auto_id=False) |         f = UserRegistration({}, auto_id=False) | ||||||
|         self.assertHTMLEqual(f.as_table(), """<tr><th>Username:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="username" maxlength="10" /></td></tr> |         self.assertHTMLEqual(f.as_table(), """<tr><th>Username:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="username" maxlength="10" /></td></tr> | ||||||
| <tr><th>Password1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password1" /></td></tr> | <tr><th>Password1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="password" name="password1" /></td></tr> | ||||||
| @@ -683,6 +707,7 @@ class FormsTestCase(TestCase): | |||||||
|         self.assertEqual(f.errors['username'], ['This field is required.']) |         self.assertEqual(f.errors['username'], ['This field is required.']) | ||||||
|         self.assertEqual(f.errors['password1'], ['This field is required.']) |         self.assertEqual(f.errors['password1'], ['This field is required.']) | ||||||
|         self.assertEqual(f.errors['password2'], ['This field is required.']) |         self.assertEqual(f.errors['password2'], ['This field is required.']) | ||||||
|  |  | ||||||
|         f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False) |         f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'bar'}, auto_id=False) | ||||||
|         self.assertEqual(f.errors['__all__'], ['Please make sure your passwords match.']) |         self.assertEqual(f.errors['__all__'], ['Please make sure your passwords match.']) | ||||||
|         self.assertHTMLEqual(f.as_table(), """<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr> |         self.assertHTMLEqual(f.as_table(), """<tr><td colspan="2"><ul class="errorlist"><li>Please make sure your passwords match.</li></ul></td></tr> | ||||||
| @@ -693,12 +718,25 @@ class FormsTestCase(TestCase): | |||||||
| <li>Username: <input type="text" name="username" value="adrian" maxlength="10" /></li> | <li>Username: <input type="text" name="username" value="adrian" maxlength="10" /></li> | ||||||
| <li>Password1: <input type="password" name="password1" /></li> | <li>Password1: <input type="password" name="password1" /></li> | ||||||
| <li>Password2: <input type="password" name="password2" /></li>""") | <li>Password2: <input type="password" name="password2" /></li>""") | ||||||
|  |  | ||||||
|         f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False) |         f = UserRegistration({'username': 'adrian', 'password1': 'foo', 'password2': 'foo'}, auto_id=False) | ||||||
|         self.assertEqual(f.errors, {}) |         self.assertEqual(f.errors, {}) | ||||||
|         self.assertEqual(f.cleaned_data['username'], 'adrian') |         self.assertEqual(f.cleaned_data['username'], 'adrian') | ||||||
|         self.assertEqual(f.cleaned_data['password1'], 'foo') |         self.assertEqual(f.cleaned_data['password1'], 'foo') | ||||||
|         self.assertEqual(f.cleaned_data['password2'], 'foo') |         self.assertEqual(f.cleaned_data['password2'], 'foo') | ||||||
|  |  | ||||||
|  |         f = UserRegistration({'username': 'adrian', 'password1': 'FORBIDDEN_VALUE', 'password2': 'FORBIDDEN_VALUE'}, auto_id=False) | ||||||
|  |         self.assertEqual(f.errors['password1'], ['Forbidden value.']) | ||||||
|  |         self.assertEqual(f.errors['password2'], ['Forbidden value.']) | ||||||
|  |  | ||||||
|  |         f = UserRegistration({'username': 'adrian', 'password1': 'FORBIDDEN_VALUE2', 'password2': 'FORBIDDEN_VALUE2'}, auto_id=False) | ||||||
|  |         self.assertEqual(f.errors['__all__'], ['Non-field error 1.', 'Non-field error 2.']) | ||||||
|  |         self.assertEqual(f.errors['password1'], ['Forbidden value 2.']) | ||||||
|  |         self.assertEqual(f.errors['password2'], ['Forbidden value 2.']) | ||||||
|  |  | ||||||
|  |         with six.assertRaisesRegex(self, ValueError, "has no field named"): | ||||||
|  |             f.add_error('missing_field', 'Some error.') | ||||||
|  |  | ||||||
|     def test_dynamic_construction(self): |     def test_dynamic_construction(self): | ||||||
|         # It's possible to construct a Form dynamically by adding to the self.fields |         # It's possible to construct a Form dynamically by adding to the self.fields | ||||||
|         # dictionary in __init__(). Don't forget to call Form.__init__() within the |         # dictionary in __init__(). Don't forget to call Form.__init__() within the | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user