Flask-Admin创建User对象报错:'tuple' object has no attribute 'items'
Flask-Admin结合SQLAlchemy使用Enum字段时新增用户页面报错
AttributeError: 'tuple' object has no attribute 'items' 问题详情
访问后台新增用户页面 http://127.0.0.1:5000/admin/user/new/?url=/admin/user/ 时触发错误:
AttributeError: 'tuple' object has no attribute 'items'
问题出在User模型的role和gender字段使用了Enum类,而无Enum字段的Product模型在Flask-Admin中运行正常。
相关代码
models.py
from enum import Enum from sqlalchemy import Column, Integer, String, Date, ForeignKey from sqlalchemy_utils import EnumType from flask_login import UserMixin from clinic import db class Gender(Enum): MALE = 'male' FEMALE = 'female' class UserRole(Enum): ADMIN = 'admin' PATIENT = 'patient' class User(db.Model, UserMixin): id = Column(Integer, autoincrement=True, primary_key=True) username = Column(String(50), unique=True, nullable=False) password = Column(String(100), nullable=False) role = Column(EnumType(UserRole), nullable=False) name = Column(String(100)) birth = Column(Date, default=datetime.date.today) phone = Column(String(14), default="2134215567") email = Column(String(100), unique=True) gender = Column(EnumType(Gender)) address = Column(String(100), default="address") avatar = Column(String(100), default="https://res.cloudinary.com/dwvkjyixu/image/upload/v1715592288/avatars/pzh51raolcegilwmhm4g.jpg") def __str__(self): return self.username class Admin(db.Model): id = Column(Integer, ForeignKey(User.id), primary_key=True) def __str__(self): return User.query.get(self.id).name class Patient(db.Model): id = Column(Integer, ForeignKey(User.id), primary_key=True) def __str__(self): return User.query.get(self.id).name class Product(db.Model): id = Column(Integer, autoincrement=True, primary_key=True) name = Column(String(50), nullable=True ) price = Column(Integer, nullable=True) if __name__ == '__main__': from clinic import app with app.app_context(): db.create_all()
admin.py
from clinic import app, db from flask_admin import Admin from flask_admin.contrib.sqla import ModelView from clinic.models import User, UserRole, Product, Gender from flask_login import current_user admin = Admin(app=app, name="Private Clinic", template_mode = 'bootstrap4') class AuthenticatedView(ModelView): def is_accessible(self): return current_user.is_authenticated and current_user.role == UserRole.ADMIN class MyUserView(ModelView): column_list = ['id', 'name', 'phone', 'username', 'email', 'address', 'role'] column_searchable_list = ['username', 'name', 'phone'] column_editable_list = ['name', 'role', 'gender'] can_export = True column_filters = ['role'] column_labels = { 'id': 'ID', 'name': 'fullname', 'phone': 'SĐT', 'username': 'user name', 'email': 'Email', 'address': 'address', 'role': 'role', } admin.add_view(MyUserView(User, db.session)) admin.add_view(ModelView(Product, db.session))
init.py
from flask import Flask from flask_sqlalchemy import SQLAlchemy import cloudinary from flask_login import LoginManager app = Flask(__name__) app.config["SQLALCHEMY_DATABASE_URI"] = 'mysql+pymysql://root:12345@localhost/myclinic?charset=utf8mb4' app.secret_key = '^%^&%^(*^^&&*^$%((^^&$$&^' app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True app.config["PAGE_SIZE"] = 4 cloudinary.config( cloud_name = 'mycloud', api_key = 'api_key', api_secret = 'api_secret' ) db = SQLAlchemy(app) login = LoginManager(app)
问题原因
Flask-Admin的SQLAlchemy ModelView默认无法正确识别第三方库(如sqlalchemy_utils)提供的EnumType,在生成表单解析枚举字段选项时,返回了元组而非预期的字典格式,导致后续代码调用items()方法时触发错误。而原生类型(如Product模型中的String、Integer)能被Flask-Admin正确处理,因此无报错。
解决方案
方案1:手动为枚举字段指定表单控件
在MyUserView类中重写form_overrides和form_args,使用WTForms的SelectField手动定义枚举选项:
from wtforms import SelectField class MyUserView(ModelView): # 保留原有配置... form_overrides = { 'role': SelectField, 'gender': SelectField } form_args = { 'role': { 'choices': [(role.value, role.name) for role in UserRole], 'coerce': lambda x: UserRole(x) }, 'gender': { 'choices': [(gender.value, gender.name) for gender in Gender], 'coerce': lambda x: Gender(x) if x else None } }
方案2:改用SQLAlchemy原生Enum类型
如果你的数据库支持原生Enum(如MySQL 5.1+、PostgreSQL),直接使用SQLAlchemy内置的Enum代替第三方EnumType,Flask-Admin能自动识别枚举选项:
# 导入SQLAlchemy原生Enum from sqlalchemy import Enum # 修改User模型中的字段定义 role = Column(Enum(UserRole), nullable=False) gender = Column(Enum(Gender))
方案3:优化Enum类的字符串表示
为Enum类添加__str__方法,帮助Flask-Admin正确识别枚举值:
class UserRole(Enum): ADMIN = 'admin' PATIENT = 'patient' def __str__(self): return self.name # 或返回self.value,根据显示需求选择 class Gender(Enum): MALE = 'male' FEMALE = 'female' def __str__(self): return self.name
验证修改
重启应用后访问新增用户页面,枚举字段会显示正常的下拉选项,不再触发AttributeError。
内容的提问来源于stack exchange,提问作者Phuong Nguyen
相关产品推荐
相关产品推荐

