Как использовать колбу-админ для редактирования модели
Как установить password_hash с помощью generate_password_hash со страницы редактирования на flask-admin
- Я создаю имя пользователя и пароль в оболочке Python. пароль хэширует
- admin.add_view(MyModelView(пользователь, db.session) - позвольте мне редактировать пользовательский класс Models
- когда я редактирую пароль и отправляю, но пароль сохраняется в виде простого текста.
Как отредактировать пароль от flask-admin, пароль должен быть сохранен в виде хеширования
Мой код:
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()
5 ответов
Я решил свою проблему с помощью функции on_model_change в 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
Альтернативным решением является подкласс TextField
добавление пользовательской логики обработки:
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',
),
)
Более простое решение, вам не нужно создавать подклассы TextField
Просто добавь 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 = ''
Это предотвратит двойное хеширование.
Я попробовал решения, изложенные в некоторых других ответах, и добился успеха лишь частично. Возникли проблемы с возможностью редактирования пользователя позже, а также с изменением пароля или его полным исчезновением.
Одно открытие, которое я сделал, было то, что on_model_change
фактически вызывается ПОСЛЕ того, как модель заполняется из формы. Невозможно получить доступ к старым значениям модели, не обращаясь к базе данных или исправлениям обезьян update_model
,
Я придумал более простую версию (я считаю), которая работает во всех сценариях.
Вот весь вид:
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)
Что я сделал, так это добавил поле формы set_password
который при заполнении создает хэш пароля и обновляет password
на модели.
Один и готово!
Мое решение состояло в том, чтобы просто добавить поле форматирования столбца в модель UserView, которая возвращает dict всех полей формы. затем выбрал форматирование пароля, сохраняемого с помощью хеша bcrypt.
class UserView(ModelView):
column_formatters =dict(password=lambda v,c,m,password: bcrypt.generate_password_hash(m.password, config.get('BCRYPT_LOG_ROUNDS')) \
.decode('utf-8'))
Подробнее об аргументах, которые принимает лямбда-функция, можно найти в официальной документации flaskAdmin. column_formatters