python - Flask-admin 批处理操作,通过弹出模式窗口进行参数

标签 python flask modal-dialog flask-admin

有什么方法可以从 Flask 函数启动弹出窗口吗?

我有一个 flask-admin + flask-sqlalchemy 应用程序。数据库中的一个表包含一个带有一些值的字段 foo。我有一个 UserAdmin View ,我正在尝试创建一个 batch action有一些外部参数。 即我想:

  • 从我的数据库中选择几个元素
  • 将每个元素的旧 foo 值替换为一个新的用户定义值和
  • 我想要接收这个新值的方式是模态窗口。

所以模型是:

class User(db.Model):
    # some code
    foo = Column(Integer)
    def change_foo(self, new_foo):
        self.foo = int(new_foo)
        db.session.commit()
        return True

class UserAdmin(sqla.ModelView):
    # some code
    @action('change_foo', 'Change foo', 'Are you sure you want to change foo for selected users?')
    def action_change_foo(self, ids):
        query = tools.get_query_for_ids(self.get_query(), self.model, ids)
        count = 0
        # TODO: pop-up modal window here to get new_foo_value
        # new_foo_value = ???
        for user in query.all():
            if user.change_foo(new_foo_value):
                count += 1
        flash(ngettext('Foo was successfully changed.',
                       '%(count)s foos were successfully changed.',
                       count, count=count))
    except Exception as e:
        flash(ngettext('Failed to change foo for selected users. %(error)s', error=str(e)), 'error')

我承认整个方法并不是最优的,所以我很高兴有人建议我使用更好的方法。

还有一些相关的问题:« Batch Editing in Flask-Admin »(尚未回答)和«Flask-Admin batch action with form »(使用 WTF 表单的一些解决方法)。

最佳答案

这是实现此目的的一种方法。我已将完整的独立示例放在 Github 上,flask-admin-modal .

2018 年 5 月 28 日更新。Github 项目已由另一位用户增强,可以很好地处理表单验证。

在此示例中,SQLite 数据库模型是一个具有名称(字符串)和成本(整数)属性的项目,我们将更新 Flask-Admin ListView 中选定行的成本值。请注意,当 Flask 应用程序启动时,数据库会填充随机数据。

这是模型:

class Project(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(255), nullable=False, unique=True)
    cost = db.Column(db.Integer(), nullable=False)

    def __str__(self):
        return unicode(self).encode('utf-8')

    def __unicode__(self):
        return "Name: {name}; Cost : {cost}".format(name=self.name, cost=self.cost)

用接受新成本的整数成本字段定义一个表单。此表单还有一个隐藏字段,用于跟踪所选行的 ID。

class ChangeForm(Form):
    ids = HiddenField()
    cost = IntegerField(validators=[InputRequired()])

覆盖项目 View 模型的列表模板。我们这样做是为了在 {% block body %} 中注入(inject)一个带有 id changeModal 的 Bootstrap 模态形式,确保我们调用 {{ super () }} 首先。

我们还添加了一个 jQuery 文档就绪函数,如果模板变量 (change_modal) 的计算结果为真,该函数将显示模态形式。模态主体中使用相同的变量来显示 change_form。我们使用 Flask-Admin lib 宏 render_form 以 Bootstrap 样式呈现表单。

请注意 render_form 中 action 参数的值 - 它是我们在项目 View 中定义的路由,我们可以在其中处理表单数据。另请注意,“关闭”按钮已替换为链接,但样式仍为按钮。该链接是发起操作的原始 URL(包括页面和过滤器详细信息)。

{% extends 'admin/model/list.html' %}

{% block body %}
    {{ super() }}

    <div class="modal fade" tabindex="-1" role="dialog" id="changeModal">
      <div class="modal-dialog" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <a href="{{ url }}" class="close" aria-label="Close"><span aria-hidden="true">&times;</span></a>
            <h4 class="modal-title">Change Project Costs</h4>
          </div>
          <div class="modal-body">
              {% if change_modal %}
                  {{ lib.render_form(change_form, action=url_for('project.update_view', url=url)) }}
              {% endif %}
          </div>
        </div><!-- /.modal-content -->
      </div><!-- /.modal-dialog -->
    </div><!-- /.modal -->
{% endblock body %}

{% block tail %}
    {{ super() }}
    <script>
        {% if change_modal %}
            $(document).ready(function(){
                $("#changeModal").modal('show');
            });
        {% endif %}
    </script>
{% endblock tail %}

项目 View 类需要修改批处理方法的行为并定义几个接受 POST 请求的路由。

@action('change_cost', 'Change Cost', 'Are you sure you want to change Cost for selected projects?')
def action_change_cost(self, ids):
    url = get_redirect_target() or self.get_url('.index_view')
    return redirect(url, code=307)

批处理操作获取发布操作的 url,而不是直接处理 id,此 url 将包含任何页码和过滤器详细信息。然后它使用 307 重定向回 ListView 。这确保了所选行的 ID 在正文中携带以及它是 POST 请求的事实。

定义一个 POST 路由来处理这个重定向,从请求体中获取 ids 和 url,实例一个 ChangeForm,将隐藏的 ids 表单字段设置为一个编码列表的ID。将 urlchange_formchange_model 变量添加到模板参数中,然后再次呈现 ListView - 这次将显示模态弹出窗体在 View 中。

@expose('/', methods=['POST'])
def index(self):
    if request.method == 'POST':
        url = get_redirect_target() or self.get_url('.index_view')
        ids = request.form.getlist('rowid')
        joined_ids = ','.join(ids)
        encoded_ids = base64.b64encode(joined_ids)
        change_form = ChangeForm()
        change_form.ids.data = encoded_ids
        self._template_args['url'] = url
        self._template_args['change_form'] = change_form
        self._template_args['change_modal'] = True
        return self.index_view() 

定义一个 POST 路由来处理模态表单的数据。这是标准的表单/数据库处理,完成后重定向回启动操作的原始 url。

@expose('/update/', methods=['POST'])
def update_view(self):
    if request.method == 'POST':
        url = get_redirect_target() or self.get_url('.index_view')
        change_form = ChangeForm(request.form)
        if change_form.validate():
            decoded_ids = base64.b64decode(change_form.ids.data)
            ids = decoded_ids.split(',')
            cost = change_form.cost.data
            _update_mappings = [{'id': rowid, 'cost': cost} for rowid in ids]
            db.session.bulk_update_mappings(Project, _update_mappings)
            db.session.commit()
            return redirect(url)
        else:
            # Form didn't validate
            # todo need to display the error message in the pop-up
            print change_form.errors
            return redirect(url, code=307)

关于python - Flask-admin 批处理操作,通过弹出模式窗口进行参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47593195/

相关文章:

python - 支持多个 Python 模块版本(具有相同版本的 Python)

python-3.x - Flask/uWSGI - 一段时间后进程过多

python - {%block content%} 内 flask 中的新行

html - Bootstrap 模态不工作

java - 多个 Swing 事件分发线程

Swing 的 JavaFX 模态窗口所有权

python - gdalinfo不起作用

Java 和 Python

python - 使用 lmfit ExponentialGaussianModel( )

python - 条件 Flask-WTF 表单字段