Flask管理员记住表单值

12
在我的应用程序中,我有用户和帖子作为模型。每个帖子都有一个指向用户名的外键。当我在我的帖子模型上创建一个ModelView时,我可以在管理界面中以特定用户的身份创建帖子,如下图所示。

enter image description here

我添加了一篇文章并点击“保存并添加另一个”后,“用户”会回到“user1”。如何使表单记住先前的值“user2”?

我的研究表明,可以通过修改on_model_change和on_form_prefill,并将先前的值保存在flask session中来完成此操作,但这似乎是对一个简单任务的过度设计。必须有一种更简单的方法。

我的代码如下所示

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)


[保存并添加另一个] 意味着清除当前表单并将新表单填充到表单中。如果您想在选择框中使用先前的表单用户作为默认值,则可以使用 cookie(客户端)或 session(服务器)来保存用户值并实现它。 - John
我不认为你从研究中得出的解决方案是过度工程化的。正如@John所说,你必须维护一个cookie或会话才能实现它。 - Krushi Raj
如果我误解了你的问题,请原谅我,@user787267。你是想将表单的默认加载选项更改为当前选择的选项,还是动态添加用户并将其设置为表单的默认选项? - realr
@calestini 我想让表单记住用户上次选择的值。这样,如果管理员想要为user2添加多篇文章,他不必在每个插入操作中重新选择user2。 - user787267
1
@user787267,总体选项包括:(1)异步发送表单,以便保留当前值;(2)使用上述提到的cookie;(3)传递URL参数,例如user_id=1并动态更改表单的默认值;或者(4)保存会话。选项3是一种简单而不太正规的方法,但它会在URL上公开您的内部ID。 - realr
2个回答

7
我以前也遇到过这种情况,我使用了两个函数来解决它。这很容易而且简单。
@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 

这是一个两步操作,非常小而且不需要太多时间。我现在只添加了骨架/伪代码。


谢谢!如果您能添加剩余的代码,我会非常感激。 - user787267

1

on_form_prefill对此问题无济于事,因为它仅适用于编辑表单。

正如库代码所说-> 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. 我们将其设置在cookies中,并在创建请求中获取。
  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()

1
这也是一个很好的答案!我以前没能用_template_args让它工作,但是设置以下内容后, `if 'user_id' in flask.session and not form.case.data: form.case.data=db.session.query(models.Users).filter_by(user_id=flask.session['user_id']).first()` 我成功了。由于某种奇怪的原因,我不得不覆盖form.case.data而不是form.case.default。 - user787267

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接