On Sep 6, 2006, at 11:04 AM, BJörn Lindqvist wrote:
>
> On 9/5/06, Karl Guertin <[EMAIL PROTECTED]> wrote:
>>
>> On 9/5/06, BJörn Lindqvist <[EMAIL PROTECTED]> wrote:
>>> What I'm wondering is how does the decorators validate and
>>> error_handler really work?
>>
>> Do not ask how sausage is made! Actually, if you _really_ want to
>> know
>> how it all works, you'll have to read the source. There's more code
>> involved than I can reasonably cover in an email. You'll want to look
>> at controllers.py, errorhandling.py and widgets/forms.py.
>
> I tried that method before asking the list. :)
>
>>> Then
>>> the error_handler decorator I think makes a HTTPRedirect back to
>>> add()
>>> if validation fails.
>>
>> I'm pretty sure that there isn't a HTTPRedirect involved, the add()
>> method is called by the error handling code and tg_errors is injected
>> into the parameters list.
>
> Yes, I noticed now. It seems wrong that the URL changes to /save but
> the page is still showing the /add page.
You could store the errors and input values in a cookie/session and
issue a HTTP Redirect if this really bothers you. However, I find it
easier to pass them around at request.X and calling the error
handling method from within the method that received input. YMMV
however.
>
>>> But how does it manage to display the error
>>> messages in the form?
>>
>> tg_errors is a dictionary of formencode.Invalid instances. The form
>> widget checks this error dict while building the form and generates
>> the message by str()'ing the invalid instance.
>
> I'm probably wrong, but I think you are wrong. If I modify the
> original examples add() method to the following:
>
> @expose(template=".templates.add")
> def add(self):
> return dict(form=comment_form)
>
> I.e, I remove the tg_errors parameter. It still works so tg_errors
> seem to be unused by the widgets. FormEncodes error messages must be
> passed to the widget using some other mechanism.
Refer to my prev. post where I tried my best to explain this as
clearly as my English allows me.
>
>>> How does the form know that it should display
>>> the values that you wrote there previously when you are redirected
>>> back?
>>
>> The values are still in the CherryPy environmental variables, the
>> widgets pull their data from there if they aren't passed in data.
>
> TurboGears stuffs it in request.input_values and
> request.validation_errors?
As I mentioned in my prev. post in this thread, yes. tg_errors ==
request.validation_errors. tg_errors can be used in the method that
is target of error_handler as a parameter to do something with them
when they're not None.
You can also omit error_handler altogether by giving a tg_errors
parameter to the method that is decorated with validate. If you do
so, this method will become it's implicit error_handler.
@validate(...)
def save(self, ..., tg_errors=None):
if tg_errors:
# Errors coerced, do something useful
else:
# No errors, work with the good, coerced values.
>
>>> I would like to implement code similar to the example above, but
>>> without using a form widget. And preferably without using the
>>> validate
>>> and error_handler decorators. Maybe someone can show me an
>>> example of
>>> that?
Refer to the my prev. post where I gave a pseudo-code example of
exactly this.
>>
>> The pieces really are designed to work together. You can use them
>> separately, but building this system has consumed most of the
>> development effort in TurboGears thus far.
>>
>> I'm curious what you can't accomplish by re-templating the current
>> system.
>
> A few reasons. I want multiple methods that share a save() method:
>
> ...
> def add_stuff_one_way(self):
> return dict(...)
>
> def add_stuff_another_way(self):
> return dict(...)
>
> def save(self, ....):
> save called from either add_stuff_one_way() or
> add_stuff_another_way()
>
> In a setup like this, the @error_handler decorator doesn't work
> because it only takes one argument.
Wrong. Did you really read the source? ;) You can accomplish exactly
what you're trying to do by specializing error_handler:
@error_handler(add_stuff_one_way, "another_way in tg_errors")
@error_handler(add_stuff_one_way, "one_way in tg_errors")
def save(self, ..):
...
Now you only need a chained_validator which adds a "one_way" or
"another_way" to the error_dict if it finds any errors in it (this is
left as an exercise to the reader). Might be hacky, but works....
> The other reason is that I don't want to use TurboGears widgets, and
> @validate and @error_handler seem to be tightly coupled to the widget
> system.
Wrong again. "validate" is tightly coupled with FormEncode *only*.
You can skip widgets altogether and use plain FE validators with it:
@validate(validator={'param1':Int, 'param2', WhatEver})
or
@validate(validator=Schema(....))
If you look at validate's source, you can even notice that form
doesn't have to be a widget at all. You can pass any object that has
a "validate" method and raises FE's Invalids on wrong input.
"error_handler" has nothing to do with widgets but with errorhandling.
The only part of this process where the widgets kick in is with the
inspection of request.input_values and request.validation_errors to
display previous values and errors. Nothing is preventing you from
rolling your own mechanism to do the same, using errorhandling and
avoiding widgets altogether.
Alberto
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"TurboGears" 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/turbogears
-~----------~----~----~----~------~----~------~--~---