将参数传递给 for 循环中的视图函数(表单)以填充表单 flask wtforms sqlalchemy

pass a parameter to a view function (form) in a for loop to populate form flask wtforms sqlalchemy

我希望能够在我的网页上将数据库模型的行显示为可更新的预填充表单!我可以轻松地在页面上显示行,我可以向每个行添加一个 link 以打开一个单独的页面来编辑每一行,我还可以使用更新表单显示每一行,但我无法显示填充的表单。这是我的代码:

@bp.route('/stock', methods=['GET', 'POST'])
@bp.route('/stock/<int:id>', methods=['GET', 'POST'])
@login_required
def stock(id=None):
    if id is not None:
        obj = Stock.query.get_or_404(id)
        form = AddStockForm(request.form, obj=obj)
        if form.validate_on_submit():
            form.populate_obj(obj)
            db.session.commit()
        return redirect(url_for('stock.stock'))
    else:
        form = AddStockForm()
        page = request.args.get('page', 1, type=int)
        stock = Stock.query.order_by(Stock.id.desc()).paginate(
        page, current_app.config['ITEMS_PER_PAGE'], False)
        next_url = url_for('stock.stock', page=stock.next_num) \
            if stock.has_next else None
        prev_url = url_for('stock.stock', page=stock.prev_num) \
            if stock.has_prev else None
        return render_template('stock/stock.html',form=form, title=Stock, stock=stock.items,
             next_url=next_url, prev_url=prev_url)

和stock.html代码:

{% extends "base.html" %}

{% block content %}
<div class="main">
    <h2>Stock</h2>
    <div class="books"><a href="{{ url_for('stock.upload_stock') }}">Upload Stock csv</a> 
</div>
    <div class="books"><a href="{{ url_for('stock.add_stock') }}">Add a new Item</a></div>
    {% for s in stock %}
        {% include 'stock/_stock.html' %}
    {% endfor %}
</div>

_stock.html代码:

<div class="stock">
    <div class="c0"><img src="{{ s.image_url }}" alt="{{ s.image_filename }}"></div>

        <form action="{{ url_for('stock._stock', id=s.id) }}" method="post", 
           enctype="multipart/form-data">
            {{ form.hidden_tag() }}
            <div>SKU<BR> {{ s.id }} </div>
            <div>Date of Purchase<br>{{ form.date(class="input") }}</div>
            <div>Description<br>{{ form.description(class="input") }}</div>
            <div>Market<br>{{ form.event(class="input") }}</div>
            <div>Purchase Price<br>{{ form.achat(class="input") }}</div>
            <div>Sale Price<br>{{ form.vente(class="input") }}</div>
            <div>Sold<br>{{ form.sold(class="input") }}</div>
            <div>{{ form.submit(class="submit") }}</div>
        </form>

</div>

在 google 开发者工具上每个表单显示 stock/4 或 3 但这似乎并没有填充表单。没有错误消息。 在此先感谢您的帮助。 问候保罗

编辑 嗨@Greg Cowell,谢谢你的帮助,我已经添加了你的代码但是我得到了这个错误

  File "/var/www/accounts/bdf/templates/base.html", line 30, in root
</body>
  File "/var/www/accounts/env/lib/python3.7/site-packages/jinja2/runtime.py", line 262, in call
return __obj(*args, **kwargs)
  File "/var/www/accounts/env/lib/python3.7/site-packages/flask/helpers.py", line 370, in url_for
return appctx.app.handle_url_build_error(error, endpoint, values)
  File "/var/www/accounts/env/lib/python3.7/site-packages/flask/app.py", line 2215, in handle_url_build_error
reraise(exc_type, exc_value, tb)
  File "/var/www/accounts/env/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
  File "/var/www/accounts/env/lib/python3.7/site-packages/flask/helpers.py", line 358, in url_for
endpoint, values, method=method, force_external=external
  File "/var/www/accounts/env/lib/python3.7/site-packages/werkzeug/routing.py", line 2020, in build
raise BuildError(endpoint, values, method, self)
werkzeug.routing.BuildError: Could not build url for endpoint 'stock.stock'. Did you forget to specify values ['id']?
[pid: 29588|app: 0|req: 1/1] 192.168.0.13 () {48 vars in 1095 bytes} [Sun Nov 17 09:26:58 2019] GET /index =>

这里是修改后的代码:

