Flask-Security无法更新用户信息,报错User无save方法
Flask-Security + SQLAlchemy 用户资料更新失败:AttributeError: 'User' object has no attribute 'save'
我用Flask-Security实现了小型Web应用的认证功能,登录、登出等基础功能正常,但开发个人资料页面时无法更新用户记录,报错AttributeError: 'User' object has no attribute 'save'。希望采用兼容Flask-Security和SQLAlchemy的ORM方式解决,不想直接操作session。
视图代码
@profile_bp.route('/', methods=('GET','POST')) @login_required def profile(): form_profile = ProfileForm(request.form) user = User.query.filter_by(id=current_user.id).first() if request.method == 'POST' and form_profile.save: print("Profile form submitted") user = User( updated = utc_now_int(), first_name = form_profile.first_name.data, last_name = form_profile.last_name.data, gender = form_profile.gender.data, date_of_birth = form_profile.date_of_birth.data, ) user.save() return render_template('profile/profile_saved.html') # Populate the form when when user loads his profile and then render the template if user: form_profile.first_name.data = user.first_name form_profile.last_name.data = user.last_name form_profile.gender.data = user.gender form_profile.date_of_birth.data = user.date_of_birth return render_template('profile/userprofile.html', form_profile=form_profile)
模型代码
from app.database import Base from flask_security.models import fsqla_v3 as fsqla from flask_security import UserMixin, RoleMixin, AsaList from sqlalchemy.orm import relationship, backref from sqlalchemy.ext.mutable import MutableList from sqlalchemy import Boolean, DateTime, Column, Integer, \ String, ForeignKey from app.utilities.common import utc_now as now, uid_generator class RolesUsers(Base): __tablename__ = 'roles_users' id = Column(Integer(), primary_key=True) user_id = Column('user_id', Integer(), ForeignKey('users.id')) role_id = Column('role_id', Integer(), ForeignKey('roles.id')) class Role(Base, RoleMixin): __tablename__ = 'roles' id = Column(Integer(), primary_key=True) name = Column(String(80), unique=True) description = Column(String(255)) permissions = Column(MutableList.as_mutable(AsaList()), nullable=True) class User(Base, UserMixin): __tablename__ = 'users' id = Column(Integer, primary_key=True) email = Column(String(255), unique=True) password = Column(String(255)) username = Column(String(255), unique=True, nullable=True) fs_uniquifier = Column(String(64), unique=True, nullable=False) created = Column(DateTime(), default=lambda: now()) active = Column(Boolean()) updated = Column(DateTime()) # confirmed_at = Column(DateTime(), default=lambda: now()) confirmed_at = Column(DateTime()) last_login_at = Column(DateTime()) current_login_at = Column(DateTime()) last_login_ip = Column(String(40)) current_login_ip = Column(String(40)) login_count = Column(Integer) first_name = Column(String(255)) last_name = Column(String(255)) gender = Column(String(1)) date_of_birth = Column(DateTime()) roles = relationship('Role', secondary='roles_users', backref=backref('users', lazy='dynamic')) def __str__(self): return self.email
错误信息
AttributeError: 'User' object has no attribute 'save'
解决方案
1. 问题根源
- User模型未定义
save()方法,直接调用会报错。 - POST请求中重新创建了新的User对象,而非更新已查询到的数据库实例,会丢失用户原有核心信息(如email、fs_uniquifier),甚至产生重复用户。
2. 修正视图代码(标准ORM方式)
直接更新查询到的user实例,通过SQLAlchemy的session提交修改,完全兼容Flask-Security:
from app import db # 导入你的SQLAlchemy实例,根据实际路径调整 @profile_bp.route('/', methods=('GET','POST')) @login_required def profile(): form_profile = ProfileForm(request.form) user = User.query.filter_by(id=current_user.id).first() if request.method == 'POST' and form_profile.validate(): # 用表单验证确保数据合法 print("Profile form submitted") # 更新已有user实例的字段,而非新建对象 user.updated = utc_now_int() user.first_name = form_profile.first_name.data user.last_name = form_profile.last_name.data user.gender = form_profile.gender.data user.date_of_birth = form_profile.date_of_birth.data db.session.commit() # 提交session保存修改 return render_template('profile/profile_saved.html') # 填充表单初始数据 if user: form_profile.first_name.data = user.first_name form_profile.last_name.data = user.last_name form_profile.gender.data = user.gender form_profile.date_of_birth.data = user.date_of_birth return render_template('profile/userprofile.html', form_profile=form_profile)
3. 可选:给User模型添加save方法
如果想保留user.save()的调用方式,可在User模型中添加通用save方法:
class User(Base, UserMixin): # ... 原有字段和方法 ... def save(self): from app import db # 或在模型顶部提前导入db db.session.add(self) db.session.commit()
添加后,视图中可使用user.save()替代db.session.commit(),本质仍是通过session提交,完全兼容Flask-Security。
4. 额外注意
- 表单验证:优先使用
form_profile.validate()判断表单提交合法性,避免非法数据入库。 - 类型匹配:确保
utc_now_int()返回的类型与User模型中updated字段(DateTime类型)一致,若返回时间戳需转换为datetime对象。
内容的提问来源于stack exchange,提问作者afsar
相关产品推荐
相关产品推荐

