Flask - Невозможно использовать валидаторы в подформах - PullRequest
3 голосов
/ 08 июля 2019

Моя точка зрения такова:

У меня есть вход FieldList с FloatFields на нем. Но валидаторы в этих вложенных полях не запускаются.

NumberRange отлично работает, когда у меня есть базовая форма. Но когда у меня есть вложенная форма, wtforms.validators.NumberRange вызывает следующую ошибку:

TypeError: '<' не поддерживается между экземплярами 'FloatField' и 'INT' </p>

Я не знаю, почему возникают такие ошибки?

Вот мой основной файл:

from flask import Flask, render_template, flash
from flask_wtf import FlaskForm
from wtforms import FloatField, SubmitField, StringField, FieldList, FormField
from wtforms.validators import NumberRange


app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'

class mySubForm(FlaskForm):
    class Meta:
        csrf = False
    mySubField = FloatField(validators=[NumberRange(min=-100, max=100)])

class myForm(FlaskForm):
    myField = FieldList(FormField(mySubForm))
    mySubmit = SubmitField("Save")


@app.route('/', methods=['GET','POST'])
def home():
    form = myForm()

    xLabels = ["A", "B", "C", "D"]

    for x in xLabels:
        subForm = mySubForm()
        form.myField.append_entry(subForm)

    if form.validate_on_submit():
        flash("success")

    return render_template("draft.html", form=form)


if __name__ == "__main__":
    app.run(host="127.0.0.1", port="5000" ,debug=True)

Вот мой шаблон:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .error{border-color: red;}
    </style>
  </head>
  <body>
    <div>
      <form method="POST" action="/">
        {{ form.hidden_tag() }}

        {% for field in form.myField %}
          {% if field.mySubField.errors %}
            {{ field.mySubField(class="error") }}
            {% for error in field.mySubField.errors %}
              <span>{{ error }}</span>
            {% endfor %}
          {% else %}
            {{ field.mySubField.data }}
          {% endif %}
        {% endfor %}

        {{ form.mySubmit() }}
      </form>

      {% with messages = get_flashed_messages(with_categories=False) %}
        {% if messages %}
          {% for message in messages %}
            <p>{{ message }}</p>
          {% endfor %}
        {% endif %}
      {% endwith %}
    </div>

  </body>
</html>

Ответы [ 2 ]

2 голосов
/ 13 июля 2019

Проблема в том, что append_entry не принимает поле, оно принимает необработанные данные, поэтому проверка завершается неудачно, потому что она сравнивает число с FloatField.

Также передается полевам нужно использовать mySubField.data в шаблоне вместо простого mySubField(), потому что mySubField отображает еще одно поле, которое вы передали.

Чтобы исправить это, выможет сделать что-то вроде

form.myField.append_entry({'mySubField': some_number})

, что, как уже упоминалось выше, позволит вам также исправить шаблон:

{% else %}
  {{ field.mySubField() }}
{% endif %}

Помимо этого, вы можете захотеть заключить в оболочку add_entryлогика условная, поэтому это происходит только в GET запросах, в противном случае вы будете добавлять новые записи каждый раз, когда отправляете форму.

0 голосов
/ 15 июля 2019

Спасибо Луису, вот рабочий код:

Мой основной файл:

from flask import Flask, render_template, flash, request
from flask_wtf import FlaskForm
from wtforms import FloatField, SubmitField, StringField, FieldList, FormField
from wtforms.validators import NumberRange


app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'


class myForm(FlaskForm):
    myField = FieldList(FloatField(validators=[NumberRange(min=-100, max=100)]))
    mySubmit = SubmitField("Save")


@app.route('/', methods=['GET','POST'])
def home():
    form = myForm()

    xLabels = ["A", "B", "C", "D"]

    if request.method == 'GET':
        for x in xLabels:
            form.myField.append_entry(data=42)

    if form.validate_on_submit():
        flash("success")

    return render_template("drat.html", form=form)


if __name__ == "__main__":
    app.run(host="127.0.0.1", port="5000" ,debug=True)

Шаблон:

<!DOCTYPE html>
<html>
  <head>
    <style>
      .error{border-color: red;}
    </style>
  </head>
  <body>
    <div>
      <form method="POST" action="/">
        {{ form.hidden_tag() }}

        {% for field in form.myField %}
          {% if field.errors %}
            <br>{{ field(class="error") }}
            {% for error in field.errors %}
              <span><br>{{ error }}</span>
            {% endfor %}
          {% else %}
            <br>{{ field }}
          {% endif %}
        {% endfor %}

        <br>{{ form.mySubmit() }}
      </form>

      {% with messages = get_flashed_messages(with_categories=False) %}
        {% if messages %}
          {% for message in messages %}
            <p>{{ message }}</p>
          {% endfor %}
        {% endif %}
      {% endwith %}
    </div>

  </body>
</html>
...