Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handling an empty / None option in selects. #64

Open
TrilceAC opened this issue Feb 4, 2019 · 2 comments
Open

Handling an empty / None option in selects. #64

TrilceAC opened this issue Feb 4, 2019 · 2 comments

Comments

@TrilceAC
Copy link

TrilceAC commented Feb 4, 2019

Last week I reported an issue into wtforms-alchemy regarding its inability to render a CountryField with an empty option for those cases when the user does not want to select one and None should be stored. But it seems to me that the place to report it might be this project because it seems that the real issue is how wtforms-components should render a None option for selects.

On the issue already mentinoed I tried to add an empty option as you see in the example that I provided. On the following different case, with different data type, the issue is just the same:

class Person(Model):
    id = Column(Integer, primary_key=True, index=True)
    uid = Column(Integer, unique=True, nullable=True, index=True)
    guid = Column(
        Integer,
        nullable=True,
        index=True,
        info={
            'label': 'UNIX GID',
            'description': 'Id del grupo de UNIX al que pertenece el usuario.',
            'choices': [
                (None, ''),
                (500, '500: IT'),
                (502, '502: Management'),
            ]
        }
    )

Note that I'm using sqlalchemy-utils and this model is translated to a form, being guid a select with three options. At the time of rendering the form, this fails because wtforms-components tries to coerce None into int, which causes an exception on line 270.

try:
coerce_func, data = mixed
except TypeError:
selected = mixed
else:
if isinstance(data, list) or isinstance(data, tuple):
selected = coerce_func(value) in data
else:
selected = coerce_func(value) == data

wtforms_components/widgets.py", line 270, in render_option
selected = coerce_func(value) == data
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

Trying options based on strings raises a different exception on the same line because it doesn't know how to covnert the option into a int. Supose that che choice is ('', '') or ('None', ''), in any of both cases the problem is that it is unable to convert the option into an int:

/wtforms_components/widgets.py", line 270, in render_option
selected = coerce_func(value) == data
ValueError: invalid literal for int() with base 10: ''

Would it be a reasonable solution to test whether the given value is None, and if so, do not perform the data coercion? I'm happy to help if this approach seems reasonable.

@TrilceAC
Copy link
Author

TrilceAC commented Feb 4, 2019

The following modification to the commented code allows the rendering of the select. Not sure whether this is adequate:

        else:
            if isinstance(data, list) or isinstance(data, tuple):
                selected = coerce_func(value) in data
            elif value is None:
                selected = None
            else:
                selected = coerce_func(value) == data

This is a way to render such an option, but when the form is submitted, how should be handled this option if it is the selected one? I only get validation error when this is the case.

@TrilceAC TrilceAC changed the title Rendering select that should have an empty / None option causes exceptions Handling an empty / None option in selects. Feb 4, 2019
@TrilceAC
Copy link
Author

TrilceAC commented Feb 5, 2019

Digging a bit on the code, I found that one can write custom coerce functions on the info dict used by wtforms-alchemy. This did the trick:

class Person(Model):
    id = Column(Integer, primary_key=True, index=True)
    uid = Column(Integer, unique=True, nullable=True, index=True)
    guid = Column(
        Integer,
        nullable=True,
        index=True,
        info={
            'label': 'UNIX GID',
            'description': 'Unix group id of the user.',
            'coerce': lambda x: None if x == 'None' or x is None else int(x),
            'choices': [
                (None, ''),
                (500, '500: IT'),
                (502, '502: Management'),
            ]
        }
    )

Not sure anymore whether this should be in the realm of WTForms-Components or in the realm of WTForms-Alchemy, but I think that somehow there should be an easier way to allow None in a select field when the Column is nullable, i.e. nullable=True

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant