Flask 管理 - 使用 on_model_change() 访问旧值

问题描述 投票:0回答:2

我的目标是当用户更改现有记录的值时执行一些附加操作。

我在文档中找到了 on_model_change() 并编写了以下代码:

def on_model_change(self, form, model, is_created): # get old and new value old_name = model.name new_name = form.name if new_name != old_name: # if the value is changed perform some other action rename_files(new_name)

我的期望是

model

 参数将代表应用表单中的新值之前的记录。但事实并非如此。相反,我发现 
model
 始终与 
form
 具有相同的值,这意味着 if 语句从未得到满足。 

后来我尝试了这个:

class MyView(ModelView): # excluding the name field from the form form_excluded_columns = ('name') form_extra_fields = { # and adding a set_name field instead 'set_name':StringField('Name') } ...

def on_model_change(self, form, model, is_created): # getting the new value from set_name instead of name new_name = form.set_name ...

虽然这解决了我的目标,但也引发了一个问题:

set_name

字段不会预先填充现有名称,即使用户不打算更改名称,也会强制用户键入名称

我还尝试在

db.rollback()

 开始时执行 
on_model_change()
 ,这将撤消 Flask-admin 所做的所有更改,并使 
model
 代表旧数据。这是相当 hacky 的,导致我自己重新实现了很多 Flask 管理代码,这变得很混乱。 

解决这个问题的最佳方法是什么?

我是如何解决的 我使用 on_form_prefill 来预填充新名称字段,而不是 @pjcunningham 的答案。

# fill values from model def on_form_prefill(self, form, id): # get track model track = Tracks.query.filter_by(id=id).first() # fill new values form.set_name.data = track.name
    
python flask-admin
2个回答
4
投票
在您的视图中覆盖方法

update_model。如果您使用 SqlAlchemy 视图,这是默认行为,我添加了一些注释来解释模型的状态。

def update_model(self, form, model): """ Update model from form. :param form: Form instance :param model: Model instance """ try: # at this point model variable has the unmodified values form.populate_obj(model) # at this point model variable has the form values # your on_model_change is called self._on_model_change(form, model, False) # model is now being committed self.session.commit() except Exception as ex: if not self.handle_view_exception(ex): flash(gettext('Failed to update record. %(error)s', error=str(ex)), 'error') log.exception('Failed to update record.') self.session.rollback() return False else: # model is now committed to the database self.after_model_change(form, model, False) return True

您需要类似以下的内容,这取决于您在哪里放置支票,我在模型提交后将其放置:

def update_model(self, form, model): """ Update model from form. :param form: Form instance :param model: Model instance """ try: old_name = model.name new_name = form.name.data # continue processing the form form.populate_obj(model) self._on_model_change(form, model, False) self.session.commit() except Exception as ex: if not self.handle_view_exception(ex): flash(gettext('Failed to update record. %(error)s', error=str(ex)), 'error') log.exception('Failed to update record.') self.session.rollback() return False else: # the model got committed now run our check: if new_name != old_name: # if the value is changed perform some other action rename_files(new_name) self.after_model_change(form, model, False) return True

您可以为

create_modeldelete_model 重写类似的方法。


0
投票
根据 @pjcunningham 的出色推荐,我是这样做的:

class MyModel(ModelView): def update_model(self, form, model): """Override this method to record something from the model before it's updated""" # Make a copy of the old surface location before it's updated, so we can compare it later self.old_surface = model.surface return super().update_model(form, model) def after_model_change(self, form, model, is_created): """ Check to see if the "surface" field has changed, and if so, update the GPS coordinates. Do this after the model has changed, so we can start a new database transaction. """ if ( "surface" in form.data.keys() and form.data["surface"] != self.old_model.surface ): get_or_update_gps(structure_obj=model)
    
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.