Flask admin запоминает значение формы

В моем приложении у меня есть Пользователи и Сообщения в качестве моделей. Каждый пост имеет внешний ключ к имени пользователя. Когда я создаю ModelView поверх моей модели сообщений, я могу создавать сообщения как определенные пользователи в интерфейсе администратора. как видно на скриншоте ниже

enter image description here

После того, как я добавил сообщение и нажал "Сохранить и добавить другое", "Пользователь" возвращается к "user1". Как я могу заставить форму помнить предыдущее значение "user2"?

Мои исследования привели меня к мысли, что это можно сделать, изменив on_model_change и on_form_prefill и сохранив предыдущее значение в сеансе фляги, но, похоже, это слишком сложная задача. Должен быть более простой способ.

Мой код можно увидеть ниже

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import flask_admin
from flask_admin.contrib import sqla

app = Flask(__name__)

db = SQLAlchemy()

admin = flask_admin.Admin(name='Test')


class Users(db.Model):
    """
    Contains users of the database
    """
    user_id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True, nullable=False)

    def __str__(self):
        return self.username


class Posts(db.Model):
    """
    Contains users of the database
    """
    post_id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(11), db.ForeignKey(Users.username), nullable=False)
    post = db.Column(db.String(256))
    user = db.relation(Users, backref='user')


def build_sample_db():
    db.drop_all()
    db.create_all()
    data = {'user1': 'post1', 'user1': 'post2', 'user2': 'post1'}
    for user, post in data.items():

        u = Users(username=user)
        p = Posts(username=user, post=post)

        db.session.add(u)
        db.session.add(p)
    db.session.commit()

class MyModelView(sqla.ModelView):

    pass


if __name__ == '__main__':

    app.config['SECRET_KEY'] = '123456790'
    app.config['DATABASE_FILE'] = 'sample_db.sqlite'
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database'
    app.config['SQLALCHEMY_ECHO'] = True
    db.init_app(app)

    admin.init_app(app)
    admin.add_view(MyModelView(Posts, db.session))

    with app.app_context():
        build_sample_db()

    # Start app
    app.run(debug=True)

Ответ 1

Я сталкивался с этой ситуацией раньше, и я решил ее, используя 2 функции. это довольно легко и мало.

@expose('/edit/', methods=('GET', 'POST'))
def edit_view(self):
    #write your logic to populate the value into html        
    self._template_args["arg_name"] = stored_value
    # in your html find this value to populate it as you need

вышеупомянутая функция позволит вам заполнить значения в html, когда пользователь пытается изменить любое значение. Это может быть заполнено, используя сохраненное значение. А ниже находится функция, которая помогает вам сохранить значение из предыдущего редактирования.

в этом class MyModelView(sqla.ModelView): вам нужно добавить следующие 2 функции.

def on_model_change(self, form, model, is_created):
    stored_value = model.user # this is your user name stored
    # get the value of the column from your model and save it 

Это двухэтапная операция, которая довольно мала и не требует много времени. Я добавил только скелет/псевдокод.

Ответ 2

Функция on_form_prefill не поможет вам в решении этой проблемы, поскольку она работает только для формы редактирования.

Как сказано в коде lib → on_form_prefill => Выполните дополнительные действия для предварительно заполните форму редактирования

При поступлении запроса происходит следующий поток кода:

(Базовый класс) Представление (create_view) → create_form-> _ create_form_class-> get_ create_form-> get_form-> scaffold_form

Следовательно, если мы хотим изменить значение по умолчанию загружаемой формы создания, мы можем обновить его в методах, обрабатывающих форму, как описано в приведенном выше потоке.

Следовательно, мы можем переопределить create_form.

 def create_form(self):
     form = super().create_form()
     # set the user id we want in the form as default.
     form.user_id.default = 'USER_2_ID'
     return form

Это было для получения значения по умолчанию для формы.

Чтобы установить значение, мы переопределяем on_model_change

def on_model_change(self, form, model, is_created):
    # set the USER_ID from this model.user_id
    pass

Теперь существует способ поделиться этими данными (USER_ID) с помощью методов установки и получения,

  1. Мы устанавливаем это в куки и получаем запрос на создание.
  2. Обновите ссылку кнопки "сохранить и добавить еще", чтобы добавить user_id в строки запроса.

Эти данные должны быть разделены между двумя различными запросами, следовательно, сохраняя их в контексте приложения, g не будет работать. Контекст приложения "не будет разделен между запросами"

 def create_form(self):
     form = super().create_form()
     user_id = request.args.get('user_id')
     form.user_id.default = user_id

     # or if you want only one option to be available 
     user_query = self.session.query(User).filter(User.id = user_id).one()
     form.user.query = [user_query]
     return form

Как уже упоминалось в ответе об использовании edit_view, create_view, который также можно использовать для добавления

простой вариант, но не самый удачный, - это запрос на создание это даст вам последнюю запись (Но этот подход не является оптимальным один)

@expose('/new/', methods=('GET', 'POST'))
def create_view(self):
    model = self.get_model()
    # query the model here to get the latest value of the user_id
    self._template_args['user_id'] = user_id
    return super(YourAdmin, self).details_view()