Validating a select box

7 views
Skip to first unread message

Mark

unread,
Mar 2, 2010, 6:20:26 AM3/2/10
to pylons-discuss
Hi guys,

Which validator should I use for a select box, where the 'value' of
the option selected is a number?

For instance:

<select name="type_id" id="type_id">
<option value="6">A</option>
<option value="7">B</option>
<option selected="selected" value="2">C</option>
</select>

I am pulling the values to populate the select box from the database.
Should I use OneOf or should I use Int?

I am currently using OneOf, but the problem with it is that it is
reading my inputs as unicode strings when it should really be an
integer.

On a similar note:

What about multi-select boxes? Should those also use the same
validator as select boxes like above?

-Mark

Mike Orr

unread,
Mar 2, 2010, 2:08:13 PM3/2/10
to pylons-...@googlegroups.com
On Tue, Mar 2, 2010 at 3:20 AM, Mark <zheng...@gmail.com> wrote:
> Hi guys,
>
> Which validator should I use for a select box, where the 'value' of
> the option selected is a number?
>
> For instance:
>
> <select name="type_id" id="type_id">
> <option value="6">A</option>
> <option value="7">B</option>
> <option selected="selected" value="2">C</option>
> </select>
>
> I am pulling the values to populate the select box from the database.
> Should I use OneOf or should I use Int?

I made a combined validator for that. Here it is, along with a couple
other useful validators.

===
import formencode.validators as v
class SelectInt(v.FancyValidator):
"""A combination of the Int and OneOf validators with a custom message"""
__unpackargs__ = ("list",)
not_empty = True

def _to_python(self, value, state):
try:
return int(value)
except ValueError:
self._invalid(value, state)

_from_python = _to_python

def validate_python(self, value, state):
if value not in self.list:
self._invalid(value, state)

def _invalid(self, value, state):
message = "please choose an item from the list"
raise v.Invalid(message, value, state)
===

By the way, a couple other validators I find useful:

===
# For checkboxes
class Boolean(v.StringBoolean):
if_missing = False

# For integer fields
class Int(v.Int):
messages = {
"integer": _("Please enter a numeric value"),
}
===


> What about multi-select boxes?  Should those also use the same
> validator as select boxes like above?

I'm not sure about that. It would probably be best to ask on the
FormEncode list. FormEncode has a few ways to handle multiple values,
and I'm not sure which one would be appropriate for a multiselect.

--
Mike Orr <slugg...@gmail.com>

Jonathan Vanasco

unread,
Mar 2, 2010, 2:25:21 PM3/2/10
to pylons-discuss
Mike danced around a good point above which he didn't explictly
mention - for most formencode validators the results will be Strings
-- both in the validator and form_result. So they may mess up your
comparisons or validations.

Mark

unread,
Mar 2, 2010, 8:28:06 PM3/2/10
to pylons-discuss
Thank you for the detailed explanation.

One thing: What does __unpackargs__ do? I don't see this being used
everytime, is it something optional? What do you usually supply it
with?

On Mar 3, 3:08 am, Mike Orr <sluggos...@gmail.com> wrote:

> Mike Orr <sluggos...@gmail.com>

Mike Orr

unread,
Mar 2, 2010, 10:02:44 PM3/2/10
to pylons-...@googlegroups.com
I don't understand Johnathan's point. Most fields are strings, yes.
But I assumed Mark wanted integers. That's what SelectInt is for.
Otherwise you can just use OneOf.

On Tue, Mar 2, 2010 at 5:28 PM, Mark <zheng...@gmail.com> wrote:
> Thank you for the detailed explanation.
>
> One thing:  What does __unpackargs__ do? I don't see this being used
> everytime, is it something optional?  What do you usually supply it
> with?

``.__unpackargs__`` tells how many positional args the validator
constructor takes, and which attributes they should be assigned to.
FancyValidator takes no args, but custom subclasses might want to, to
specify constraints like length, minimum value, type, etc.

