how to use widget selection dynamically?

0 views
Skip to first unread message

Olli Wang

unread,
Feb 21, 2006, 11:27:54 PM2/21/06
to TurboGears
hi, i got problem when using SingleSelectField. i want to load data
from database for options, but if i add new record to database, the
option won't update automatically. any ideas?

# get existed categories
categories = list(ScheduleCategory.select())
options = []
for category in categories:
options.append((category.id, "%s - %s" % (category.name,
category.description)))

class AddEntryFields(widgets.WidgetsDeclaration):
# option won't update automatically if i add new record to
ScheduleCategory.
category = widgets.SingleSelectField(label="Category:",
options=options)

add_entry_form = widgets.TableForm(fields=AddEntryFields(),
submit_text=" Save Entry ")

Michele Cella

unread,
Feb 22, 2006, 5:00:05 AM2/22/06
to TurboGears

You can use a callable to prepare options:

def prepare_options():
categories = list(ScheduleCategory.select())
return [(category.id, "%s - %s" % (category.name,
category.description)) for category in categories]

then:

category = widgets.SingleSelectField(label="Category:",

options=prepare_options)

Not tested but I think it should work.

Ciao
Michele

Leandro Lucarella

unread,
Feb 22, 2006, 12:18:37 PM2/22/06
to turbo...@googlegroups.com
Michele Cella, el mi�rcoles 22 de febrero a las 10:00 me escribiste:

What about changing the options at "display-time"? That should work too,
right?

--
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
.------------------------------------------------------------------------,
\ GPG: 5F5A8D05 // F8CD F9A7 BF00 5431 4145 104C 949E BFB6 5F5A 8D05 /
'--------------------------------------------------------------------'
SEÑOR BIELSA: CON TODO RESPETO ¿USTED LO VE JUGAR A RIQUELME?
-- Crónica TV

Alberto Valverde

unread,
Feb 22, 2006, 1:43:37 PM2/22/06
to turbo...@googlegroups.com
Yep, most widgets let you override most init parameters at display time.

Allberto

Olli Wang

unread,
Feb 22, 2006, 10:10:50 PM2/22/06
to TurboGears
could u tell my how to change the options at "display-time"?

Michele Cella

unread,
Feb 23, 2006, 4:40:36 AM2/23/06
to TurboGears
Olli Wang wrote:
> could u tell my how to change the options at "display-time"?

Pass an option parameter to the display method of your form, if you
have a field named "type" that's a SelectionField (like
SingleSelectField, MultipleSelectField, RadioButtonList and
CheckBoxList) you can for example pass a dict like this from the
controller:

new_options = dict(type=[(1, "Java"), (2, "Ruby")])

and then:

form.display(options=new_options)

By the way even using a callable changes the options at display time
since that's when it's called.

For further reference take a look at our tests:

http://trac.turbogears.org/turbogears/browser/trunk/turbogears/widgets/tests/test_widgets.py#L229

Ciao
Michele

Olli Wang

unread,
Feb 24, 2006, 10:52:56 AM2/24/06
to TurboGears
thanks. does it can set default value like that? i want use the same
form to deal with "add new" and "edit post" like wiki20 tutorial. i
have no idea how to use it.

Michele Cella

unread,
Feb 24, 2006, 12:52:21 PM2/24/06
to TurboGears

You can set the default value only at instantation time.

But you can pass the value to be displayed on the first form display by
using the same method as for options, for example if you have a form
like this:

class PageFormFields(WidgetsDeclaration):
page = TextField()
languages = MultipleSelectField(options=[(1, "Python"), (2,
"C"), (3, "Java")])

form = TableForm(fields=PageFormFields())

you should use:

form_values = dict(page="pagename", languages=[1,2])

The you display your for form in this way:

form(value=form_values, options=...)

Ciao
Michele

Olli Wang

unread,
Feb 24, 2006, 11:08:17 PM2/24/06
to TurboGears
oh yes! that's what I need. thank u Michele :)

Jorge Godoy

unread,
Feb 28, 2006, 3:39:04 PM2/28/06
to turbo...@googlegroups.com
"Michele Cella" <michel...@gmail.com> writes:

I've been trying to do that for forms. How would you pass just new options
for some widgets inside, for example, a TableForm?

Example:

================================================================================
def unidades():
unidades = [[unidade.id, unidade.simbolo]
for unidade in model.Unidade.select(
orderBy = model.Unidade.q.simbolo,
)]
return unidades

formulario_conversao_unidades_de_medida = widgets.TableForm(
[
widgets.SingleSelectField(name = 'origem',
label = lazy_gettext('Unidade de Origem'),
css_classes = ['required'],
validator = validators.Int(not_empty = True),
options = unidades(),
),
widgets.SingleSelectField(name = 'destino',
label = lazy_gettext('Unidade de Destino'),
css_classes = ['required'],
validator = validators.Int(not_empty = True),
options = unidades(),
),
widgets.TextField(attrs = {'size':16, 'maxlength':15},
name = 'multiplicador',
label = lazy_gettext('Fator Multiplicador'),
css_classes = ['required'],
validator = validators.Number(not_empty = True),
),
widgets.HiddenField(name = 'conversao_unidade_id',
validator = validators.Int(if_empty = None),
),
],
)
================================================================================

