Say I have a user model like:
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
first_name = db.Column(db.String(255))
last_name = db.Column(db.String(255))
email = db.Column(db.String(255), unique=True)
password = db.Column(db.String(255))
registered_on = db.Column(db.DateTime, nullable=True)
roles = db.relationship('Role', secondary=roles_users,
backref=db.backref('users', lazy='dynamic'))
And an admin view:
class UserView(MyModelView):
form_columns = (
'roles',
'first_name',
'last_name',
'email',
'password',
'registered_on',
)
form_args = dict(
registered_on=dict(default=datetime.now())
)
When I create a new user how to I automatically generate a password hash with something like bcrypt?
I think by automatic you mean that it should automatically convert a manually-supplied plain-text password into a hash, but I am not certain. I am answering as if this assumption is correct.
We don't expose our password fields in Flask-Admin, but we handle the basic question of how and when passwords get hashed by defining password
as a property with a setter responsible for computing the hash itself and tucking it away in user._password
.
A naive swing at just trying to add password
as a column in the admin view didn't work, but if you use sqlalchemy's hybrid_property
instead of property
, it looks like this works fine with "password"
in your User view's list of form_columns
(as you already have):
# models.py
from sqlalchemy.ext.hybrid import hybrid_property
class User(sql.Model):
# ...
_password = sql.Column(sql.Binary)
_salt = sql.Column(sql.Binary, default=lambda: os.urandom(512))
# ...
@hybrid_property
def password(self):
"""Return the hashed user password."""
return self._password
@password.setter
def password(self, new_pass):
"""Salt/Hash and save the user's new password."""
new_password_hash = compute_new_password_hash(new_pass, self._salt)
self._password = new_password_hash
# admin.py
class UserView(MyModelView):
# ...
form_columns = ("email", "password", ...)
The editing experience isn't exactly polished--you'd probably need to override the field to refine it. Here are some screenshots:
Creating a new user with a pre-set password:
The edit view after creation:
Updating the user's password:
The edit view after saving the new password: