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"))
Using Flask, SQLAlchemy, WTForms against an MySQL DB.
Imports
Have an Enumerated Type Field that's stored in MySQL as a native Enum Column
Model Definition
Setting up Globals
Use ModelForm to Auto-Build Form
Flask Handler Snippet
The Form in the HTML Template
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.
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: