Just got back from a week-long Hawaii vacation, so I'm getting back into the Django groove. Earlier today I committed the first stab at validation-aware models on the magic-removal branch:
http://code.djangoproject.com/changeset/2518 Here's how it works: * Model instances have a validate() method. It returns a dictionary of field name -> list of error messages. If there are no errors, it returns an empty dictionary. * Behind the scenes, validate() actually does a two-pass validation over all the model instance's fields: * First, it runs the field's to_python() method, which is field-type-specific and converts the data to the appropriate Python type. For example, if a date field is set to '2005-01-03', to_python() converts it to a datetime object. * Second, for all fields that didn't have validation errors in to_python(), it executes the field's validate_full() method. That method can safely assume the data is in the correct data type. The separation of "type-specific" validation and "logical" validation makes things a lot cleaner, both in concept and implementation. It's sort of like the CriticalValidationError framework in django/core/formfields.py in trunk. * Model instances' save() method will call validate() behind the scenes, and the object won't save if there are any validation errors. I haven't coded this part yet, but it's a simple change. * I've only implemented to_python() and validate_full() for a handful of field types in django/db/models/fields/__init__.py. The rest still need to be implemented. * Every one of the to_python() and validate_full() functions that *are* implemented (to my knowledge) have unit tests in tests/modeltests/validation/models.py. As we implement to_python() and validate_full() for other field types, they should get unit tests immediately. EXAMPLE CODE: class Person(models.Model): name = models.CharField(maxlength=50) birthday = models.DateField() favorite_number = models.IntegerField() >>> p = Person(name='Joe', birthday='never', favorite_number='foo') >>> p.validate() {'birthday': 'Enter a valid date in YYYY-MM-DD format.', 'favorite_number': 'This value must be an integer.'} >>> p = Person(name='Joe', birthday='2005-1-3', favorite_number='34') >>> p.validate() {} >>> p.birthday datetime.date(2005, 1, 3) >>> p.favorite_number # note this is an integer now, no longer a string 34 Thoughts, criticisms? The only part I'm sketchy on is the side effect of converting the values to their Python data types. The cleanliness/consistency is quite nice, but it's slightly not something a developer might expect. However, we can solve the latter through clear documentation. Adrian -- Adrian Holovaty holovaty.com | djangoproject.com --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to [email protected] To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/django-developers -~----------~----~----~----~------~----~------~--~---
