Python wtforms QuerySelectField: возвращает что-то еще, кроме записи первичного ключа - PullRequest
0 голосов
/ 07 октября 2019

Я использую Flask для создания веб-приложения.

В двух словах: Когда мы отправляем форму, которая использует QuerySelectField + sqlalchemy для заполнения поля выбора, фактическое значение отправляетсякажется первичным ключом, но что, если мне нужно передать другое значение? Скажем, в таблице два столбца: ID и Item, теперь ID является первичным ключом, но пользователь выбирает строку не по идентификатору первичного ключа, а по Item, то есть то, что он видит в именах элементов, а не в идентификаторах первичного ключа. Но форма отправляет идентификаторы, я хочу вместо этого отправить имена элементов.

Мне трудно это объяснить, поэтому здесь длинная версия

Длинное объяснение

У меня есть модель, в которой таблица нутриональных значений содержит два столбца: «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)

Я создаю класс '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', я могу изменить параметры выбора на фактические элементы

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>

, но при отправке формы поле выбора возвращает «1» для «хлеба», но я хочу, чтобы оно возвращало «хлеб»

, потому чтоЗатем я использую это для ввода этих данных в другую таблицу следующим образом

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» как еду, которую я только что съел, я хочу ввести «хлеб».

Так как я могу использовать QuerySelectField + sqlalchemyинструментарий запроса для передачи фактического имени элемента обратно при отправке формы?

1 Ответ

1 голос
/ 08 октября 2019

Ответ очень похож на то, что вы уже делаете с get_label, где get_label принимает либо имя строкового атрибута, либо вызываемый из одного аргумента объект, которому передаются объекты для получения метки.

Из документации :

По большей части первичные ключи будут автоматически определяться из модели, поочередно передают один аргументможет вызываться для get_pk, который может возвращать уникальный сопоставимый ключ .

Несколько непоследовательно, аргумент get_pk не принимает имя строкового атрибута, только вызываемый один аргумент, но по существу делаетто же самое (ваша строка, переданная в get_label, превращается в вызываемую с одним аргументом, используя operator.attrgetter() [ source ]). Таким образом, вы можете контролировать поле вашего объекта, которое используется для идентификации выбранной опции, передавая вызываемое значение в get_pk, например, get_pk=operator.attrgetter("item") или get_pk=lambda x: x.item, чтобы сохранить импорт.

Вы можетехотите наложить уникальное ограничение на nutritionalvalues.item, если вы намереваетесь использовать его таким образом, чтобы избежать появления ошибок, если кто-то добавляет элемент с именем, которое уже существует.

...