Flask使用SQLAlchemy插入新用户触发AttributeError错误如何解决
问题排查与解决方案
报错根因
你遇到的AttributeError: 'str' object has no attribute '_sa_instance_state'错误,核心原因是SQLAlchemy的多对多关系字段roles期望接收Role模型的实例对象或实例列表,你直接传入了字符串"Admin",无法被SQLAlchemy识别为合法的ORM实例。
现有代码两处需要修正的问题
1. 多对多关系配置错误
当前你把backref单独声明为User类的属性,属于配置错误,backref是relationship的入参,正确配置如下:
# 注意:需要先提前定义多对多中间表,否则运行会报错 users_roles = db.Table('users_roles', db.Column('user_id', db.Integer, db.ForeignKey('users.id'), primary_key=True), db.Column('role_id', db.Integer, db.ForeignKey('roles.id'), primary_key=True) ) class User(db.Model, UserMixin): __tablename__ = 'users' username = db.Column(db.String(100), nullable=False) id = db.Column(db.Integer, primary_key=True, autoincrement=True) email = db.Column(db.String(100), unique=True, nullable=False) password_hash = db.Column(db.String(128), nullable=False) # 将backref作为relationship的参数传入 roles = db.relationship('Role', secondary='users_roles', backref=db.backref('users', lazy='dynamic')) # 密码哈希设置方法 def set_password(self, password): self.password_hash = generate_password_hash(password) class Role(db.Model, RoleMixin): __tablename__ = 'roles' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String(60), unique=True)
2. 用户插入逻辑错误
给多对多字段roles赋值时,必须传入Role实例,不能直接传角色名字符串,正确的插入逻辑如下:
# 先查询Admin角色,不存在则先创建存储到数据库 admin_role = Role.query.filter_by(name='Admin').first() if not admin_role: admin_role = Role(name='Admin') db.session.add(admin_role) db.session.commit() # 创建用户实例 new_user = User(username="user1", email="user1@gmail.com") # 调用封装好的set_password方法生成哈希值,不要手动给password_hash赋值 new_user.set_password("你的用户明文密码") # 给roles字段赋值Role实例的列表(多对多支持一个用户绑定多个角色) new_user.roles = [admin_role] db.session.add(new_user) db.session.commit()
额外注意点
所有涉及到ORM关系的字段,赋值时都要传入对应模型的实例,不能直接传主键值或者名称字符串,否则都会触发同类_sa_instance_state相关报错。
内容的提问来源于stack exchange,提问作者Nyi Nyi Hmue Aung
相关产品推荐
相关产品推荐

