I've been thinking about how to solve this problem, and what I've come up with so far is this:
- Schemas may be bound to a set of values. When a schema is bound, it is cloned, and any "deferred" values it has will be resolved. - A deferred value is a callable that accepts the schema node being bound and a set of arbitrary keyword arguments. It should return a value appropriate for its usage (a widget, a missing value, a validator, etc). - Deferred values are not resolved until the schema is bound. - Schemas are bound via "SomeSchema().bind(**kw)". The values in "kw" are passed to each deferred value along with the schema node being bound. Here's an example: """ @colander.deferred def deferred_date_validator(node, **kw): max_date = kw.get('max_date') if max_date is None: max_date = datetime.date.today() return colander.Range(min=datetime.date.min, max=max_date) @colander.deferred def deferred_date_description(node, **kw): max_date = kw.get('max_date') if max_date is None: max_date = datetime.date.today() return 'Blog post date (no earlier than %s)' % max_date.ctime() @colander.deferred def deferred_date_missing(node, **kw): default_date = kw.get('default_date') if default_date is None: default_date = datetime.date.today() return default_date @colander.deferred def deferred_body_validator(node, **kw): max_bodylen = kw.get('max_bodylen') if max_bodylen is None: max_bodylen = 1 << 18 return colander.Length(max=max_bodylen) @colander.deferred def deferred_body_description(node, **kw): max_bodylen = kw.get('max_bodylen') if max_bodylen is None: max_bodylen = 1 << 18 return 'Blog post body (no longer than %s bytes)' % max_bodylen @colander.deferred def deferred_body_widget(node, **kw): body_type = kw.get('body_type') if body_type == 'richtext': widget = deform.widget.RichTextWidget() else: widget = deform.widget.TextAreaWidget() return widget @colander.deferred def deferred_category_validator(node, **kw): categories = kw.get('categories', []) return colander.OneOf([ x[0] for x in categories ]) @colander.deferred def deferred_category_widget(node, **kw): categories = kw.get('categories', []) return deform.widget.RadioChoiceWidget(values=categories) class BlogPostSchema(Schema): title = SchemaNode( colander.String(), title = 'Title', description = 'Blog post title', validator = colander.Length(min=5, max=100), widget = deform.widget.TextInputWidget(), ) date = SchemaNode( colander.Date(), title = 'Date', missing = deferred_date_missing, description = deferred_date_description, validator = deferred_date_validator, widget = deform.widget.DateInputWidget(), ) body = SchemaNode( colander.String(), title = 'Body', description = deferred_body_description, validator = deferred_body_validator, widget = deferred_body_widget, ) category = SchemaNode( colander.String(), title = 'Category', description = 'Blog post category', validator = deferred_category_validator, widget = deferred_category_widget, ) schema = BlogPostSchema().bind( max_date = datetime.date.max, max_bodylen = 5000, body_type = 'richtext', default_date = datetime.date.today(), ) form = deform.Form(schema) """ This proposal does not deal with conditional inclusion or exclusion of schema nodes, only resolving deferred schema properties. Comments are appreciated. - C On Tue, 2010-09-07 at 20:37 +0800, Tim Hoffman wrote: > Bummer ;-) > > > I don't think I have a developed an application in the last 10 years > that hasn't has to do this. > I was quite surprised when I discovered this feature was missing in > formish, but it seems to be missing in quite a > few other form libs like wtforms as well. > > I suppose at least they all have declarative method of defining the > schema, but it does mean the actual schema definition is a bit more > obscured. > > Cheers > > T > > > > > On Tue, Sep 7, 2010 at 8:20 PM, Chris McDonough <chr...@plope.com> wrote: > > Hi Tim, > > > > Sorry, there is no built-in solution that will allow you to use > > declarative-module-scope code only. You'll need to generate schemas and > > widgets at render time. > > > > - C > > > > > > On Tue, 2010-09-07 at 12:56 +0800, Tim Hoffman wrote: > >> Hi Chris. > >> > >> Am just starting too look at deform in some detail and I have question. > >> > >> One of the things I have struggled with formish has been the fact I > >> can't easily > >> define a source of values for widgets like checkbox or validators such > >> as OneOf to > >> only be resolved late at render time. And I can't see how I would go > >> about it with deform. > >> > >> In your example http://docs.repoze.org/deform/app.html you have > >> colors = (('red', 'Red'), ('green', 'Green'), ('blue', 'Blue')) used > >> as values for > >> > >> widget.RadioChoiceWidget values and for the validator OneOf > >> > >> So in my contrived example I would like the set of possible values > >> for color is dependent on the > >> user and some other factor. Looking at the code for SelectWidget and > >> RadioChoice widget > >> it appears they won't take a callable and lazily render those values > >> at render time. > >> > >> > >> With formish I basically constructed the form structure (schema) > >> but only applied widget definitions and validators just before render > >> time. So that I could use things > >> like the current context to determine values for validation or > >> choices. This was a bit of a hack. > >> > >> > >> So do you have a strategy or suggestion on how to approach this use case ? > >> > >> I suppose I could work with imperative schema definition performed > >> late, but I much prefer to work with classes. > >> (I currently generate Formish (structures) directly from UML). > >> > >> Cheers > >> > >> Tim > >> _______________________________________________ > >> Repoze-dev mailing list > >> Repoze-dev@lists.repoze.org > >> http://lists.repoze.org/listinfo/repoze-dev > >> > > > > > > > _______________________________________________ Repoze-dev mailing list Repoze-dev@lists.repoze.org http://lists.repoze.org/listinfo/repoze-dev