You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 05:07:32