Python Flask WTForm SelectField with Enum values 'Not a valid choice' upon validation

♀尐吖头ヾ 提交于 2019-12-24 09:03:54

问题


My Python Flask app is using WTForms with built in python Enum support. I'm attempting to submit a form (POST) where a SelectField is populated by all values of a Enum.

When I hit 'Submit' i'm given the error, 'Not a valid choice.' This seems strange because when checking the values of the incoming form, the form seemingly does contain a valid choice from the list of Enum values provided.

I'm using a subclass of Enum named AJBEnum which is formatted like so:

class UserRole(AJBEnum):
    admin = 0
    recipient = 1

I chose to do this because I use many Enums through the project and wanted to write a helper function that gathers all choices and formats them WTForm SelectField tuple friendly. AJBEnum is formatted like so:

class AJBEnum(Enum):

    @classmethod
    def choices(cls, blank=True):
        choices = []
        if blank == True:
            choices += [("", "")]
        choices += [(choice, choice.desc()) for choice in cls]
        return choices

Which means I can give WTForms all choices for UserRole during the creating of the SelectField like so:

role = SelectField('Role', choices=UserRole.choices(blank=False), default=UserRole.recipient)

Note the function parameter blank provides an additional blank SelectField option in case the SelectField is optional. In this case, it is not.

When I hit the Submit button I check the incoming incoming request in my routes and by printing the form.data i'm given this content:

{'email': 'abc@gmail.com', 'password': 'fake', 'plan': 'A', 'confirm': 'fake', 'submit': True, 'id': None, 'role': 'UserRole.recipient'}

As you can see, it appears WTForms has stringified UserRole.recipient. Is there a way to coerce WTForms into converting the incoming POST request value back to the Enum value that it was intended to be?


回答1:


Is there a way to coerce WTForms

The argument you're looking for is actually called coerce, and it accepts a callable that converts the string representation of the field to the choice's value.

  1. The choice value should be an Enum instance
  2. The field value should be str(Enum.value)
  3. The field text should be Enum.name

To accomplish this, I've extended Enum with some WTForms helpers:

class FormEnum(Enum):
    @classmethod
    def choices(cls):
        return [(choice, choice.name) for choice in cls]

    @classmethod
    def coerce(cls, item):
        return cls(int(item)) if not isinstance(item, cls) else item

    def __str__(self):
        return str(self.value)

You can then edit a FormEnum derived value using a SelectField:

role = SelectField(
        "Role",
        choices = UserRole.choices(),
        coerce = UserRole.coerce)


来源:https://stackoverflow.com/questions/43160780/python-flask-wtform-selectfield-with-enum-values-not-a-valid-choice-upon-valid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!