-
-
Notifications
You must be signed in to change notification settings - Fork 395
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
SelectField Enum support #338
Comments
This is something we'll consider supporting and adding to the documentation, however currently In the meantime, it's possible to use them by converting the >>> from wtforms.fields import SelectField
>>> from enum import Enum
>>> class Colour(Enum):
... RED = 1
... GREEN = 2
... BLUE = 3
...
>>> SelectField(u'Favourite colour', choices=[(member.value, name.capitalize()) for name, member in Colour.__members__.items()])
<UnboundField(SelectField, ('Favourite colour',), {'choices': [(1, 'Red'), (2, 'Green'), (3, 'Blue')]})> |
@ftm how can I follow a discussion around adding enums? |
Using the above workaround, the form will not validate. |
Why was this issue closed? |
Sure, we can reopen the ticket and discuss it here. |
I also need something like this, I'm currently able to use this: from wtforms import Form, SelectField
from enum import IntEnum
class Role(IntEnum):
USER = 0
ADMIN = 1
class UserForm(Form):
user_role = SelectField("Role", choices=[(role, role.name) for role in Role]) Which almost works, as doing I'd love to see something like |
If anyone is looking for a solution, I ended up creating my own custom field class extending SelectField like this: from collections.abc import Callable
from enum import Enum
from typing import cast
from wtforms import SelectField
class EnumSelectField(SelectField):
"""Extension of ``wtforms.SelectField`` that supports Enum classes.
Note that this will mutate the passed enum class, by adding __str__ and __html__
methods (unless already present).
"""
def __init__(self, label: str, enum_cls: type[Enum], *args, **kwargs) -> None:
self._attach_functions(enum_cls)
choices = [(variant, variant.name) for variant in enum_cls]
coerce = self._coerce_enum(enum_cls)
super().__init__(
label,
*args,
choices=choices,
coerce=coerce, # type: ignore # pyright expects type[str]
**kwargs,
)
@staticmethod
def _coerce_enum(enum_type: type[Enum]) -> Callable[[Enum | str], Enum]:
"""Create a custom coerce function for enums used in ``wtforms.SelectField``."""
def coerce(name: Enum | str) -> Enum:
if isinstance(name, enum_type):
return name
name = cast(str, name) # pyright doesn't auto-infer this for some reason
try:
return enum_type[name]
except KeyError:
raise ValueError(name)
return coerce
@staticmethod
def _attach_functions(enum_type: type[Enum]) -> None:
"""Attach the necessary __str__ and __html__ functions to the enum class.
This will only attach these functions if they're not present already.
"""
if not hasattr(enum_type, "__str__"):
enum_type.__str__ = lambda self: self.name # type: ignore
if not hasattr(enum_type, "__html__"):
enum_type.__html__ = lambda self: self.name # type: ignore It works well enough, although it is a bit hacky as it mutates the enum class you give it and adds the |
What worked for me was using class PointTypes(enum.Enum):
MUSEUM = 'museum'
SIGHT = 'sight'
# etc
# ...
def point_types_coerce(data):
logger.debug('data %s [%s]', data, type(data))
if isinstance(data, PointTypes):
return data.value
return data
class PointForm(FlaskForm):
TYPE_CHOICES = [(p.value, p.value.capitalize()) for p in PointTypes]
# ...
type = SelectField('Point type', choices=TYPE_CHOICES, coerce=point_types_coerce) |
There are a dozen of different implementations to use enums with |
Enums are part of the standard lib right now and they are becoming mainstream.
Can you do a tutorial on how we can integrate enums with SelectField?
The text was updated successfully, but these errors were encountered: