如何使用 flask-admin 编辑模型视图

how to use flask-admin for editing modelview

如何使用 flask-admin

编辑页面中的 generate_password_hash 设置 password_hash
  1. 我在 python shell 中创建了一个用户名和密码。密码正在散列
  2. admin.add_view(MyModelView(User, db.session) - 让我编辑用户 class 模型
  3. 当我编辑密码并提交时,密码以纯文本形式保存。

如何从 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()

我使用 flask-admin

中的 on_model_change 函数解决了我的问题
#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_formdata(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 模型,该模型 returns 所有表单字段的字典。然后选择使用 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'))

有关 lambda 函数参数的更多详细信息,请参阅官方 flaskAdmin 文档。column_formatters