烧瓶确认动作 [英] Flask Confirm Action

查看:59
本文介绍了烧瓶确认动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Flask框架创建一个网站,并正在为(主要是管理上的)行为实施一个确认页面;即删除用户.

I'm creating a site using the Flask framework, and am implementing a confirmation page for (mainly administrative) actions; i.e. deleting a user.

我当前的方法(在下面详细介绍)可以工作,但是感觉很笨拙,似乎对于一个简单的任务来说需要大量工作.有更好的解决方案吗?

My current method (detailed below) works, but feels quite clunky and seems like a huge amount of work for a simple task. Is there a more optimal solution to this?

目前,我有一条启动操作的路线:

Currently I have a route to initiate the action:

@admin.route('/user/<int:user_id>/delete', methods=['GET'])
@login_required
@admin_required
def del_user(user_id):
    user = User.query.get_or_404(user_id)
    desc = "delete"
    subject = user.username
    action = 'admin.do_del_user'
    next = url_for('admin.get_user', user_id=user.id)
    return redirect(url_for('main._confirm', desc=desc, subject=subject, action=action, next=next, user_id=user.id))

哪个重定向到确认路线:

Which redirects over to the confirm route:

@main.route('/confirm', methods=['GET', 'POST'])
def _confirm():
    form = Confirm()
    kwargs = {}
    for arg in request.args:
        if arg != 'action' or arg != 'desc' or arg != 'subject':
            kwargs[arg] = request.args[arg]
    action = request.args.get('action')
    desc = request.args.get('desc')
    subject = request.args.get('subject')

    if action is None:
        abort(404)

    if form.validate_on_submit():
        return redirect(url_for(action, confirm=form.confirm.data, **kwargs))
    return render_template('_confirm.html', form=form, desc=desc, subject=subject)

然后,在确认确认表之后,哪个会再次重定向以执行实际操作:

Which then redirects again to do the actual action after validating the confirmation form:

@admin.route('/user/<int:user_id>/do_delete', methods=['GET'])
@login_required
@admin_required
def do_del_user(user_id):
    confirm = request.args.get('confirm')
    next = request.args.get('next')
    if confirm:
        user = User.query.get_or_404(user_id)
        db.session.delete(user)
        db.session.commit()
    return redirect(next)

我希望这是有道理的!请注意,为确认模板传递了 desc subject ,而 kwargs 只是为了捕获构建url_for()所需的任何内容.网址.

I hope that makes sense! Just to note, desc and subject are passed for the confirmation template, and the kwargs is just to catch anything url_for() needs in building the urls.

推荐答案

我认为最简单的方法是在客户端进行确认.它的外观不是很漂亮,但是 window.confirm('您确定吗?'); 会做同样的事情.

I think the simplest approach would be to do the confirmation client-side. It's not visually pretty, but a window.confirm('Are you sure?'); would do the same thing.

也就是说,如果您只是在寻找服务器端解决方案,则可以创建一个 @confirmation_required 装饰器来处理重定向.然后,您可以用它包装需要确认的任何视图,并传入一个函数以获取要显示的消息.

That said, if you're only looking for a server-side solution, you could create a @confirmation_required decorator to handle the redirects. Then, you can wrap any view you need confirmation for with it, passing in a function to get the message you want to display.

from functools import wraps
from urllib import urlencode, quote, unquote
from flask import Flask, request, redirect, url_for, render_template

app = Flask(__name__)

def confirmation_required(desc_fn):
    def inner(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            if request.args.get('confirm') != '1':
                desc = desc_fn()
                return redirect(url_for('confirm', 
                    desc=desc, action_url=quote(request.url)))
            return f(*args, **kwargs)
        return wrapper
    return inner

@app.route('/confirm')
def confirm():
    desc = request.args['desc']
    action_url = unquote(request.args['action_url'])

    return render_template('_confirm.html', desc=desc, action_url=action_url)

def you_sure():
    return "Are you sure?"

@app.route('/')
@confirmation_required(you_sure)
def hello_world():
    return 'Hello World!'


if __name__ == '__main__':
    app.run(debug=True)

_confirm.html:

_confirm.html:

<html xmlns="http://www.w3.org/1999/html">
<body>
<h1>{{ desc }}</h1>
<form action="{{ action_url }}" method="GET">
    <input type="hidden" name="confirm" value="1">
    <input type="submit" value="Yes">
</form>
</body>
</html>

但是请注意,只有在要包装的视图接受GET的情况下,此重定向操作才有效,并且对任何修改数据的操作都允许GET并不是一个好主意.(请参阅为什么不应该在HTTP上修改数据GET请求?)

Note though that doing this redirecting will only work if the view you are wrapping accepts a GET, and it's not a good idea to allow GETs for any operation that modifies data. (See Why shouldn't data be modified on an HTTP GET request?)

更新:如果您真的想要一个与POST一起使用的通用解决方案,我将切换到基于类的视图,并创建一个处理确认逻辑的mixin.像这样:

Update: If you really wanted a generic solution that worked with POSTs, I would switch to class-based views and create a mixin that handles the confirmation logic. Something like:

class ConfirmationViewMixin(object):
    confirmation_template = '_confirm.html'

    def get_confirmation_context(self):
        # implement this in your view class
        raise NotImplementedError()

    def post(self):
        if request.args.get('confirm') == '1':
            return super(ConfirmationViewMixin, self).post()

        return render_template(
            self.confirmation_template, **self.get_confirmation_context())

(未经测试,不确定会如何.但是您明白了.)

(That's untested, not sure how that would fare. But you get the idea.)

这篇关于烧瓶确认动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