Search code examples
pythonflaskflask-security

python flask flask_security unable to update user first name last name etc


I have used flask_security to enable authentication in my small web application. In the early phase I have managed to enable login logout etc. However when implementing profile page I am unable to update the record.

view:

@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)

model:

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

error I am getting is:

AttributeError: 'User' object has no attribute 'save'

I can use session to update the record outside of the orm but I want to do it using most flask_security and sqlalchamy compatible way, please help.


Solution

  • As other have said - db.session.commit() is the answer. The main issue I see in your example is that you are creating a NEW User record and committing that - you are overwriting the 'user' variable. Also - you have 'current_user' already - not sure why you are looking it up again! So:

    if request.method == 'POST' and form_profile.save:
      current_user.last_name = form_profile.last_name.data
      db.session.commit()