Im trying to se flask-admin and flask-security-too
and use the Views from flask-admin to administrate the users and its roles
the problem is that, the view from flask-admin is trying to update or create users with a standar db.commit() when the flask-security-too uses the method create_user()
or in security.datastore()
so, i havent find a way to override this little error that avoids me to create or edit the erros
by the moment
i have tried
def form_action(self, form, model, ids):
and gives a error that form, model and ids arent posible to use
then i tried
def update_model(self, form, model, ids):
try:
user = security.datastore.find_user(id=ids)
if user != None:
username = model.username
name = model.name
email = model.email
password = model.password
user.username = username
user.email = email
user.name = name
user.password = password
security.datastore.update_user(user)
security.datastore.commit()
flash(f'usuario {user.name} fue editado con exito', 'success')
else:
username = model.username
name = model.name
email = model.email
password = model.password
user.username = username
user.email = email
user.name = name
user.password = password
security.datastore(user)
security.datastore.commit()
flash(f'usuario {user.name} fue editado con exito', 'success')
except Exception as e:
print(e)
flash('ups algo salio mal', 'danger')
and it still tries to update the database in the sqlalchemy ay without using the security methods. so it gives a problem in the fs_uniquifier (1048, "Column 'fs_uniquifier' cannot be null")
so any insigth is well apreciated
models.py
class RolesUsers(db.Model):
__tablename__ = 'roles_users'
__table_args__ = {'extend_existing': True}
id = db.Column(db.Integer(), primary_key=True)
user_id = db.Column('user_id', db.Integer(), db.ForeignKey('user.id'))
role_id = db.Column('role_id', db.Integer(), db.ForeignKey('role.id'))
class Role(db.Model, RoleMixin):
__tablename__ = 'role'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.String(80), unique=True)
description = db.Column(db.String(255))
# __str__ is required by Flask-Admin, so we can have human-readable
# values for the Role when editing a User.
def __str__(self):
return self.name
# __hash__ is required to avoid the exception
# TypeError: unhashable type: 'Role' when saving a User
def __hash__(self):
return hash(self.name)
class User(db.Model, UserMixin):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(255), unique=True)
username = db.Column(db.String(255), unique=True, nullable=True)
name = db.Column(db.String(255), nullable=True)
password = db.Column(db.String(255), nullable=False)
last_login_at = db.Column(db.DateTime())
current_login_at = db.Column(db.DateTime())
last_login_ip = db.Column(db.String(100))
current_login_ip = db.Column(db.String(100))
login_count = db.Column(db.Integer)
active = db.Column(db.Boolean())
fs_uniquifier = db.Column(db.String(255), unique=True, nullable=False)
confirmed_at = db.Column(db.DateTime())
roles = db.relationship('Role', secondary='roles_users',
backref=db.backref('users', lazy='dynamic'))
def __repr__(self):
return '<Usuario {}>'.format(self.username)
the views.py
class UserModelView(sqla.ModelView):
def is_accessible(self):
return (current_user.is_active and
current_user.is_authenticated and
current_user.has_role('superuser')
)
column_exclude_list = ('password', 'fs_uniquifier', 'email')
column_default_sort = 'name'
can_delete = False
#
# exclude fileds that im not interested in render
#
form_excluded_columns = ('roles', 'last_login_at', 'current_login_at', 'last_login_ip', 'current_login_ip', 'login_count', 'fs_uniquifier', 'confirmed_at', 'password')
#override the basic form to show fields that i want
def scaffold_form(self):
# Start with the standard form as provided by Flask-Admin. We've already told Flask-Admin to exclude the
# password field from this form.
form_class = super(UserModelView, self).scaffold_form()
# Add a password field, naming it "password2" and labeling it "New Password".
form_class.password2 = PasswordField('Nuevo Password', [validators.InputRequired(), validators.EqualTo('password3', message='los passwords tienen que coincidir'), validators.Length(min=8, message='el password tiene que tener 8 digitos')])
form_class.password3 = PasswordField('confirmar password')
return form_class
def on_model_change(self, form, model, is_created):
# If the password field isn't blank...
if model.password3 == model.password2:
# ... then encrypt the new password prior to storing it in the database. If the password field is blank,
# the existing password in the database will be retained.
model.password = hash_password(model.password2)
else:
flash('ups, hay algo mal en el password')
# add methods to use with flask security too and use the UserMixin of security
#
def update_model(self, form, model, ids):
try:
user = security.datastore.find_user(id=ids)
if user != None:
username = model.username
name = model.name
email = model.email
password = model.password
user.username = username
user.email = email
user.name = name
user.password = password
security.datastore.update_user(user)
security.datastore.commit()
flash(f'usuario {user.name} fue creado con exito', 'success')
else:
username = model.username
name = model.name
email = model.email
password = model.password
user.username = username
user.email = email
user.name = name
user.password = password
security.datastore(user)
security.datastore.commit()
flash(f'usuario {user.name} fue editado con exito', 'success')
except Exception as e:
print(e)
flash('ups algo salio mal', 'danger')
@action('activar', 'activar usuarios', 'Seguro que quiere activar este usuario?')
def activar(self, ids):
try:
user = security.datastore.find_user(id=ids)
security.datastore.activate_user(user)
security.datastore.commit()
flash(f'usuario {user.name} fue activado', 'success')
except Exception as e:
print(e)
flash('ups algo salio mal', 'danger')
@action('desactivar', 'desactivar usuarios', 'Seguro que quiere desactivar este usuario?')
def desactivar(self, ids):
try:
user = security.datastore.find_user(id=ids)
security.datastore.deactivate_user(user)
security.datastore.commit()
flash(f'usuario {user.name} fue desactivado', 'success')
except Exception as e:
print(e)
flash('ups algo salio mal', 'danger')
@action('cerrar sesion', 'cerrar sesiones', 'Seguro que quieres cerrar todas sus sesiones?')
def cerrar_sesion(self, ids):
try:
user = security.datastore.find_user(id=ids)
security.datastore.set_uniquifier(user)
security.datastore.commit()
flash(f'usuario {user.name} fueron cerradas todas sus sesiones', 'success')
except Exception as e:
print(e)
flash('ups algo salio mal', 'danger')
def _handle_view(self, name, **kwargs):
# Override builtin _handle_view in order to redirect users when a view is not accessible.
if not self.is_accessible():
if current_user.is_authenticated:
# permission denied
abort(403)
else:
# login
return redirect(url_for('security.login', next=request.url))