Error “No es una elección válida” en WTF.forms para SelectField actualizado dinámicamente.
Vi algunas preguntas similares sobre esta, pero ninguna de ellas tenía una respuesta clara. Así que intentaré hacerlo lo más claro posible.
Inicialmente publiqué la pregunta con parte de mi código real, que no era fácil de replicar ya que dependía de la conexión a la base de datos Oracle. Por lo tanto, hice una versión simplificada.
Así que, lo primero es lo primero. Lo que estoy haciendo es crear un formulario con 4 SelectField utilizando Flask. Las opciones para el primer SelectField están definidas en la definición de la clase (en la parte de la vista). Las opciones de los otros 3 SelecteFields se definen dinámicamente en función de las opciones de los campos anteriores.
El problema es que cuando envío el formulario, recibo un “No es una opción válida” para estos 3 campos.
Seguí este tutorial para crear esto.
El código de la vista (form_toy.py) es el siguiente
from flask import Flask, session, request, render_template, jsonify, url_for, redirect
from flask_wtf import FlaskForm
from wtforms import SelectField, SubmitField
from wtforms.validators import DataRequired
from flask_bootstrap import Bootstrap
import pandas as pd
app = Flask(name)
app.config[‘SECRET_KEY’] = ‘asdas8789)(&673’
bootstrap = Bootstrap(app)
class TestForm(FlaskForm):
df = pd.read_csv(‘db.csv’)
df1 = df[‘site’].drop_duplicates()
choices_site = []
i = 1
for _,v in df1.iteritems():
choices_site.append((i,v))
i = i + 1
site = SelectField("Site", coerce=int, choices=choices_site)
plant = SelectField("Plant", coerce=int, choices=[])
ctrl = SelectField("Ctrl", coerce=int, choices=[])
subctrl = SelectField("Sub", coerce=int, choices=[])
submit = SubmitField("OK")
@app.route(“/”, methods=[‘GET’, ‘POST’])
def index():
site = ”
plant = ”
ctrl = ”
subctrl = ”
form = TestForm()
if form.validate_on_submit():
site = form.site.data
plant = form.plant.data
ctrl = form.ctrl.data
subctrl = form.subctrl.data
return render_template('index.html',
form=form,
site=site,
plant=plant,
ctrl=ctrl,
subctrl=subctrl)
@app.route(“/plant/
def GetPlant(site):
plants_array = []
df = pd.read_csv(‘db.csv’)
df1 = df.loc[df[‘site’] == site]
df2 = df1[‘plant’].drop_duplicates()
i = 1
for _,p in df2.iteritems():
plants_array.append({'id':i,'plant':p})
i = i + 1
return jsonify({'plants':plants_array})
@app.route(“/ctrl/
def GetCtrl(site, plant):
ctrls_array = []
df = pd.read_csv(‘db.csv’)
df1 = df.loc[df[‘site’] == site]
df2 = df1.loc[df1[‘plant’] == plant]
df3 = df2[‘ctrl’].drop_duplicates()
i = 1
for _,c in df3.iteritems():
ctrls_array.append({'id':i,'ctrl':c})
i = i + 1
return jsonify({'ctrls':ctrls_array})
@app.route(“/subctrl/
def GetSubCtrl(site, plant, ctrl):
subctrls_array = []
df = pd.read_csv(‘db.csv’)
df1 = df.loc[df[‘site’] == site]
df2 = df1.loc[df1[‘plant’] == plant]
df3 = df2.loc[df2[‘ctrl’] == ctrl]
df4 = df3[‘subctrl’].drop_duplicates()
i = 1
for _,s in df4.iteritems():
subctrls_array.append({'id':i,'subctrl':s})
i = i + 1
return jsonify({'subctrls':subctrls_array})
El código de la plantilla (index.html) está aquí (puse todo en el mismo archivo por motivos de simplificación)
{% import “bootstrap/wtf.html” as wtf %}
{% block title %}FORM_VALIDATION{% endblock %}
{{ wtf.quick_form(form)}}
{% if form.errors %}
{{ form.errors}}
{% endif %}
davy.ai
El problema que estás enfrentando es con la validación de las opciones dinámicas de SelectField en tus WTForms. Cuando se envía el formulario, Flask-WTF verifica si los datos enviados para cada campo son una opción válida según lo definido en el parámetro
choices
de SelectField.En tu caso, las opciones para los tres SelectFields dinámicos (
plant
,ctrl
,subctrl
) se cargan de forma asíncrona usando JavaScript después de que la página se ha cargado. Flask-WTF no está al tanto de estas opciones dinámicas y por lo tanto genera el error “No es una opción válida”.Para resolver esto, es necesario anular la validación por defecto para estos campos en la clase del formulario. Puede hacer esto creando una función validadora personalizada que compruebe si los datos enviados son una de las opciones válidas que se generaron de forma asíncrona. Aquí tienes un ejemplo:
Luego, en la clase
TestForm
, puedes usar esta validación personalizada para los SelectFields dinámicos de la siguiente manera:Aquí, hemos agregado una función validadora personalizada para cada uno de los SelectFields dinámicos (
plant
,ctrl
,subctrl
) que comprueba si los datos enviados son una de las opciones válidas que se generaron de forma asíncrona. La funciónget_valid_choices()
debe ser una función que recupere las opciones válidas para cada uno de los SelectFields dinámicos en función de las opciones de los campos anteriores.Al agregar estas validaciones personalizadas, Flask-WTF las usará en lugar de la validación por defecto y ya no debería generarse el error “No es una opción válida”.
¡Espero que esto ayude! Hazme saber si tienes más preguntas.