@bp.route('/stock/stock/<int:id>/', methods=['GET', 'POST'])
@login_required
def stock(id=None):
    if id is not None:
        group = current_user.group()
        try:
            stock = Stock.query.filter_by(group=group, id=id).one()
        except NoResultFound:
            flash('Invalid account.')
            return redirect(url_for('stock.add_stock'))
        accounts = current_user.group().stock
        form = AddStockForm()
        form.stock_id.default = stock.id
        if form.validate_on_submit():
            if form.modify.data:
                for s in stock:
                    if (
                        item.id == form.stock_id.data and
                        item.id != form.stock_id.default
                    ):
                        flash('Another account already has this name.')
                        return redirect(url_for('stock.add_stock', id=id))
                stock.id = form.stock_id.data
                db.session.add(stock)
            db.session.commit()
        form.process()  # Do this after validate_on_submit or breaks CSRF token
    else:
        form = AddStockForm()
        page = request.args.get('page', 1, type=int)
        stock = Stock.query.order_by(Stock.id.desc()).paginate(
             page, current_app.config['ITEMS_PER_PAGE'], False)
        next_url = url_for('stock.stock', page=stock.next_num) \
            if stock.has_next else None
        prev_url = url_for('stock.stock', page=stock.prev_num) \
            if stock.has_prev else None
    return render_template('stock/stock.html',form=form, title=Stock, stock=stock.items,
         next_url=next_url, prev_url=prev_url)

第二次编辑

我在视图函数的顶部添加了这个:

@bp.route('/stock', methods=['GET', 'POST'])

消除了上述错误,然后我得到了类似的错误 "stock.html code"

    {% for s in stock %}
        {% include 'stock/_stock.html' %}
    {% endfor %}

我改成了:

   {% include {{ url_for('stock._stock', id=['s.id']) }} %}

这给了我以下错误:

jinja2.exceptions.TemplateSyntaxError: expected token ':', got '}'

我使用不同的方法来预填充表单。

总而言之,我为每个表单字段设置了默认值,并在呈现之前处理表单。在下面的示例中,我使用 form.account_name.default = account.accname 设置 account_name 字段默认值,然后在呈现表单之前调用 form.process()

@web.route('/accounts/modify/<int:accno>/', methods=['GET', 'POST'])
@login_required
def modify_account(accno):
    """
    Modify or delete accounts.
    Return a form for modifying accounts or process submitted
    form and redirect to Accounts HTML page.
    """
    group = current_user.group()
    try:
        account = Account.query.filter_by(group=group, accno=accno).one()
    except NoResultFound:
        flash('Invalid account.')
        return redirect(url_for('.accounts_page'))
    accounts = current_user.group().accounts
    form = ModifyAccountForm()
    form.account_name.default = account.accname

    if form.validate_on_submit():
        if form.modify.data:
            for item in accounts:
                if (
                    item.accname == form.account_name.data and
                    item.accname != form.account_name.default
                ):
                    flash('Another account already has this name.')
                    return redirect(url_for('.modify_account', accno=accno))
            account.accname = form.account_name.data
            db.session.add(account)
            db.session.commit()
        elif form.delete.data:
            for transaction in current_user.group().transactions:
                if transaction.account == account:
                    unknown_account = Account.query.filter_by(
                        group=current_user.group(), accname='Unknown').one()
                    transaction.account = unknown_account
                    db.session.add(transaction)
                    db.session.commit()
            db.session.delete(account)
            db.session.commit()
        elif form.cancel.data:
            pass
        return redirect(url_for('.accounts_page'))

    form.process()  # Do this after validate_on_submit or breaks CSRF token

    return render_template(
        'modify_account.html', form=form, accno=accno, menu="accounts")

要制作一个 HTML 页面,其中每条记录都有一个表单,每条记录都有一个单独的提交按钮,您需要在 view/route 函数中创建多个表单,然后循环遍历它们在您的 HTML 模板中。

View/route:

@web.route('/stocks', methods=['GET', 'POST'])
def stocks():
    """Return Stocks HTML page."""
    stocks = Stock.query.all()
    forms = []
    for stock in stocks:
        form = ModifyStockForm()
        form.stock_id.default = stock.stock_id
        form.stock_name.default = stock.stock_name
        forms.append(form)

    for form in forms:
        if form.validate_on_submit():
            if form.modify.data:
                stock = Stock.query.filter_by(stock_id=form.stock_id.data).one()
            stock.stock_name = form.stock_name.data
            db.session.add(stock)
            db.session.commit()
        elif form.delete.data:
            stock = Stock.query.filter_by(stock_id=form.stock_id.data).one()
            db.session.delete(stock)
            db.session.commit()
        return redirect(url_for('.stocks'))

        form.process()  # Do this after validate_on_submit or breaks CSRF token

return render_template('stocks.html', forms=forms, stocks=stocks)

模板:

<h2>Stocks:</h2>

   {% for form in forms %}

    <form method="post" role="form" enctype="multipart/form-data">
        {{ form.hidden_tag() }}

        {{ form.stock_id }}
        {{ form.stock_name }}
        {{ form.modify }}
        {{ form.delete }}

    </form>

   {% endfor %}

我在这个 repo 中放了一个完整的例子:Example of multiple forms on a single page