Flask Admin - Доступ к старым значениям с помощью on_model_change () - PullRequest
0 голосов
/ 24 марта 2020

Моя цель - выполнить некоторые дополнительные действия, когда пользователь изменяет значение существующей записи.

Я нашел 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 представлять старые данные. Это было довольно странно и привело к тому, что я сам переопределил 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

1 Ответ

0 голосов
/ 24 марта 2020

Метод переопределения 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_model и delete_model .

...