-Regards-
-QH-
That's actually a really good question. The first answer that comes
up: do it the way the 20 minute wiki *will* do it in the next
iteration: don't bother with a flag. Have the edit method catch
SQLObjectNotFound and add a record if that's the case.
The next answer is to use a FieldSet. What I'm about to say is heading
off into fuzzy territory for me, because I haven't played much with
FieldSets. (Michele and Alberto will undoubtedly correct me if I'm
wrong on this one). Let's say, in the wiki20 case, you've got a
FieldSet for the wiki page instance (we'll call that fieldset "page").
Your form would have that fieldset plus the hidden field. You'd pass
to your template a dictionary that looks like this:
dict(formdata=dict(page=page, new=new))
I'm not spelling out the widget stuff, since it sounds like you're
comfortably using widgets right now.
Kevin
Another question has come up for me with regards to using form widgets.
I have seen that there are two basic layout types, table and list. How
does one do a more complex form layout using a widget? The real
application I need to build once I get more comfortable with TG has
some fairly complex forms that need to be laid out as compactly as
possible. A mockup of one of the pages is available here:
http://www.slane.k12.or.us/cmap_cedit.html . The main entry stuff on
the left would be simple enough, but getting the other entry box on the
right escapes me. Can one define custom layouts in one form like this
with widgets?
> Another question has come up for me with regards to using form widgets.
> I have seen that there are two basic layout types, table and list. How
> does one do a more complex form layout using a widget? The real
> application I need to build once I get more comfortable with TG has
> some fairly complex forms that need to be laid out as compactly as
> possible. A mockup of one of the pages is available here:
You have to write your own layout. The code in TableForm and ListForm can
help you getting started.
> http://www.slane.k12.or.us/cmap_cedit.html . The main entry stuff on
> the left would be simple enough, but getting the other entry box on the
> right escapes me. Can one define custom layouts in one form like this
> with widgets?
Yes, you can. It's in the class variable "template". Take a look at the
source -- it's not hard, it's inside turbogears/widgets/ and there you have
forms.py and other files -- and you'll get an idea.
--
Jorge Godoy <jgo...@gmail.com>
As Kevin said, if what you need is passing values at display time to
your widgets that's what you can do.
Let's take the wiki20 Form:
<form action="save" method="post">
<input type="hidden" name="pagename" py:attrs="value=pagename"/>
<textarea name="data" py:content="data" rows="10" cols="60"/>
<input type="submit" name="submit" value="Save"/>
</form>
In Widgets language :D this becomes something like:
class MyFields(WidgetsList):
name = HiddenField()
data = TextArea()
wiki20_form = TableForm(name="page", fields=MyFields(),
action="save",
submit_text="Save")
Now if you problem is passing a value to the hidden field, that's what
you will do from your edit method (for example):
@turbogears.expose(html="wiki20.templates.edit")
def edit(self, pagename):
page = Page.byPagename(pagename)
form_values = dict(name=page.pagename, data=page.data)
return dict(form=wiki20_form, form_values=form_values)
in your edit.kid page you will need to do this then:
form.display(value=form_values)
One thing to keep in mind, if you're using a CompoundFormField (ATM a
FieldSet for example) it means you are using a nested field, the value
you get as input associated to such a field is not a plain value but a
dictionary containing its field, value pair.
For example:
class NestedFields(WidgetsList):
one = TextField()
two = TextField()
class MyFields(WidgetsList):
name = TextField()
nested = FieldSet(fields=NestedFields())
myform = TableForm(fields=MyFields(), action="save")
your save method needs to be something like this:
def save(self, name, nested):
The basic rule is that you just expect the parameter you've listed in
the WidgetsList class that you are passing as fields to the form
Widget, in this case fields=MyFields() so we use name and nested.
now when you submit such a form that's what you get as input:
name = "myname"
nested = {"one": "hey", "two": "hello"}
the same rule applies if you need to pass dynamically computed values
to your form for the first display, so in the previous example (wiki20)
you don't pass a flat dictionary but a nested dictionary like this one:
form_values = dict(name="michele",
nested=dict(one="yeah one",
two="really two"))
finally if you don't need to pass dynamically computed values of you
just want a field to always have a default value that should be used on
every first display of your form you can provide it at the widget
instantiation, for example:
name = TextField(default="Your name here!")
Ciao
Michele
> Ok so I added a validator to my edit.
> @turbogears.validate(form=myforms.COOL_FORM)
> def cooledit(self,...):
> dict(editValues=..)
>
> So the problem I am having is that if I use the validator decorator
> the form is not populated when it is first loaded. If I modify the
> data and submit it (submits to itself) it works correctly. If I
> comment out the validator decorator then I get the expected
> behavior of on first page visit the data is populated from the
> values I passed into the view from the controller. And it works
> fine submitting to itself. Is it frowned on to use widgets and
> submit to the same controller function? Or do we think there is a
> bug in my code?
Have you tried passing a value to the form in the template?
def controllermethod(...)
...
return dict(form=form, value=dict(name="Haifa", surname="Wehbe"))
(in the template)
${form.display(value=value)}
Alberto.
I've been reading about metaclasses recently, and I think it would be
quite possible to create a meta class, that processes a class
definition, and produces something that returns the exact same
structure as currently used in widgets.
What do you think, insane or interesting?
Sean
IMHO? insane... :D
That's not how an object is supposed to work, why should we use a class
instead of an instance? it's just not how OOP works and that's why you
can't do that without resorting to metaclass magic, I hope TG will
never do something similar because that could really be confusing and
feel strange to everyone.
But that's only my opinion. ;-)
Ciao
Michele
>
> While I was reading this topic, something just tickled my brain. I
> remember that Kevin had mentioned somewhere (screencast probably)
> about
> the posibility of widgets being defined as classes (ref. SQLObject),
> rather than with an instantiated object, and a dictionary of fields.
>
> I've been reading about metaclasses recently, and I think it would be
> quite possible to create a meta class, that processes a class
> definition, and produces something that returns the exact same
> structure as currently used in widgets.
>
> What do you think, insane or interesting?
Insane :)
Metaclasses are very porwerful and solve some problems very
elegantly, but, like any other powerfull tool, should only be used
when absolutely needed (although it's fun to use them for uneeded
problems to get a grip of them, and have fun, of course).
I remember one case when I coded an internal app for the company I
work at to handle nightly backups (via rdiff-backup) of many servers.
Plugins were made to support different schemas (postgres, mysql,
tracs, svn repositories, etc...) and the idea was that these plugins
could be easily written by the python newbie coworkers. I decided to
take a shot on metaclasses so they didn't need to call super
cooperatively when extending methods. As you can guess, I ended up
reimplementing python's MRO in an unmaintainable mess and helped them
neither as when they wanted to write real python code they weren't
used the "super" idiom. But it's true that I learned a lot on the way...
The widget API right now is using metaclasses internally for various
stuff, but we really tried hard not to get overexcited with it
(thanks Michele for stopping my feet at #419 ;) as it would only over-
complicate things for no good reason.
Regards,
Alberto
>IMHO? insane... :D
>
>That's not how an object is supposed to work, why should we use a class
>instead of an instance? it's just not how OOP works and that's why you
>can't do that without resorting to metaclass magic, I hope TG will
>never do something similar because that could really be confusing and
>feel strange to everyone.
>
>But that's only my opinion. ;-)
>
>Ciao
>Michele
>
>
heh, yeah, I thought it sounded a bit crazy, but I thought of that just
after waking up this morning.
But, crazy ideas about class/object mutation aside, I think it would be
preferable to define a form as a class. Besides the aesthetic difference
(which is a good one IMHO) it could also provide for better functionality.
i.e. you could define custom validation for your fields in the class,
I'm not sure I like this decorator method that exists now. But to be
honest, I haven't really used it (partly because of lack of docs).
pseudo example:
class MyForm( WidgetForm ):
Name = TextField(label=...[, class=..., value=..., size=..., ...])
Value = TextField(label=...[, class=..., value=..., size=..., ...])
Submit = SubmitButton(value=...[, name=..., class=...])
def _validateName( self, value ):
if len( value ) < 4:
return false
if not value.isalnum():
return false
...etc...
then defining a your method could simply be a matter of:
@expose()
@validate(MyForm, postOnly=true)
def save(self, **values):
# database code here
Anyway, that's my fantasy, I may make it my own reality eventually.
Sean
Don't give up, crazy ideas sometimes turn out to be the best ones... :)
> pseudo example:
> class MyForm( WidgetForm ):
> Name = TextField(label=...[, class=..., value=..., size=..., ...])
> Value = TextField(label=...[, class=..., value=...,
> size=..., ...])
> Submit = SubmitButton(value=...[, name=..., class=...])
>
> def _validateName( self, value ):
> if len( value ) < 4:
> return false
> if not value.isalnum():
> return false
> ...etc...
You can use something smilar to de "declarative" style you're
proposing using WidgetList and the current API:
class NameValidator(FancyValidator):
def to_python(self, value, state=None):
# your validtion code here, raise Inavalid in not valid, return
coerced value
class MyFormFields(WidgetList):
name = TextField(validator=NameValidator())
value = TextField(...)
submit = submitButton(...) # You don't really need it as the form
provides...
class MyForm(Form):
fields = MyFormFields()
>
> Anyway, that's my fantasy, I may make it my own reality eventually.
well, I'd encourage you to share your fantasies (Widget related)
here, If they're good they will likely be part of TG for everyone to
enjoy.
Regards,
Alberto
FastData simply uses formmaker.fields_for to ispect the SQLObject model
and build a list of widgets that are then passed to the Form
constructor as the fields argument, the other somewhat special thing is
that the form parameter passed to the validate decorator is not a form
instance but a callable that returns the above form instance. ;-)
Ciao
Michele