问题
How to set password_hash using generate_password_hash from the edit page of flask-admin
- i create a username and password in python shell. the password is hashing
- admin.add_view(MyModelView(User, db.session) - let me edit the User class Models
- when i edit the password and submit but the password is saved in plain text.
How to edit password from flask-admin, the password should be save in hashing type
My code is:
from werkzeug.security import generate_password_hash, check_password_hash
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(120))
password_hash = db.Column(db.String(64))
username = db.Column(db.String(64), unique=True, index=True)
@password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
def __repr__(self):
return '<User %r>' % self.username
#Create custom models view
class MyModelView(sqla.ModelView):
@admin.expose('/login/')
def index(self):
return self.render('login.html')
# Create custom admin view
class MyAdminView(admin.BaseView):
@admin.expose('/')
def index(self):
return self.render('myadmin.html')
admin = admin.Admin(name="Simple Views")
admin.add_view(MyAdminView(name='hello'))
admin.add_view(MyModelView(User, db.session))
admin.init_app(app)
app.run()
回答1:
Alternative solution is to subclass a TextField
adding custom processing logic:
class MyPassField(TextField):
def process_data(self, value):
self.data = '' # even if password is already set, don't show hash here
# or else it will be double-hashed on save
self.orig_hash = value
def process_fromdata(self, valuelist):
value = ''
if valuelist:
value = valuelist[0]
if value:
self.data = generate_password_hash(value)
else:
self.data = self.orig_hash
class UserView(ModelView):
form_overrides = dict(
passhash=MyPassField,
)
form_widget_args = dict(
passhash=dict(
placeholder='Enter new password here to change password',
),
)
回答2:
i solved my problem by using on_model_change function in flask-admin
#Create custom models view
class MyModelView(sqla.ModelView):
@admin.expose('/login/')
def index(self):
return self.render('login.html')
def on_model_change(self, form, User, is_created=False):
User.password = form.password_hash.data
回答3:
Simpler solution, you don't need to subclass TextField
Just add on_form_prefill
:
def on_model_change(self, form, User, is_created):
if form.password_hash.data:
User.set_password(form.password_hash.data)
else:
del form.password_hash
def on_form_prefill(self, form, id):
form.password_hash.data = ''
This will prevent double-hashing.
回答4:
I tried the solutions outlined in some of the other answers and I was only partially successful. There were issues with being able to edit the user later, and the password rehashing, or disappearing altogether.
One discovery I made was that on_model_change
actually gets called AFTER the model is populated from the form. There is no way to access the old values of the model without querying the database or monkey patching update_model
.
I have come up with a simpler version (I believe) that works in all scenarios.
Here is the whole view:
class UserView(AdminModel):
can_create = True
column_list = ('name', 'email',)
column_searchable_list = ('name', 'email',)
form_excluded_columns = ('password',)
form_extra_fields = {
'set_password': PasswordField('Set New Password')
}
def on_model_change(self, form, model, is_created):
if is_created:
model.active = True
model.pending = False
if form.email.data:
# Strip spaces from the email
form.email = form.email.data.strip()
if form.set_password.data:
model.password = bcrypt.generate_password_hash(form.set_password.data.strip())
def __init__(self, session, **kwargs):
# You can pass name and other parameters if you want to
super(UserView, self).__init__(User, session, **kwargs)
What I did was add a form field set_password
which when populated creates a password hash and updates password
on the model.
One and done!
来源:https://stackoverflow.com/questions/28970076/how-to-use-flask-admin-for-editing-modelview