I am glad to give you code examples (some follow at the end of this
message), but I may not have stated the problem as clearly as
possible. I am concerned with how the SelectionField *displays* its
data, not how it *validates* incoming data. (Validation works just
fine). I provide the SingleSelectField with a Python value to be
*displayed*, and it (should, I believe) either
a) Convert that python value to a string using from_python and compare
it with the <option>s to see which one is selected, OR
b) Convert each <option> value to a corresponding Python value using
to_python to see which one is selected.
What it actually *does*, however, is
c) Try to convert the *python value* to another *python value* using
to_python and compare it with the <option>s to see which one is
selected (obviously never matching anything)
Before I get into my specific code, here's a quick contrived example
of how it currently works and how I think it should work:
@expose(template='.foo')
def test(self):
class TestObj(object):
def __init__(self):
self.testval='three:3'
class TestValidator:
def to_python(self, value, state=None):
log.info('Call to_python on value "%s"', value)
result = {'1':'one:1',
'2':'two:2',
'3':'three:3',
'4':'four:4',
'5':'five:5' }.get(value, None)
if result is None: raise Invalid('Bad Value', value,
state)
return result
def from_python(self, value, state=None):
log.info('Call from_python on value "%s"', value)
name, id = value.split(':')
return id
class TestFields(WidgetsList):
testval=SingleSelectField(
'testval', label='Test Value',
options=[('1','one'), ('2','two'), ('3','three'),
('4','four')],
validator=TestValidator())
test_form = TableForm('test', fields=TestFields())
return dict(form=test_form,
item=TestObj())
The template has the expected ${form.display(item)}. If I use the
widgets code as-is, I get the following log output:
...
2007-03-04 07:00:58,853 tutornet.controllers INFO Call to_python on
value "three:3"
2007-03-04 07:00:58,982 tutornet.controllers INFO Call to_python on
value "three:3"
2007-03-04 07:00:58,982 tutornet.controllers INFO Call to_python on
value "three:3"
2007-03-04 07:00:58,983 tutornet.controllers INFO Call to_python on
value "three:3"
And of course, no option in the select field is ever selected. If I
switch the widgets code to call from_python, however, I get the
following log output:
...
2007-03-04 07:04:34,820 tutornet.controllers INFO Call from_python on
value "three:3"
2007-03-04 07:04:34,822 tutornet.controllers INFO Call from_python on
value "three:3"
2007-03-04 07:04:34,823 tutornet.controllers INFO Call from_python on
value "three:3"
2007-03-04 07:04:34,825 tutornet.controllers INFO Call from_python on
value "three:3"
And the third option is correctly selected.
Now in my *actual* code, I have a validator which converts incoming
ids into objects using the SA .get method:
class SQL(FancyValidator):
not_empty=True
messages = dict(
integer='Please enter an integer value',
notFound='The %(model)s with ID %(value)s was not found')
def __init__(self, model, method='get', base=Int, *l, **kw):
self.model = model
self.method = method
self.base = base
self.l = l
self.kw = kw
self._bound = False
if isinstance(model, str):
##print 'Delay binding of SQL validator on %s' % model
pass
else:
self._bind()
def _bind(self):
if isinstance(self.model, str):
self.model = classregistry.findClass(self.model)
self.method = getattr(self.model, self.method)
if 'if_empty' in self.kw:
self.not_empty=False
self.base = self.base(*self.l, **self.kw)
self._bound = True
def _to_python(self, value, state):
if not self._bound:
self._bind()
value = self.base.to_python(value)
try:
return self.method(value)
except SQLObjectNotFound:
raise Invalid(self.message('notFound', state,
model=self.model.__name__,
value=value),
value, state)
def _from_python(self, value, state):
if isinstance(value, int): keyval = value
else: keyval = value.id
return Int().from_python(keyval, state)
This is used in a form as follows:
class CurriculumItemFields(WidgetsList):
type=SingleSelectField(label='Item Type',
options=lambda: [(t.id, t.name) for t in
model.ItemType.select()],
validator=SQL(model.ItemType))
name=TextField()
description=TextArea(attrs=dict(rows=2))
textile=TextArea(label='Content', attrs=dict(rows=10),
validator=UnicodeString(if_empty=''))
attachment=FileField()
edit_curriculum_item_form=TableForm(
'curriculum_item_form',
fields=CurriculumItemFields(),
action='./save',
submit_text='Save Curriculum Item')
In my controller, I retrieve a CurriculumItem (which has a "type_id"
foreign key into ItemType's table) from the database and then send it
to the template as (simplified):
return dict(item=model.CurriculumItem.get(id),
form=edit_curriculum_item_form)
When I attempt to do form.display(item) inside the Kid template,
however, it does not correctly set the "selected" attr on the correct
option (it does not set *any* "selected" attrs, in fact.) This is
because it is trying to call SQL(model.ItemType).to_python(<ItemType
instance ...>) inside _is_option_selected when rendering the widget.
Replacing the to_python with from_python works beautifully, correctly
coercing the value both in valididating the form and when rendering
it.
On Mar 3, 12:12 pm, "Diez B. Roggisch" <[EMAIL PROTECTED]>
wrote:
> Rick schrieb:
>
> > Hey all,
>
> > I was working with a SingleSelectField and a complicated validator and
> > noticed that, when the widget is rendering itself, it calls
> > _is_option_selected, which in turn calls the validator's "to_python".
> > It seems that "from_python" should actually be called, since we're
> > starting with a Python value and ending up with a form value to
> > compare against. (Plus, it makes my code work when I switch them.)
> > I'm not sure if this should be created as a ticket/patch/whatever, or
> > if my understanding is just wrong, so if anyone could point me in the
> > right direction, it would be greatly appreciated.
>
> No, it shouldn't, as the validator will work on a request-parameter
> (always a string in the first place) but should result in something that
> is in the options list, e.g. an id from an object.
>
> If you show us some code, we might be able to spot why things don't work
> for you.
>
> Diez
--~--~---------~--~----~------------~-------~--~----~
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?hl=en
-~----------~----~----~----~------~----~------~--~---