This is one of the problems with @validate; it's not flexible enough
for this situation. The developers are mulling over ways to rewrite
it or replace it.
You can generally do what @validate does:
html = self.my_form_method()
return htmlfill.render(html, request.params, {"error_field": "Error
Message"}) # Or request.POST for post-only situation
--
Mike Orr <slugg...@gmail.com>
This is generally true, but sometimes you need to flag an error based
on information outside the form data, or not known until a particular
point in the action. This is generally related to other data in the
database or in the session.
You can pass it to the validator via the 'state' argument, but there
are three problems with that:
- 'state' is incompatible with @validate because the state is not
known when the decorator is called.
- Checking external conditions can make the validators ugly and
non-portable.
- 'state' is not well thought through. The docs give the
impression that you can pass anything, but I think parts of FormEncode
assume it's a dict and add keys if so?
If you don't use 'state', your other choice is to check it manually in
the action.
--
Mike Orr <slugg...@gmail.com>
Originally there was a plan to split it into three parts, with
@validate calling the parts in order for compatibility.
http://pylonshq.com/project/pylonshq/ticket/405
Since then, there has been discussion about just leaving the decorator
as-is and writing some utility functions for the controller, or
promoting WTForms (http://wtforms.simplecodes.com/), or adding more
support for one-method form handling (doing form & validation in the
same method).
I was initially enthusiastic about WTForms but I think it may be too
big a jump for Pylons. (That doesn't mean you can't use it, or that
it shouldn't have a Pylons Howto eventually.)
There's a lot to be said for doing the form and validation in the same
action. Something like:
if request.POST:
if not validation-errors:
do action and return success page or redirect
display form(maybe with data and errors)
I always did this until I came to Pylons. It avoids the need for a
decorator. I've been using @validate because the Pylons tradition is
to have separate methods for the form and validation, but I'm
beginning to wonder if it's worth it. I'd like to add a map.resource
method that uses one-method form handling, to make it easier to do.
--
Mike Orr <slugg...@gmail.com>
The decorator works, it's just limited. Ideally you want to do all
your validation the same way. But @validate can only handle some
cases.
1. If you want to validate based on the current database record, that
isn't known until the middle of the action. This would be a good use
for 'state', but there's no way to pass state through the decorator.
2. The default post_only=True, on_get=False is ridiculous. It ends up
passing GET requests through without validation, which will then cause
your action to crash (if expected data isn't there or is the wrong
type) or to perform an action it shouldn't.
3. If the validation passes but you later want to flag a different
error, you're in the same situation the OP is in.
4. If you want to perform some of the error handling in the action,
you can't just paste code from @validate because it does a lot of
other stuff to deal with its arguments, and you have to sit there and
think about which parts of the code are relevant to the situation and
how to transform them.
--
Mike Orr <slugg...@gmail.com>
FormEncode's main problem is it needs a better manual, which I'm
working on. The examples in the manual are geared toward interactive
usage, which leaves you somewhat at a loss for how to use them in
Pylons. Which options to use for a checkbox, advanced uses, schemas,
chained validators, how the messages work -- these are all things I
had to puzzle through at various occasions.
--
Mike Orr <slugg...@gmail.com>
Yes. I think it was created because TurboGears had a validate
decorator and we wanted one too. It solves the use cases it was
designed for, but not the ones it wasn't. I don't know how other
frameworks, which are generally more rigid than Pylons, work around
these use cases. How do TurboGears users handle edge cases in
validation?
> I will mention though that I think
> formencode's validators and htmlfill are part of the solution although
> maybe they themselves need some improvements.
>
> Anyways I think this can be solved with some incredibly well
> documented examples and some more tools in webhelpers.
What specific improvements? Ask and ye may receive. Don't ask and
you definitely won't.
> To find out what those tools are I think we
> should _talk_ about the most generic framework for form validation
> possible using formencode validators and htmlfill with mako and pylons
> but not actually design such a framework as much as design the tools
> for the framework. As it evolves we can build better examples and
> better helpers.
Maybe. We'd need to consider a concrete example of the "tools" or
design patterns to judge their feasability.
Some people use Mako def's to layout a widget with its label and error
message and other goodies. Mako's call-with-content feature is good
for plugging some (custom) HTML inside other (boilerplate) HTML.
> So some comments with regard to what I think such a virtual framework
> would need to allow for:
These are the design patterns, I suppose?
> 1. the separation of form prompt(initial display), form
> redisplay(errors) and form rendering(shared by initial display and
> redisplay).
What would that gain you? Are you talking about something like a
class with methods for these three parts?
> 2. ability to remove field defaults from being redisplayed (ie. passwords)
This would probably have to be done at the controller level, zapping
any data values you don't want to redisplay. A form-framework class
could have a .zap-these-fields method.
> 3. A dummy state class that can be used with formencode
FormEncode's 'state' assumptions need to be documented. Ian once
remarked he wished 'state' had defaulted to something else rather than
None; I don't remember if it he'd wanted an empty dict or object.
How would a dummy state object help?
> 4. How to pass in the proper encoding, these seems to have changed
> since some form examples were put in the wiki and I don't understand
> why some are more complicated than others.
I'm not aware of any encoding changes in FormEncode, but there may
have been. There were some bugs with Routes and Unicode arguments,
but that's another thing.
> 5. How to handle repetitions in the template, schema and error handling
That's what the ForEach validator is for, but it's undocumented. I've
never gotten the hang of repeating form widgets, so I avoid them. If
somebody who understands them can write a howto for putting a
repeatable row of widgets on a form and validating them, that would be
very helpful.
> 6. How to handle javascript and repetitions
> 7. How can non-javascript be safely handled when a form is dynamically
> built with javascript callbacks? For example updating a form's layout
> depending on the type of user to create.
My understanding of Javascript is basic so I'll skip these.
> 8. How to manually raise errors in such a way that the form is
> redisplayed as if the FE schema didn't succeed.
This needs to be documented in any case.
> 9. How are options used in the form? How can the validators use these
> options to validate the form? How can they be used to validate AND
> redisplay the form on error without multiple db requests?
What kind of "options" do you mean? There are SELECT options,
validator constructor args, etc.
--
Mike Orr <slugg...@gmail.com>
I saw your mail on the FE list and I made some changes to the wiki
document. I might make some more.
>
> > To find out what those tools are I think we
> > should _talk_ about the most generic framework for form validation
> > possible using formencode validators and htmlfill with mako and pylons
> > but not actually design such a framework as much as design the tools
> > for the framework. As it evolves we can build better examples and
> > better helpers.
>
> Maybe. We'd need to consider a concrete example of the "tools" or
> design patterns to judge their feasability.
I made an example linked below [2], but its still pretty ugly. I
guess that's actually the point, how can we hide the ugliness in such
a way that its easy to do simple form validation and moderately easy
to extend it to do more complicated validation(repetitions, use of
state, etc). I don't think decorators really work because there are
two many intermediary steps that need hooks not just one step in the
middle. I don't really feel like the clunker of a class I just made
is a solution but at least its an example of the steps necessary to
provide validation. Maybe some people have suggestions on how to
handle this or see functionality that can be encapsulated in a tool.
Other people might think that all this is not worth encapsulating and
everyone should just write it themselves from scratch, I think we can
do a smidgen better than that though.
>
> Some people use Mako def's to layout a widget with its label and error
> message and other goodies. Mako's call-with-content feature is good
> for plugging some (custom) HTML inside other (boilerplate) HTML.
Yes and that is how it should be, everyone does markup their own way,
EXCEPT it makes documentating a generalized example of using all the
data pieces a pain.
>
> > So some comments with regard to what I think such a virtual framework
> > would need to allow for:
>
> These are the design patterns, I suppose?
They are more like edge cases to the form processing design pattern,
if you want to call it that.
>
> > 1. the separation of form prompt(initial display), form
> > redisplay(errors) and form rendering(shared by initial display and
> > redisplay).
>
> What would that gain you? Are you talking about something like a
> class with methods for these three parts?
Yeah I've included such a class. You can seperate GET and POST
between the prompt and process methods for one thing and you don't
have to check if the form should be received or sent. Also it will
compress down to the less general case where both actions are the same
action.
>
> > 2. ability to remove field defaults from being redisplayed (ie. passwords)
>
> This would probably have to be done at the controller level, zapping
> any data values you don't want to redisplay. A form-framework class
> could have a .zap-these-fields method.
Yeah I think this should be custom but it has to kind of sit between
everything else so it needs a hook or something. In the example given
you could strip it from defaults in your own version of
_process_error().
>
> > 3. A dummy state class that can be used with formencode
>
> FormEncode's 'state' assumptions need to be documented. Ian once
> remarked he wished 'state' had defaulted to something else rather than
> None; I don't remember if it he'd wanted an empty dict or object.
>
> How would a dummy state object help?
As far as I know formencode will not work unless you pass an object as
the state, ie. it will not take a dictionary. Therefore everytime you
need state you make a class, any class. Its just two lines to have it
do nothing but its two lines I have to write _every_ time I want a
state object. If you want it to repr/str to something useful you have
to add that everytime as well. This is the kind of boiler plate that
by itself is nothing but summing up becomes annoying. Is there a
Dummy class in the python stdlib? We chould probably do something
more creative with its contructor than nothing though. There are
examples in the wiki.
>
> > 4. How to pass in the proper encoding, these seems to have changed
> > since some form examples were put in the wiki and I don't understand
> > why some are more complicated than others.
>
> I'm not aware of any encoding changes in FormEncode, but there may
> have been. There were some bugs with Routes and Unicode arguments,
> but that's another thing.
Actually you are right I don't think anything changed, I meant in
pylons though.
Something like the madness(I'm sure its fine I just don't see why)
seen here has to be used: [1].
>
> > 5. How to handle repetitions in the template, schema and error handling
>
> That's what the ForEach validator is for, but it's undocumented. I've
> never gotten the hang of repeating form widgets, so I avoid them. If
> somebody who understands them can write a howto for putting a
> repeatable row of widgets on a form and validating them, that would be
> very helpful.
>
Yes ForEach is just the start though, NestedVariables + pulling
repetitions from the values after encoding them gets really wild.
Especially if you have nested things and want labels with valid ids.
> > 6. How to handle javascript and repetitions
> > 7. How can non-javascript be safely handled when a form is dynamically
> > built with javascript callbacks? For example updating a form's layout
> > depending on the type of user to create.
>
> My understanding of Javascript is basic so I'll skip these.
Yeah eventually we aren't going to be able to get away with ignoring
javascript's role in form processing.
>
> > 8. How to manually raise errors in such a way that the form is
> > redisplayed as if the FE schema didn't succeed.
>
> This needs to be documented in any case.
>
> > 9. How are options used in the form? How can the validators use these
> > options to validate the form? How can they be used to validate AND
> > redisplay the form on error without multiple db requests?
>
> What kind of "options" do you mean? There are SELECT options,
> validator constructor args, etc.
Yeah I meant more of options for selects, but really any dynamic data
that is needed during form validation AND presentation.
>
> --
> Mike Orr <sluggos...@gmail.com>
[1] https://www.knowledgetap.com/hg/pylons-dev/file/5b3367b3aac1/pylons/decorators/__init__.py#l175
[2]
(template)
http://pylonshq.com/pasties/e881e31a8fb3801cecd5d849c98e9247
(usage)
http://pylonshq.com/pasties/728ebeea0a28d21df6c76af72a07c365
(library outlining hooks and core functionality)
http://pylonshq.com/pasties/92435103c1ab8ae05b5705cb641ae7d0
-Ian Wilson
Base controllers like your #2 and #3 links are a good idea. Put them
in the Pylons Cookbook and if any of them get highly used, they might
be considered for the Python core.
>> > 3. A dummy state class that can be used with formencode
>>
>> FormEncode's 'state' assumptions need to be documented. Ian once
>> remarked he wished 'state' had defaulted to something else rather than
>> None; I don't remember if it he'd wanted an empty dict or object.
>>
>> How would a dummy state object help?
>
> As far as I know formencode will not work unless you pass an object as
> the state, ie. it will not take a dictionary. Therefore everytime you
> need state you make a class, any class. Its just two lines to have it
> do nothing but its two lines I have to write _every_ time I want a
> state object. If you want it to repr/str to something useful you have
> to add that everytime as well. This is the kind of boiler plate that
> by itself is nothing but summing up becomes annoying. Is there a
> Dummy class in the python stdlib?
``webhelpers.containers.DumbObject``
It creates attributes for its keyword args. It doesn't do anything else.
There's also ``formencode.declarative.Declarative``, which uses
metaclass tricks to set up standard attributes from positional args.
The closest thing in the stdlib is ``object``, but you can't use it
for data because its instances won't take attributes.
--
Mike Orr <slugg...@gmail.com>