Django

Code

Ticket #6652: allow_clean_to_specify_the_wrong_field-updated-tests-docs.diff

File allow_clean_to_specify_the_wrong_field-updated-tests-docs.diff, 8.3 kB (added by mrts, 5 months ago)

Appends errors from clean() to original errors.

  • django/newforms/util.py

    old new  
    5050        return repr([force_unicode(e) for e in self]) 
    5151 
    5252class ValidationError(Exception): 
    53     def __init__(self, message): 
     53    def __init__(self, message, field_name=None): 
    5454        """ 
    5555        ValidationError can be passed any object that can be printed (usually 
    5656        a string) or a list of objects. 
    5757        """ 
     58        self.field_name = field_name 
    5859        if isinstance(message, list): 
    5960            self.messages = ErrorList([smart_unicode(msg) for msg in message]) 
    6061        else: 
  • django/newforms/forms.py

    old new  
    215215        try: 
    216216            self.cleaned_data = self.clean() 
    217217        except ValidationError, e: 
    218             self._errors[NON_FIELD_ERRORS] = e.messages 
     218            name = e.field_name or NON_FIELD_ERRORS 
     219            if e.field_name and name in self._errors: 
     220                self._errors[name] = ErrorList(self._errors[name] + e.messages) 
     221            else: 
     222                self._errors[name] = e.messages 
    219223        if self._errors: 
    220224            delattr(self, 'cleaned_data') 
    221225 
  • tests/regressiontests/forms/forms.py

    old new  
    611611 
    612612Another way of doing multiple-field validation is by implementing the 
    613613Form's clean() method. If you do this, any ValidationError raised by that 
    614 method will not be associated with a particular field; it will have a 
    615 special-case association with the field named '__all__'. 
     614method either will not be associated with a particular field 
     615and will have a special-case association with the field named '__all__';  
     616or if you specify the invalid field explicitly by passing the 'field_name' 
     617parameter to the error constructor, it will be associated with the field in 
     618similar manner to clean_XXX(). 
    616619Note that in Form.clean(), you have access to self.cleaned_data, a dictionary of 
    617620all the fields/values that have *not* raised a ValidationError. Also note 
    618621Form.clean() is required to return a dictionary of all clean data. 
     
    653656>>> f.cleaned_data 
    654657{'username': u'adrian', 'password1': u'foo', 'password2': u'foo'} 
    655658 
     659The following is a somewhat contrived example that tests specifying the 
     660invalid field in clean(). Note that default values in self.cleaned_data.get() 
     661are neccessary to test if errors are appended correctly to base field errors. 
     662 
     663>>> class EmailRegistration(Form): 
     664...    username = CharField(max_length=10) 
     665...    email1 = EmailField() 
     666...    email2 = EmailField() 
     667...    def clean(self): 
     668...        email1 = self.cleaned_data.get('email1', 'foo') 
     669...        email2 = self.cleaned_data.get('email2', 'bar') 
     670...        if email1 != email2: 
     671...            raise ValidationError(u'Please make sure the email addresses match.', field_name = 'email2') 
     672...        return self.cleaned_data 
     673...  
     674>>> f = EmailRegistration(auto_id=False) 
     675>>> f.errors 
     676{} 
     677>>> f = EmailRegistration({}, auto_id=False) 
     678>>> f.errors 
     679{'username': [u'This field is required.'], 'email2': [u'This field is required.', u'Please make sure the email addresses match.'], 'email1': [u'This field is required.']} 
     680>>> print f.as_ul() 
     681<li><ul class="errorlist"><li>This field is required.</li></ul>Username: <input type="text" name="username" maxlength="10" /></li> 
     682<li><ul class="errorlist"><li>This field is required.</li></ul>Email1: <input type="text" name="email1" /></li> 
     683<li><ul class="errorlist"><li>This field is required.</li><li>Please make sure the email addresses match.</li></ul>Email2: <input type="text" name="email2" /></li> 
     684>>> print f.as_table() 
     685<tr><th>Username:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="username" maxlength="10" /></td></tr> 
     686<tr><th>Email1:</th><td><ul class="errorlist"><li>This field is required.</li></ul><input type="text" name="email1" /></td></tr> 
     687<tr><th>Email2:</th><td><ul class="errorlist"><li>This field is required.</li><li>Please make sure the email addresses match.</li></ul><input type="text" name="email2" /></td></tr> 
     688>>> f = EmailRegistration({'username': 'adrian', 'email1': 'foo@foo.com', 'email2': 'bar'}, auto_id=False) 
     689>>> f.errors 
     690{'email2': [u'Enter a valid e-mail address.', u'Please make sure the email addresses match.']} 
     691>>> f.as_ul() 
     692u'<li>Username: <input type="text" name="username" value="adrian" maxlength="10" /></li>\n<li>Email1: <input type="text" name="email1" value="foo@foo.com" /></li>\n<li><ul class="errorlist"><li>Enter a valid e-mail address.</li><li>Please make sure the email addresses match.</li></ul>Email2: <input type="text" name="email2" value="bar" /></li>' 
     693>>> f.as_table() 
     694u'<tr><th>Username:</th><td><input type="text" name="username" value="adrian" maxlength="10" /></td></tr>\n<tr><th>Email1:</th><td><input type="text" name="email1" value="foo@foo.com" /></td></tr>\n<tr><th>Email2:</th><td><ul class="errorlist"><li>Enter a valid e-mail address.</li><li>Please make sure the email addresses match.</li></ul><input type="text" name="email2" value="bar" /></td></tr>' 
     695>>> f = EmailRegistration({'username': 'adrian', 'email1': 'foo@foo.com', 'email2': 'bar@bar.com'}, auto_id=False) 
     696>>> f.errors 
     697{'email2': [u'Please make sure the email addresses match.']} 
     698>>> f.as_ul() 
     699u'<li>Username: <input type="text" name="username" value="adrian" maxlength="10" /></li>\n<li>Email1: <input type="text" name="email1" value="foo@foo.com" /></li>\n<li><ul class="errorlist"><li>Please make sure the email addresses match.</li></ul>Email2: <input type="text" name="email2" value="bar@bar.com" /></li>' 
     700>>> f.as_table() 
     701u'<tr><th>Username:</th><td><input type="text" name="username" value="adrian" maxlength="10" /></td></tr>\n<tr><th>Email1:</th><td><input type="text" name="email1" value="foo@foo.com" /></td></tr>\n<tr><th>Email2:</th><td><ul class="errorlist"><li>Please make sure the email addresses match.</li></ul><input type="text" name="email2" value="bar@bar.com" /></td></tr>' 
     702>>> f = EmailRegistration({'username': 'adrian', 'email1': 'foo@foo.com', 'email2': 'foo@foo.com'}, auto_id=False) 
     703>>> f.errors 
     704{} 
     705>>> f.as_ul() 
     706u'<li>Username: <input type="text" name="username" value="adrian" maxlength="10" /></li>\n<li>Email1: <input type="text" name="email1" value="foo@foo.com" /></li>\n<li>Email2: <input type="text" name="email2" value="foo@foo.com" /></li>' 
     707>>> f.as_table() 
     708u'<tr><th>Username:</th><td><input type="text" name="username" value="adrian" maxlength="10" /></td></tr>\n<tr><th>Email1:</th><td><input type="text" name="email1" value="foo@foo.com" /></td></tr>\n<tr><th>Email2:</th><td><input type="text" name="email2" value="foo@foo.com" /></td></tr>' 
     709>>> f.cleaned_data 
     710{'username': u'adrian', 'email2': u'foo@foo.com', 'email1': u'foo@foo.com'} 
     711 
    656712# Dynamic construction ######################################################## 
    657713 
    658714It's possible to construct a Form dynamically by adding to the self.fields 
  • docs/newforms.txt

    old new  
    15891589      cleaned data if you override this method (by default, ``Form.clean()`` 
    15901590      just returns ``self.cleaned_data``). 
    15911591 
    1592       Note that any errors raised by your ``Form.clean()`` override will not 
    1593       be associated with any field in particular. They go into a special 
     1592      Note that by default any errors raised by your ``Form.clean()`` override 
     1593      will not be associated with any field in particular. They go into a special 
    15941594      "field" (called ``__all__``), which you can access via the 
    1595       ``non_field_errors()`` method if you need to. 
     1595      ``non_field_errors()`` method if you need to. However, if you want to 
     1596      explicitly associate the error with a particular field, you can do so 
     1597      by passing the ``field_name`` parameter to the ``ValidationError`` 
     1598      constructor. 
    15961599 
    15971600These methods are run in the order given above, one field at a time.  That is, 
    15981601for each field in the form (in the order they are declared in the form