Flask-WTF:同一类的多种形式都在提交时返回相同的数据

时间:2017-12-18 00:16:04

标签: python flask wtforms flask-wtforms

我正在生成多个表单,每个图像一个,并将图像和相应的表单打包为列表中的元组。

然后将此列表传递给Jinja,其中每个元组都被解压缩,每个图像和表单都插入到列表中以便通过表单进行投票。

我的问题是点击任何一个特定表单会导致所有表单都返回,就像点击了该按钮一样。

因此,实际上,对一张图像进行向上或向下投票就像对所有其他图像点击该按钮一样。

我知道我正在创建合法的表单,因为我尝试打印表单并将数据返回到控制台。当我这样做时,每个表单都有一个唯一的地址,并且所有表单在form.field.data属性中显示相同的数据(True / False)。 有人可以帮我发现这里发生了什么吗?

形式:

class VoteForm(FlaskForm):
    upvote = SubmitField('vote up')
    downvote = SubmitField('vote down')

路线:

@index_mod.route('/', methods = ['GET', 'POST'])
def index():
    pics = Pic.select().order_by(Pic.score.desc())

    pics_and_forms = []

    for pic in pics:
        voteform = VoteForm()
        #tuple of pic and corresponding form
        pics_and_forms.append( (pic, voteform) )

    for pic, form in pics_and_forms:
        if form.validate_on_submit():
            if form.upvote.data:
                pic.score += 1
                pic.save()
            if form.downvote.data:
                pic.score -= 1
                pic.save()              

    return render_template('index.html', pics_and_forms = pics_and_forms)

金贾:

<ul>
    {% for pic, form in pics_and_forms %}
    <li>
        <b>{{ pic.name }}  </b>
        <i>Submitted by {{ pic.user.username }}</i>
        Score: {{ pic.score }}
        <img src="/pic/get/{{ pic.uuid }}" style="width:128px;" >

        <form method="post" action=" {{ url_for('index_mod.index') }}">
        {{ form.csrf_token }}
        {{ form.upvote }}
        {{ form.downvote }}
        </form>

    </li>
    {% endfor %}
</ul>

修改

所以我正在弄清楚,虽然我可以在页面上嵌入尽可能多的表单,但是我想要返回的帖子请求并没有指定点击了哪个特定表单。

相反,我打算将细节嵌入隐藏字段,然后使用烧瓶请求对象从隐藏表单中检索该字段。

我宁愿完全使用Flask-WTF,但似乎没有优雅的方法可以动态地向页面添加多个表单并检索实际点击的表单。

1 个答案:

答案 0 :(得分:0)

You're only ever submitting one form at a time, so you really only need to be dealing with one Form object. I think a better approach would be to POST to a URL which contains the ID of the Pic you're voting on, and the up/down vote is captured from the submit button clicked.

I've refactored your code to illustrate this:

app.py

from flask import Flask, render_template, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import SubmitField


app = Flask(__name__)
app.secret_key = 'secret'


class VoteForm(FlaskForm):
    upvote = SubmitField('vote up')
    downvote = SubmitField('vote down')


@app.route("/", methods=['GET'])
def index():

    form = VoteForm()

    pics = [
        {
            "name": "test",
            "user": {"username": "test"},
            "score": 1,
            "uuid": 'test'
        },
        {
            "name": "test2",
            "user": {"username": "test"},
            "score": 2,
            "uuid": 'test2'
        }
    ]

    return render_template("index.html", form=form, pics=pics)


@app.route("/pic/<id>/vote", methods=['POST'])
def vote(id):

    form = VoteForm()

    if form.validate_on_submit():
        if form.upvote.data:
            print("Upvote for pic {}".format(id))
        if form.downvote.data:
            print("Downvote for pic {}".format(id))

    return redirect(url_for('index'))


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

index.html

<ul>
    {% for pic in pics %}
    <li>
        <b>{{ pic.name }}  </b>
        <i>Submitted by {{ pic.user.username }}</i>
        Score: {{ pic.score }}
        <img src="/pic/get/{{ pic.uuid }}" style="width:128px;" >

        <form method="post" action="{{ url_for('vote', id=pic['uuid']) }}">
        {{ form.csrf_token }}
        {{ form.upvote }}
        {{ form.downvote }}
        </form>

    </li>
    {% endfor %}
</ul>