如何使用flask-admin编辑modelview

时间:2015-03-10 17:17:49

标签: flask-admin

如何使用flask-admin的编辑页面中的generate_password_hash设置password_hash

  1. 我在python shell中创建了用户名和密码。密码是哈希
  2. admin.add_view(MyModelView(User,db.session) - 让我编辑User类模型
  3. 当我编辑密码并提交但密码以纯文本保存时。
  4. 如何从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 个答案:

答案 0 :(得分:7)

替代解决方案是继承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',
        ),
    )

答案 1 :(得分:4)

我通过在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

答案 2 :(得分:3)

更简单的解决方案,您不需要继承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 = ''

这样可以防止双重散列。

答案 3 :(得分:2)

我尝试了其他一些答案中概述的解决方案,但我只取得了部分成功。以后能够编辑用户,密码重新编码或完全消失存在问题。

我做的一个发现是,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

一个完成!

答案 4 :(得分:0)

我的解决方案是简单地将列格式化程序字段添加到 UserView 模型,该模型返回所有​​表单字段的字典。然后选择使用 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