On Jan 18, 5:17 am, Malcolm Tredinnick <malc...@pointy-stick.com> wrote: > (b) Please do write it out and post it here so that we can have the > discussion on the mailing list.
Let’s step back, distance ourselves from the current implementation and look at how forms, models and modelforms should ideally interact validation-wise at a somewhat abstract level. The main focus is on fields. Form fields =========== In validation context, a form field has the following responsibilities: * get input value (a string) from user, * validate that the value is in expected format (*format validation*, preconditions), * convert the value to a Python type, * validate that the resulting value satisfies any conditions set for the value (*value validation*, postconditions). Model fields ============ Ditto for model fields, omitting the first step: format validation, coercion to Python and value validation is generally required. If, however, we want to more radically depart from current behaviour, then it is possible and indeed reasonable to assume that the values assigned to model fields are already the expected Python types, as it is the application developer’s responsibility to assure that. This would get rid of the format validation and coercion step (these are already handled by the form layer). to_python() is currently used in model fields for controlling the conversion. Interaction between form and model fields ========================================= Forms and models should be orthogonal and oblivious of each other. Modelforms serves as the glue and mapping between the two, being aware of the internals of both. A modelform should have the following responsibilites in validation context: * clean the form (performs format validation, coercion to a Python type and value validation), * assign the form field values to the associated model fields, * inform the model fields that basic validation has already been done to avoid duplicated validation and call any additional validation methods. Thus, the modelform should be able to invoke only the additional and custom model field validators, *skipping the default coercers and validators* that can be assumed to be the same in similar form and model field classes (e.g. an IntegerField in forms and IntegerField in models). Let's look at an contrived example that illustrates the point. Let IntegerForeignKeyField be an imaginary foreign key field in a model that accepts only integer foreign keys. The corresponding form field would be a PositiveIntegerField. Suppose that the developer has provided a custom validator for the IntegerForeignKeyField that allows foreign keys only to objects where the is_active boolean field is True. When a modelform uses them both, it is the form field's responsibility to assure that the value is converted to a Python int and that the int is positive. IntegerForeignKeyField should not re-run neither the coercion nor basic validation routines. However, IntegerForeignKeyField must 1) validate that the integer points to an existing row in the related table (i.e. run a foreignkey-specific validator), 2) validate that the row has is_active == True (i.e. run a custom validator). In this case, coercion and basic validation is cheap, but that's not always the case. General validation principles ============================= The extended conclusion of the sections above is as follows. Double validation should never happen. There has to be a way to convey that a value is already validated and no further validation is necessary. No code duplication in type coercion or validation should occur in models and forms. The following distinct converters and validators participate in the coercion/validation process: * format validators that validate that a given string can be converted to a Python type, * converters that coerce a given string to a Python type, * value validators that assure that the value returned by a converter satisfies any conditions set for the value. It should be easy to add custom validators and intercept or override the process at any step. And now something completely different ====================================== "Every problem in computer science can be solved by another level of indirection." --- source unknown Both form and model fields need similar functionality that is not well served by just duplicating validation and coercion functions in them. It would make sense to factor out the common functionality and decouple it from both. A mixin class would serve that purpose well. The following methods would live in the mixin: * clean() that calls to_python() and then validate(), * to_python() that takes care of format validation and coercion, * validate() that takes care of value validation and running custom validators. It would have fields for storing the default and custom validators and perhaps a state field for controlling which parts of the validation process have already been run. I've hacked up an incomplete rough draft at http://dpaste.com/110671/ to illustrate this. Unfortunately it does not illustrate all the points, but the general idea should hopefully come through. Action plan for 1.1 =================== The mixin approach is not in scope for 1.1. We go with what we already have, factoring the bits in current model fields' to_python to a separate django.utils.typeconverters library (see http://github.com/mrts/honza-django/commit/a8239b063591acc367add0a01785181a91a37971 for the first steps in that direction) and using both django.core.validators and django.utils.typeconverters throughout model and form fields. I'm not sure about Honza's plans in regard avoiding duplicate validation, hopefully he comments on that himself. Also, let me remind that model and form objects have not been discussed in this post (and it's already more than 150 lines long), only fields. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Django developers" group. To post to this group, send email to django-developers@googlegroups.com To unsubscribe from this group, send email to django-developers+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/django-developers?hl=en -~----------~----~----~----~------~----~------~--~---