It's implemented by formencode.declarative.Declarative, which is a
superclass of Validator. You can use it in your own classes to avoid
writing a boilerplate .__init__ method.

Someday there will be a FormEncode manual that mentions it. Until
then, I'd recommend reading the docstrings of all the FormEncode
modules. Note that some of the validators seem (to me) old or
useless, so if something looks strange, it probably is.

--
Mike Orr <slugg...@gmail.com>

Mike Orr

unread,
Mar 2, 2010, 10:08:18 PM3/2/10
to pylons-...@googlegroups.com
On Tue, Mar 2, 2010 at 7:02 PM, Mike Orr <slugg...@gmail.com> wrote:
> I don't understand Johnathan's point.  Most fields are strings, yes.
> But I assumed Mark wanted integers.  That's what SelectInt is for.
> Otherwise you can just use OneOf.
>
> On Tue, Mar 2, 2010 at 5:28 PM, Mark <zheng...@gmail.com> wrote:
>> Thank you for the detailed explanation.
>>
>> One thing:  What does __unpackargs__ do? I don't see this being used
>> everytime, is it something optional?  What do you usually supply it
>> with?
>
> ``.__unpackargs__`` tells how many positional args the validator
> constructor takes, and which attributes they should be assigned to.
> FancyValidator takes no args, but custom subclasses might want to, to
> specify constraints like length, minimum value, type, etc.

More specifically. FancyValidator takes no *positional* args. It takes
keyword args which override its class attributes. That's another
feature of Declarative: keyword args set same-name attributes.

--
Mike Orr <slugg...@gmail.com>

Jonathan Vanasco

unread,
Mar 3, 2010, 1:57:00 AM3/3/10
to pylons-discuss
sorry, i'm sick and really loopy...

let me rephrase ( and this may have changed since last i tested a
while bac )

everything that comes through request.params / submitted to your
pylons app is a string

there are some neat validators that will handle conversions for you,
so everything is seamless / painless

however, lets say that your select field has only these valid ids,
which you know of as constants from your database:

valid_ids= [0,1,2,3,5,8,13,21,34]

but if you choose something like:
valid= formencode.validators.OneOf( valid_ids )

most will be invalid , because this is really what we want:
valid= formencode.validators.OneOf( [ "%s"%i for i in valid_ids] )

so...

enter things like mike's neat validator, which is """A combination of


