根据查询字符串值创建 FlaskForm 下拉列表

Create a FlaskForm dropdown based on the query string value

class DownloadForm(FlaskForm):    
products = service.get_products()
        choices = [(product, product.replace('-', ' '))
                       for product in products]

application = SelectField(
        'Application',
        [DataRequired()],
        choices=choices

submit = SubmitField('Submit')




@home.route('/downloads/<application_name>', methods=['GET', 'POST'])
def downloads():
    download_form = DownloadForm()

我的路线是downloads/application_name。 我可以将此路由值“application_name”发送到表单以过滤掉下载表单中的选择吗? 我是整个烧瓶的新手 python.

您可以使用工厂函数来使用 URL 中的参数来执行数据库查询。基于这个查询,然后创建一个可以在路由中使用的表单。

def download_form_factory(name):
    products = [
        'Archiver',
        'Editor-1',
        'Editor-2', 
        'Music-Player', 
        'Video-Player'
    ]
    class DownloadForm(FlaskForm):
        app = SelectField(
            'Application',
            choices= [
                (product, product.replace('-', ' ')) \
                for product in filter(lambda p: name.lower() in p.lower(), products)
            ]
        )
        submit = SubmitField('Download')
    return DownloadForm

以下示例使用QuerySelectField from WTForms-SQLAlchemy类型的输入字段来方便数据库查询。正如您在上面看到的,正常的 SelectField.

也可以实现该功能

许多产品被添加到数据库中,除了它们的名称外,还有一个额外的 属性 构建。
如果用户在索引页面上选择一个名称,则所有具有所选名称的产品都可供选择。然后他可以在提供的版本之间进行选择。

表单是在函数内部创建的。要搜索的名称作为参数传递给此函数。然后可以使用它来创建数据库查询。

def download_form_factory(name):
    # Create a class of the form.
    class DownloadForm(FlaskForm):
        # Create the select field
        app = QuerySelectField(
            # with a label
            'Application', 
            # and the database entries containing the given name as options
            query_factory=lambda: Product.query.filter(Product.name.ilike(f'%{name}%')).all(),
            # and a label for each of these options.
            get_label=lambda p: '%s (Build %s)' % (p.name, p.build),
            # An option must be selected by the user.
            validators=[InputRequired()]
        )
        # Create the Submit button.
        submit = SubmitField('Download')
    # Return the created form class.
    return DownloadForm

在端点内,使用提到的函数并创建表单实例,可以按通常方式使用。

@app.route('/download/<string:name>', methods=['GET', 'POST'])
def download(name):
    # Create the form and an instance of it.
    form = download_form_factory(name)(request.form)
    if form.validate_on_submit():
        # If the POST request is sent with valid information, 
        # the form data can be requested.
        # The result is the selected database object.
        print(form.app.data)
    return render_template('download.html', **locals())

这是完整的例子。

烧瓶 (app.py)
from flask import (
  Flask,
  render_template,
  request,
)
from flask_wtf import FlaskForm
from flask_sqlalchemy import SQLAlchemy
from wtforms import SubmitField
from wtforms_sqlalchemy.fields import QuerySelectField
from wtforms.validators import InputRequired

app = Flask(__name__)
app.secret_key = b'your secret here'
db = SQLAlchemy(app)

class Product(db.Model):
    __table_args__ = (db.UniqueConstraint('name', 'build'),)
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=False)
    build = db.Column(db.String, nullable=False)

# Create a class of the form.
def download_form_factory(name):
    class DownloadForm(FlaskForm):
        app = QuerySelectField(
            'Application',
            get_label=lambda p: f'{p.name} (Build {p.build})',
            query_factory=lambda: Product.query.filter(Product.name.ilike(f'%{name}%')).all(),
            validators=[InputRequired()]
        )
        submit = SubmitField('Download')
    return DownloadForm

# Fill the database with sample data.
with app.app_context():
    db.drop_all()
    db.create_all()
    products = [Product(name=f'Product-{str(i).zfill(2)}', build=f'{j}') \
        for i in range(1, 21) for j in range(1,i+1)]
    db.session.add_all(products)
    db.session.commit()

@app.route('/')
def index():
    products = Product.query.group_by(Product.name).order_by(Product.name).all()
    return render_template('index.html', **locals())

@app.route('/download/<string:name>', methods=['GET', 'POST'])
def download(name):
    # Create the final object of the form.
    form = download_form_factory(name)(request.form)
    if form.validate_on_submit():
        # Inquire about the selected product.
        print(form.app.data)
    return render_template('download.html', **locals())
HTML (templates/index.html)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Index</title>
  </head>
  <body>
    <ul>
      {% for prod in products -%}
      <li><a href="{{ url_for('download', name=prod.name)}}">{{prod.name}}</a></li>
      {% endfor -%}
    </ul>
  </body>
</html>
HTML (templates/download.html)
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Download</title>
  </head>
  <body>
    <form method="post">
      {{ form.csrf_token }}
      <div>
        {{ form.app.label }}
        {{ form.app() }}
      </div>
      {{ form.submit() }}
    </form>
  </body>
</html>