Having it like this, if some new unit ('unidade') is added or removed the
value is either absent or present, depending on the case, what is
undesirable. The user never sees what is on tha database at the exact moment
he "opens" the page.

I've tried this in my controller:

================================================================================
for field in formulario_conversao_unidades_de_medida.widgets['fields']:
if field.name in ['origem', 'destino']:
field.options = unidades()
================================================================================

But then I get an exception:

================================================================================
Traceback (most recent call last):
File "/usr/lib/python2.4/site-packages/CherryPy-2.2.0beta-py2.4.egg/cherrypy/_cphttptools.py", line 99, in _run
self.main()
File "/usr/lib/python2.4/site-packages/CherryPy-2.2.0beta-py2.4.egg/cherrypy/_cphttptools.py", line 247, in main
body = page_handler(*virtual_path, **self.params)
File "<string>", line 3, in index
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 212, in expose
tg_format, html, fragment, *args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/database.py", line 218, in run_with_transaction
retval = func(*args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 230, in _execute_func
output = errorhandling.try_call(func, *args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 62, in try_call
output = func(self, *args, **kw)
File "/home/godoy/empresa/clientes/latam/Site-Amostras/siteamostras/conversoes_unidades.py", line 48, in index
return self.conversoesunidades(conversao_unidade_id)
File "<string>", line 3, in conversoesunidades
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 207, in expose
output = _execute_func(func, tg_format, html, fragment,
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/controllers.py", line 230, in _execute_func
output = errorhandling.try_call(func, *args, **kw)
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/errorhandling.py", line 62, in try_call
output = func(self, *args, **kw)
File "<string>", line 3, in conversoesunidades
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/identity/conditions.py", line 232, in require
return fn(self, *args, **kwargs)
File "/home/godoy/empresa/clientes/latam/Site-Amostras/siteamostras/conversoes_unidades.py", line 62, in conversoesunidades
field.options = unidades()
File "/home/godoy/desenvolvimento/python/TurboGears/trunk/turbogears/widgets/base.py", line 281, in __setattr__
raise ValueError, \
ValueError: It is not threadsafe to modify widgets in a request
================================================================================


I've also tried this in my controller:

================================================================================
data = dict(options = dict(origem = unidades(), destino = unidades()))
================================================================================

while having

================================================================================
<span py:replace="formulario.display(data, action='%s/update/' % root_link, method = 'post')" />
================================================================================

in my template... But it didn't work either.

What is the correct way, in this case, to update my data so that it is
threadsafe and dynamic?


TIA,
--
Jorge Godoy <jgo...@gmail.com>

Jorge Godoy

unread,
Feb 28, 2006, 3:53:09 PM2/28/06
to turbo...@googlegroups.com
Jorge Godoy <jgo...@gmail.com> writes:

> I've tried this in my controller:
>
> ================================================================================
> for field in formulario_conversao_unidades_de_medida.widgets['fields']:
> if field.name in ['origem', 'destino']:
> field.options = unidades()
> ================================================================================

Using

================================================================================
formulario_conversao_unidades_de_medida.field_for('origem').options = unidades()
================================================================================

gives me the same exception on thread (un)safety.


--
Jorge Godoy <jgo...@gmail.com>

Jorge Godoy

unread,
Feb 28, 2006, 4:01:51 PM2/28/06
to turbo...@googlegroups.com
Jorge Godoy <jgo...@gmail.com> writes:

Oops! My bad here.

I have to pass it like 'unidades' instead of 'unidades()' for the options
value. If I pass the callable it works as expected.

Sorry to bother ;-)

--
Jorge Godoy <jgo...@gmail.com>

Michele Cella

unread,
Feb 28, 2006, 4:04:49 PM2/28/06
to TurboGears
Jorge Godoy wrote:
> I've been trying to do that for forms. How would you pass just new options
> for some widgets inside, for example, a TableForm?
>
> Example:
>
> ================================================================================
> def unidades():
> unidades = [[unidade.id, unidade.simbolo]
> for unidade in model.Unidade.select(
> orderBy = model.Unidade.q.simbolo,
> )]
> return unidades
>
> formulario_conversao_unidades_de_medida = widgets.TableForm(
> [
> widgets.SingleSelectField(name = 'origem',
> label = lazy_gettext('Unidade de Origem'),
> css_classes = ['required'],
> validator = validators.Int(not_empty = True),
> options = unidades(),
> ),

Hi Jorge,

can you try to change unidades() to be unidades, we want a callable not
what the function returns, that function will then be called every time
at display to update options dynamically.

Ciao
Michele

Michele Cella

unread,
Feb 28, 2006, 4:08:58 PM2/28/06
to TurboGears
Jorge Godoy wrote:
> Oops! My bad here.
>
> I have to pass it like 'unidades' instead of 'unidades()' for the options
> value. If I pass the callable it works as expected.
>

Great, just replied with the same correction.

> Sorry to bother ;-)
>

No problem at all! :-)

CIao
Michele

Reply all
Reply to author
Forward
0 new messages