the Int and OneOf validators with a custom message"""

and now you're able to do
valid= formencode.validators.SelectInt( valid_ids )

Ian Wilson

unread,
Mar 3, 2010, 1:07:52 PM3/3/10
to pylons-discuss
Just an additional note, you can combine validators to solve the int/
str problem using All or Any, (from formencode import All, Any) such
as:

my_select = All(OneOf([0,1,2,3,5,8,13,21,34]), Int())

So here Int converts the string to an integer and that integer gets
checked by OneOf.
You probably noticed that All actually works backwards, which I think
maybe is a long standing bug.

Mark

unread,
Mar 5, 2010, 3:58:22 AM3/5/10
to pylons-discuss
Hi Mike,

I have a form with some hidden fields that were dynamically added by
another operation going on in the same page. These hidden fields were
formed with values that were already validated. I do not wish to
validate this again. Can I use __unpackargs__ to specify the fields I
want to validate and just leave the ones that I don't want out of the
list? Is this what __unpackargs__ does?

So for example I have a form with first_name, last_name, course_name,
enrollment_limit,....and some hidden fields (these are also repeating
fields) like: sess-1.name, sess-1.start, sess-2.name,
sess-2.start....and so on. What do I have to do to prevent
sess-1.name, sess-1.start, sess-2.name, sess-2.start from validating,
but still I want them to be added to my object.

Seems like the only solution is to re-validate them and use
Formencode's solution of repeating fields to solve this....

-Mark

On Mar 3, 11:02 am, Mike Orr <sluggos...@gmail.com> wrote:
> I don't understand Johnathan's point.  Most fields are strings, yes.
> But I assumed Mark wanted integers.  That's what SelectInt is for.
> Otherwise you can just use OneOf.
>

> On Tue, Mar 2, 2010 at 5:28 PM, Mark <zhengha...@gmail.com> wrote:
> > Thank you for the detailed explanation.
>
> > One thing:  What does __unpackargs__ do? I don't see this being used
> > everytime, is it something optional?  What do you usually supply it
> > with?
>
> ``.__unpackargs__`` tells how many positional args the validator
> constructor takes, and which attributes they should be assigned to.
> FancyValidator takes no args, but custom subclasses might want to, to
> specify constraints like length, minimum value, type, etc.
>
> It's implemented by formencode.declarative.Declarative, which is a
> superclass of Validator. You can use it in your own classes to avoid
> writing a boilerplate .__init__ method.
>
> Someday there will be a FormEncode manual that mentions it. Until
> then, I'd recommend reading the docstrings of all the FormEncode
> modules.  Note that some of the validators seem (to me) old or
> useless, so if something looks strange, it probably is.
>
> --

> Mike Orr <sluggos...@gmail.com>

Mike Orr

unread,
Mar 5, 2010, 6:04:19 AM3/5/10
to pylons-...@googlegroups.com
On Fri, Mar 5, 2010 at 12:58 AM, Mark <zheng...@gmail.com> wrote:
> Hi Mike,
>
> I have a form with some hidden fields that were dynamically added by
> another operation going on in the same page.  These hidden fields were
> formed with values that were already validated.  I do not wish to
> validate this again.  Can I use __unpackargs__ to specify the fields I
> want to validate and just leave the ones that I don't want out of the
> list?  Is this what __unpackargs__ does?

__unpackargs__ is just a convenience for setting instance attributes.
It doesn't do anything more than that. It's up to the rest of the
class code to do something with the values.

> So for example I have a form with first_name, last_name, course_name,
> enrollment_limit,....and some hidden fields (these are also repeating
> fields) like: sess-1.name, sess-1.start, sess-2.name,
> sess-2.start....and so on.  What do I have to do to prevent
> sess-1.name, sess-1.start, sess-2.name, sess-2.start from validating,
> but still I want them to be added to my object.

> Seems like the only solution is to re-validate them and use
> Formencode's solution of repeating fields to solve this....

Why not use the String validator? It always succeeds.

Or you can define just the regular fields, and use
``allow_extra_fields=True; filter_extra_fields=False` to pass through
the other fields (the 'sess' fields). But:

* It's arguably bad form to use fields that don't have an explicit
validator. It suggests you're not security-controlling those fields.

* I'm not sure if NestedVariables() will turn "extra" fields into a
list-of-dicts structure for you. I guess it would, because it's
separate from the schema.

The "Form" validator class claims to do something with
partially-validated forms, so that you can run another validator even
if the first one finds errors, and pass through the values that did
validate successfully. But I've never understood it, so I don't know
if it would address your situation. Likewise I've never used
ForEach(), so I can only guess how it works.

--
Mike Orr <slugg...@gmail.com>

Mark

unread,
Mar 7, 2010, 9:36:43 AM3/7/10
to pylons-discuss
I'm sorry guys, maybe it's just me, but I'm having tons of problems
with my forms:

I have a new() and create() just like what the book says. My new()
action basically just renders my form. My create() action is as such:

@validate(schema=NewClassForm(), form='new', post_only=True,
on_get=True, auto_error_formatter=custom_formatter)
def create(self):
"""
Add a new class with sessions and save it to the database
"""

My Schema is the following:

class NewClassForm(formencode.Schema):
allow_extra_fields = True
filter_extra_fields = True
pdb.set_trace()
pre_validators = [variabledecode.NestedVariables()]
course = SelectIntCourseValidator(not_empty=True) ...etc.


As stated in my previous posts, I have a form with some HIDDEN input
fields. I created a ForEach() and all of the Repeating Fields stuff
for the hidden input fields.

When I submit my form (using POST), the new() action is always
run....instead of create(). This must mean there's something wrong
with my form right?

Can someone help me out with this? What's going on? Why do I always
get redirected to my new() action? How do I debug this? I tried
placing pdb.set_trace() in my Schema, but it never seems to get run at
all.

On Mar 5, 7:04 pm, Mike Orr <sluggos...@gmail.com> wrote:

> Mike Orr <sluggos...@gmail.com>

Mark

unread,
Mar 7, 2010, 10:01:35 AM3/7/10
to pylons-discuss
As a a supplement, my hidden fields are structured as such:

<input type="hidden" value="3" name="num_sessions"
id="num_sessions">
<input type="hidden" value="12 Mar 2010 " name="sess-0.date"
id="sess-0.date">
<input type="hidden" value="12:00" name="sess-0.start_time"
id="sess-0.start_time">
<input type="hidden" value="13:00" name="sess-0.end_time"
id="sess-0.end_time">
<input type="hidden" value="TB 236 - Sound Design"
name="sess-0.location" id="sess-0.location">
<input type="hidden" value="5545" name="sess-0.location_id"
id="sess-0.location_id">
<input type="hidden" value="Chris Yeo" name="sess-0.instructor"
id="sess-0.instructor">
<input type="hidden" value="3101" name="sess-0.instructor_id"
id="sess-0.instructor_id">
<input type="hidden" value="fdsfds" name="sess-0.description"
id="sess-0.description">
<input type="hidden" value="13 Mar 2010 " name="sess-1.date"
id="sess-1.date">
<input type="hidden" value="12:00" name="sess-1.start_time"
id="sess-1.start_time">
<input type="hidden" value="13:00" name="sess-1.end_time"
id="sess-1.end_time">
<input type="hidden" value="TB 236 - Sound Design"
name="sess-1.location" id="sess-1.location">
<input type="hidden" value="5545" name="sess-1.location_id"
id="sess-1.location_id">
<input type="hidden" value="Chris Yeo" name="sess-1.instructor"
id="sess-1.instructor">
<input type="hidden" value="3101" name="sess-1.instructor_id"
id="sess-1.instructor_id">
<input type="hidden" value="fdsfds" name="sess-1.description"
id="sess-1.description">

As you can see, this conforms to how FormEncode handles repeating
fields. The hidden inputs were inserted into my form through another
form on the same page.

Now if I set filter_extra_feilds = False, does this mean all of the
above hidden fields will be ignored by the validator? If so, would
this also mean that these field values won't form the field_dictionary
(I'm referring to the self.form_result)?

Wyatt Baldwin

unread,
Mar 7, 2010, 11:31:13 AM3/7/10
to pylons-discuss
On Mar 7, 6:36 am, Mark <zhengha...@gmail.com> wrote:
> I'm sorry guys, maybe it's just me, but I'm having tons of problems
> with my forms:
>
> I have a new() and create() just like what the book says.  My new()
> action basically just renders my form.  My create() action is as such:
>
> [...]

>
> As stated in my previous posts, I have a form with some HIDDEN input
> fields.  I created a ForEach() and all of the Repeating Fields stuff
> for the hidden input fields.
>
> When I submit my form (using POST), the new() action is always
> run....instead of create().  This must mean there's something wrong
> with my form right?

Sounds like you're either submitting to the wrong URL or your routes
aren't doing what you think they are.


> Can someone help me out with this?  What's going on?  Why do I always
> get redirected to my new() action?  How do I debug this?  I tried
> placing pdb.set_trace() in my Schema, but it never seems to get run at
> all.

If you're in `new`, then `create` is never run and hence your
validator is never run. You might try some logging in your base
controller's __call__ method.

Mike Orr

unread,
Mar 7, 2010, 2:02:55 PM3/7/10
to pylons-...@googlegroups.com
On Sun, Mar 7, 2010 at 6:36 AM, Mark <zheng...@gmail.com> wrote:
> I'm sorry guys, maybe it's just me, but I'm having tons of problems
> with my forms:
>
> I have a new() and create() just like what the book says.  My new()
> action basically just renders my form.  My create() action is as such:
>
> @validate(schema=NewClassForm(), form='new', post_only=True,
> on_get=True, auto_error_formatter=custom_formatter)

Try it with just the 'schema' and 'form' arguments first and see if that works.

>    def create(self):
>        """
>        Add a new class with sessions and save it to the database
>        """
>
> My Schema is the following:
>
> class NewClassForm(formencode.Schema):
>    allow_extra_fields = True

This allows the input to contain fields not mentioned in the schema.
(Otherwise it would be a validation error.)

>    filter_extra_fields = True

'False' copies the extra fields to 'self.form_result'. 'True'
suppresses the extra fields (does not copy them to
'self.form_result').

>    pdb.set_trace()

I don't know how this behaves in a Pylons controller or validator.

If you have a custom validator (maybe make a dummy pre_validator using
FancyValidator), you can put 'raise RuntimeError' in it, which will
hopefully give you an interactive traceback. That will prove the
validator is being run (and thus that the route routed to the 'create'
method). You can't put it in the 'create' method itself because we're
still in the decorator code.

To debug routes, add the following to your INI file:

[loggers]
keys = root, routes, ...

[logger_routes]
level = DEBUG
handlers =
qualname = routes.middleware
# "level = DEBUG" logs the route matched and routing variables.

I have the following in my INI too, I don't remember why:

[logger_decorators]
level = WARN
handlers =
qualname = pylons.decorators

Setting that to DEBUG may show something useful.

--
Mike Orr <slugg...@gmail.com>

Wyatt Baldwin

unread,
Mar 7, 2010, 4:23:01 PM3/7/10
to pylons-discuss
On Mar 7, 11:02 am, Mike Orr <sluggos...@gmail.com> wrote:

> On Sun, Mar 7, 2010 at 6:36 AM, Mark <zhengha...@gmail.com> wrote:
> > I'm sorry guys, maybe it's just me, but I'm having tons of problems
> > with my forms:
>
> > I have a new() and create() just like what the book says.  My new()
> > action basically just renders my form.  My create() action is as such:
>
> > @validate(schema=NewClassForm(), form='new', post_only=True,
> > on_get=True, auto_error_formatter=custom_formatter)
>
> Try it with just the 'schema' and 'form' arguments first and see if that works.

Just to make sure I understand this, the `form` keyword indicates
where to go if validation fails, right? In that case, what I said
about "submitting to the wrong URL or [incorrect] routes" probably
isn't applicable. I guess I should read the rest of the thread before
jumping in ;)

Mike Orr

unread,
Mar 7, 2010, 10:53:21 PM3/7/10
to pylons-...@googlegroups.com
On Sun, Mar 7, 2010 at 1:23 PM, Wyatt Baldwin
<wyatt.le...@gmail.com> wrote:
> On Mar 7, 11:02 am, Mike Orr <sluggos...@gmail.com> wrote:
>> On Sun, Mar 7, 2010 at 6:36 AM, Mark <zhengha...@gmail.com> wrote:
>> > I'm sorry guys, maybe it's just me, but I'm having tons of problems
>> > with my forms:
>>
>> > I have a new() and create() just like what the book says.  My new()
>> > action basically just renders my form.  My create() action is as such:
>>
>> > @validate(schema=NewClassForm(), form='new', post_only=True,
>> > on_get=True, auto_error_formatter=custom_formatter)
>>
>> Try it with just the 'schema' and 'form' arguments first and see if that works.
>
> Just to make sure I understand this, the `form` keyword indicates
> where to go if validation fails, right?

Yes.

In that case, what I said
> about "submitting to the wrong URL or [incorrect] routes" probably
> isn't applicable. I guess I should read the rest of the thread before
> jumping in ;)

I don't know if it's applicable or not. Let's see if Mark can get any
confirmation on which routes are matched and how much of the validator
is executed.

--
Mike Orr <slugg...@gmail.com>

Reply all
Reply to author
Forward
0 new messages