Re-usable form

4 views
Skip to first unread message

Diego Woitasen

unread,
May 25, 2009, 9:28:14 PM5/25/09
to TurboGears
Hi,
I want to write a reusable form using TableForm as base class. I tried
with this:

class RuleForm(TableForm):
def __init__(self, id=None, parent=None, children=[], host_filter=[],
**kw):
super(RuleForm, self).__init__(id,parent,children, **kw)
self.fields = [
TextField(id = 'description', label = 'Description'),
]

and this:

class RuleForm(TableForm):
def __init__(self, id=None, parent=None, children=[], host_filter=[],
**kw):
children = [
TextField(id = 'description', label = 'Description'),
]
super(RuleForm, self).__init__(id,parent,children, **kw)

without sucess.

What it the recommended way to write a reusable form. The complete form
will have some select fields that changes in each use of the forms.


regards,
Diego

--
Diego Woitasen
XTECH - Soluciones Linux para empresas
(54) 011 5219-0678

Diez B. Roggisch

unread,
May 26, 2009, 5:50:40 AM5/26/09
to turbo...@googlegroups.com
On Tuesday 26 May 2009 03:28:14 Diego Woitasen wrote:
> Hi,
> I want to write a reusable form using TableForm as base class. I tried
> with this:
>
> class RuleForm(TableForm):
> def __init__(self, id=None, parent=None, children=[], host_filter=[],
> **kw):
> super(RuleForm, self).__init__(id,parent,children, **kw)
> self.fields = [
> TextField(id = 'description', label = 'Description'),
> ]
>
> and this:
>
> class RuleForm(TableForm):
> def __init__(self, id=None, parent=None, children=[], host_filter=[],
> **kw):
> children = [
> TextField(id = 'description', label = 'Description'),
> ]
> super(RuleForm, self).__init__(id,parent,children, **kw)
>
> without sucess.

What does "without success" mean? You are aware, that in the latter example
you simply override whatever children are passed?

Besides, the simple problem of yours seems to be solvable using


common_widgets = [...] # list of widgets

some_form = Form(children = common_widgets + some_other_widgets]

Diez

Diego Woitasen

unread,
May 26, 2009, 10:04:09 AM5/26/09
to turbo...@googlegroups.com
Means, it doesn't work. If I use fields outside the constructor works, for
example:

class RuleForm(TableForm):
fields = [
TextField(id = 'description', label = 'Description'),
]

def __init__(self, id=None, parent=None, children=[], host_filter=[],
**kw):
super(RuleForm, self).__init__(id,parent,children, **kw)

That works, but I need fields inside the constructor because I want to use
SelectionList or CheckboxList which contents could change in each use of
RuleForm (quering data from database).

I could use a function that returns the children field list and use them
like you said but I prefer to use classes or at least understand why my
approach doesn't work.

Regards,

Diez B. Roggisch

unread,
May 26, 2009, 10:45:00 AM5/26/09
to turbo...@googlegroups.com

"doesn't" work means nothing. If that's all you can give as an
error-description, all you can get as answer is "then do it differently".

Does it throw an exception? Don't the fields appear? If yes, none of them,
onle the super-classes one, only the subclasses one?

Diez

Diez B. Roggisch

unread,
May 26, 2009, 10:49:46 AM5/26/09
to turbo...@googlegroups.com
On Tuesday 26 May 2009 16:04:09 Diego Woitasen wrote:

This is not intended to work. ToscaWidgets are instantiated once, and re-used.

To make selectfields display varying values, use a callable as
options-parameter.

def get_options():
return some_options


class MyForm(TableForm):
class fields(WidgetList):
select_field = SingleSelectField(options=get_options)


Diez

Diego Woitasen

unread,
May 26, 2009, 1:54:57 PM5/26/09
to turbo...@googlegroups.com
ok, ok... sorry...

The fields don't appear, none of them, only the submit button.

Diego Woitasen

unread,
May 26, 2009, 2:41:15 PM5/26/09
to turbo...@googlegroups.com
I got "TypeError: 'function' object is not iterable".

Anyway, I don't like that approach. What if a want to pass parameters to
get_options()? I want to pass a SQLAlchemy query when the form is
instantiated to condition the data to be returned i select fields.

I think the solution at the moment is to write a function that return all
childrens to pass to my form but I don't like it.

I'm using TG2 RC1.

Diez B. Roggisch

unread,
May 26, 2009, 4:57:33 PM5/26/09
to turbo...@googlegroups.com
Diego Woitasen schrieb:

Full stacktrace please, and code.... crystal-ball time is over for this
month.

This works in our codebase, so the problem must be on your side:

def get_users():
"""
This function returns a list of tuples

(User, str)

to be used as options for a SingleSelectField.

It is important to work with **User**-objects here,
**not** with ids! Otherwise in case of a failed
validation, the display of the SingleSelectField
wouldn't show the last selected value.
"""
return [(u, u.email) for u in User.query()[:10]]


model_select_form = ListForm("model_select_form",
action="model_select_field_action",
fields=[SingleSelectField("user",
options=get_users,

validator=ModelValidator(User)),
TextField("leave_me_empty",
validator=NotEmpty()),
])

> Anyway, I don't like that approach. What if a want to pass parameters to
> get_options()? I want to pass a SQLAlchemy query when the form is
> instantiated to condition the data to be returned i select fields.
>
> I think the solution at the moment is to write a function that return all
> childrens to pass to my form but I don't like it.

There are various ways to overcome this. You can use the tmpl_context to
pass the query.


def get_options():
return tmpl_context.some_options


# in the controller

@expose()
def my_action(self, ...):
tmlp_context.some_options = my_query
return ...


It should also be possible to do something like this (in the template):

${my_form.display(value, dict(options=dict(select_field=the_query)))}


Diez

Reply all
Reply to author
Forward
0 new messages