Skip to content

enum TypeError: object of type 'enumVar' has no len() #162

Description

@adorsett

Using Flask, SQLAlchemy, WTForms against an MySQL DB.

Imports

from flask import Flask, render_template, request, url_for, flash, redirect
from waitress import serve
from flask_sqlalchemy import SQLAlchemy
from flask_wtf import FlaskForm
from wtforms_alchemy import model_form_factory, ModelFieldList
from wtforms.fields import FormField, SelectField
from sqlalchemy import Column, Integer, String, ForeignKey, Date, Enum, Table
from sqlalchemy.orm import declarative_base, relationship, sessionmaker, aliased, backref, Query
import enum

Have an Enumerated Type Field that's stored in MySQL as a native Enum Column

class Category(enum.Enum):
    Cat1 = 'Cat1'
    Cat2 = 'Cat2'
    Cat3 = 'Cat3'

Model Definition

class Label(Base):
    __tablename__ = "labels"
    id = Column(Integer, primary_key=True)
    abbreviation = Column(String(10), nullable=False)
    label = Column(String(50), nullable=False)
    category = Column(Enum(Category))

Setting up Globals

db = SQLAlchemy(app)
Base = db.Model
BaseModelForm = model_form_factory(FlaskForm)

class ModelForm(BaseModelForm):
    @classmethod
    def get_session(self):
        return db.session

Use ModelForm to Auto-Build Form

class LabelForm(ModelForm):
    class Meta:
        model = Label
        strip_string_fields = True
        include_foreign_keys = True

Flask Handler Snippet

    label = Label()
    success = False

    if request.method == 'POST':
        form = LabelForm(request.form, obj=label)
        print(request.form)
        if form.validate():
            form.populate_obj(label)
            db.session.add(label)
            db.session.commit()
            success = True
            flash("Label Saved", 'notice')
        else:
            flash(f"Form Failed Validation: {form.errors}", 'error')

The Form in the HTML Template

    <form method="post">
        {{ form.hidden_tag() }}
        {% for field in form %}
          {% if field.widget.input_type != 'hidden' %} {{ field.label }} {% endif %}
          {{ field }}
        {% endfor %}

        <input type="submit" value="Save">
        <input type="reset" value="Reset">

The Form will show perfectly using the above template when selecting a pre-existing DB entry by ID. If I try to "Edit" that entry by simply clicking "Save" I get the following traceback.

adminui  | Traceback (most recent call last):
adminui  |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 2528, in wsgi_app
adminui  |     response = self.full_dispatch_request()
adminui  |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1825, in full_dispatch_request
adminui  |     rv = self.handle_user_exception(e)
adminui  |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1823, in full_dispatch_request
adminui  |     rv = self.dispatch_request()
adminui  |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1799, in dispatch_request
adminui  |     return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
adminui  |   File "/src/src/app.py", line 246, in clearancedetail
adminui  |     if form.validate():
adminui  |   File "/usr/local/lib/python3.8/site-packages/wtforms/form.py", line 329, in validate
adminui  |     return super().validate(extra)
adminui  |   File "/usr/local/lib/python3.8/site-packages/wtforms/form.py", line 146, in validate
adminui  |     if not field.validate(self, extra):
adminui  |   File "/usr/local/lib/python3.8/site-packages/wtforms/fields/core.py", line 242, in validate
adminui  |     stop_validation = self._run_validation_chain(form, chain)
adminui  |   File "/usr/local/lib/python3.8/site-packages/wtforms/fields/core.py", line 262, in _run_validation_chain
adminui  |     validator(form, self)
adminui  |   File "/usr/local/lib/python3.8/site-packages/wtforms/validators.py", line 138, in __call__
adminui  |     length = field.data and len(field.data) or 0
adminui  | TypeError: object of type 'Category' has no len()

I added a len() method to the Enum object and that cleared the Traceback but then I get a data validation error when calling form.validate().

This works but I want my Enum definitions stored in a central place and not in the middle of my Model definition:

class Label(Base):
    # ...
    category = Column(Enum("Cat1", "Cat2", "Cat3", name="Category", default="Cat1"))

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions