[Apologies if this appears twice. I think Google ate my homework the first time.]
On Mon, 2007-05-21 at 14:00 -0500, Tim Chase wrote: > > What is the "general way" to add your own validation to forms under > > the newforms framework? > > > > Subclassing and adding in your clean_* methods? Using decorators or > > the such around existing validation? Adding your own custom Field > > objects and setting their "clean" methods? > > My understanding (easily wrong, and appreciating correction if > so) is that they are divergent concepts, each of which serves its > own purpose. [...] > Perhaps > one of the framework gurus could shed light on "the way it should > be done"... Tim's explanation is mostly on the money. Since I have a "framework guru" T-shirt around here somewhere (actually, I don't -- I want to get a Django T-shirt one day), here's my understanding. There are three types of cleaning methods that are run during form processing. These are all executed when you access Form.errors or call call Form.full_clean() explicitly (or Form.is_valid(), which accesses Form.errors). Any cleaning method can raise ValidationError if there is a problem with the data it is processing, passing the relevant error message to the ValidationError's constructor. If no ValidationError is raised, the method should return a Python object for the cleaned (normalised) data. The three types of methods are: (1) The clean() method on a Field subclass. This is responsible for cleaning the data in a way that is generic for that type of field. For example, a FloatField will turn the data into a Python float or raise a ValidationError. (2) The clean_fieldname() method -- where "fieldname" is replaced with the name of the form field attribute. This method does any cleaning that is specific to that particular attribute, unrelated to the type of field that it is. In Matt's original problem, clean_username() would be the right place to do any uniqueness validation. You don't need a specific Username field -- it's just a CharField, really -- but you want a formfield-specific piece of validation and, possibly, cleaning. (3) The Form subclass's clean() method. This method can perform any validation that requires access to multiple fields from the form at once. This is where you might put in things to check that if fieldA is supplied, fieldB must contain a valid email address and the like. The data that this method returns is the final cleaned_data attribute for the form, so don't forget to return the full list of cleaned data if you override this method (by default, Form.clean() just returns self.cleaned_data). Note that any errors raised by your Form.clean() override will not be associated with any field in particular. They go into a special "field" called "__all__", which you can access via Form.non_field_errors() if you need to. You don't need to care about __all__ at all (ha, ha!). These methods are run in the order given above, one field at a time. That is, for each field in the form (in the order they are declared in the form definition), the Field.clean() method (or it's override) is run, then clean_<fieldname>(). Finally, once those two methods are run for every field, the Form.clean() method, or it's override, is executed. Again, any of these methods can raise a ValidationError. For any field, if step (1) raises a ValidationError, step (2) is not run, however, steps (1) and (2) are run for all remaining fields. Regardless of the results of steps (1) and (2), step (3) is always run. If step (3) raises a ValidationError, self.cleaned_data will be an empty dictionary. The previous paragraph means that if you are overriding Form.clean(), you should iterate through self.cleaned_data.items(), rather than through the list of fields in the forms: not every field may end up contributing to cleaned_data, because they may have raised ValidationErrors themselves, so don't assume you have the data you need by accessing the form fields directly -- always talk to self.cleaned_data. Hopefully that clears up some of the mystery around the various form validation phases. If somebody wants to write that up as a patch to the newforms documentation, go crazy. Regards, Malcolm --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django users" group. To post to this group, send email to django-users@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-users?hl=en -~----------~----~----~----~------~----~------~--~---