Python wtforms QuerySelectField:返回主键条目以外的内容

Python wtforms QuerySelectField: Returning something else than the primary key entry

我正在使用 Flask 制作网络应用程序。

简而言之: 当我们提交一个使用 QuerySelectField + sqlalchemy 查询来填充 select 框的表单时,提交的实际值似乎是主要的键,但如果我需要提交另一个值怎么办?假设一个 table 有两列,ID 和 Item,现在 ID 是主键,但是用户 select 不是通过主键 ID 而是通过 Item,这就是他们看到的 Item 名称,不是主键 ID。但是表单提交了 ID,我不想提交项目名称。

我觉得这很难解释,所以这里是长版

详细解释

我有一个模型,它使 table nutrialvalues 有两列,'id' 是主键,'item' 列包含食物类型的名称。

class nutritionalvalues(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    item = db.Column(db.String(200), nullable=False)

    def __repr__(self):
        return '{}'.format(self.item)

现在使用 sqlalchemy 和 flaskforms

def choice_query():
    return nutritionalvalues.query

class ChoiceForm(FlaskForm):
    item = QuerySelectField(query_factory=choice_query, allow_blank=False)

我制作了 class 'ChoiceForm' 并用它制作了一个带有

的表格
form = ChoiceForm()
return render_template('index.html', form=form)

在 index.html 模板中我有标记

    <form action="/" method="POST">
        {{ form.csrf_token }}
        {{ form.item }}
        <input type="submit" value="Add Item">
    </form>

浏览器呈现时会生成 html 代码

<form action="/" method="POST">
    <select id="item" name="item">
        <option value="1">&lt;nutritionalvalues 1&gt;</option>
        <option value="2">&lt;nutritionalvalues 2&gt;</option>
        <option value="3">&lt;nutritionalvalues 3&gt;</option>
    </select>
    <input type="submit" value="Add Item">
 </form>

现在假设我使用 'get_label' 参数,我可以将 select 选项更改为实际项目

class ChoiceForm(FlaskForm):
    item = QuerySelectField(query_factory=choice_query, allow_blank=False, get_label='item')

所以 html 呈现这样

<form action="/" method="POST">
    <select id="item" name="item">
        <option value="1">bread</option>
        <option value="2">salmon</option>
        <option value="3">pork</option>
    </select>
    <input type="submit" value="Add Item">
 </form>

但是在提交表单时,select 框 returns '1' for 'bread',但我希望它 return 'bread'

因为我然后用它把这个数据输入另一个table如下

if request.method == 'POST':
    food_item = request.form['item']
    new_food = eaten(item=food_item)

    try:
        db.session.add(new_food)
        db.session.commit()
        return redirect('/')

我不想输入“1”作为我刚吃的食物,我想输入 'bread'。

那么如何使用QuerySelectField + sqlalchemy查询工具包在提交表单时将实际项目名称传回?

答案与您已经在使用 get_label 所做的非常相似,其中 get_label 要么接受字符串属性名称,要么接受对象按顺序传递给的单参数可调用对象导出标签。

来自documentation:

For the most part, the primary keys will be auto-detected from the model, alternately pass a one-argument callable to get_pk which can return a unique comparable key.

有点不一致,get_pk 参数不接受字符串属性名称,只有一个参数可调用,但本质上做同样的事情(传递给 get_label 的字符串变成使用 operator.attrgetter() [source] 可调用的单参数)。因此,您可以通过将可调用对象传递给 get_pk 来控制用于标识所选选项的对象字段,例如 get_pk=operator.attrgetter("item"),或者 get_pk=lambda x: x.item 将为您节省导入。

如果您打算以这种方式使用它,您可能需要对 nutritionalvalues.item 施加唯一约束,以确保在有人添加名称已存在的项目时不会出现错误。