Agregue un botón de cancelación en Flask con Flask-WTF/WTForms

Aug 16 2020

Me gustaría agregar un botón de cancelar que regrese a la página anterior. Mi código es: formularios.py:

from flask_wtf import Form
from wtforms import StringField, HiddenField, SubmitField
from wtforms.validators import DataRequired, Length, ValidationError


def _required(form, field):
    if not field.raw_data or not field.raw_data[0]:
        raise ValidationError('Field is required')

class OrganisationForm(Form):
    id = HiddenField('id', default="-1")
    name = StringField('name', validators=[DataRequired()])
    manager_name = StringField('manager_name')
    address = StringField('address', validators=[DataRequired()])
    city = StringField('city', validators=[DataRequired()])
    postal_code = StringField('postal_code', validators=[DataRequired(), Length(max=16)])
    province = StringField('province', validators=[Length(max=2, message="Can't exceed 2 characters")])
    country = StringField('country', validators=[DataRequired()])
    submit = SubmitField('Add')
    cancel = SubmitField('Cancel')

y página de plantilla:

{% block content %}
<div class="content-section">
  {{ utils.flashed_messages() }}
  <div class="center">

      {% if add_orgnisation %}
                <h1>add an organisation</h1>
            {% else %}
                <h1>Edit an organisation</h1>
      {% endif %}
    <br/>
    <br/>
    {{ wtf.quick_form(form,novalidate=True) }}
  </div>
</div>
{% endblock %}

vistas

@orgs.route('/organisations/org_new')
@login_required
def org_new():
    add_orgnisation = True
    form = OrganisationForm()
    return render_template("organisations/organisation_form.html", form=form, title="New Organisation", edit=False, add_orgnisation=add_orgnisation)

Tengo un error 405 cuando hago clic en el botón cancelar: Método no permitido.

¿Dónde está mi error? y ¿qué debo agregar para volver a la página anterior cuando hago clic en Cancelar?

Gracias

Respuestas

baldy Sep 16 2020 at 10:12

No, estoy usando TimeField para forzar la captura de un tiempo válido. No he intentado cambiar eso a un campo de texto normal, así que opté por la opción Cancelar enlace de arriba. Sin embargo, mi preferencia sigue siendo tener un botón Cancelar.

3 GreyLi Aug 17 2020 at 13:19

Tengo un error 405 cuando hago clic en el botón cancelar: Método no permitido. ¿Dónde está mi error?

Cuando envíe el formulario, los datos se enviarán como una solicitud POST (porque el elemento del formulario representado utilizará <form method="post">). Sin embargo, su función de vista solo permite la solicitud GET de forma predeterminada, para aceptar la solicitud POST, debe especificar el methodsparámetro de esta manera:

@orgs.route('/organisations/org_new', methods=['GET', 'POST'])  # <--
@login_required
def org_new():
   # ...

y ¿qué debo agregar para volver a la página anterior cuando hago clic en Cancelar?

Cualquier campo creado con SubmitFieldse representará como un botón de envío ( <input type="submit">), por lo que enviará el formulario cuando haga clic en él.

Para hacer que regrese a la página anterior cuando hace clic en el botón cancelar, normalmente hay dos métodos para lograrlo:

1. Atrapa el botón enviar en la función de vista

Como el método en la respuesta de Ben . Puede capturar el envío y luego redirigir al usuario a la página anterior:

@orgs.route('/organisations/org_new', methods=['GET', 'POST'])
@login_required
def org_new():
    if request.method == 'POST':
        if form.cancel.data:  # if cancel button is clicked, the form.cancel.data will be True
            return redirect(url_for('previous_page_view_name'))
    # ...

PD Como ya lo ha configurado novalidate=True, wtf.quick_formno necesita configurar render_kw={'formnovalidate': True}el cancelbotón en la clase de formulario.

2. Crea un <a>botón en lugar de un cancelcampo

Puede crear un <a>elemento normal como botón de cancelación ( class="btn btn-secondary") y completar el hrefparámetro con la URL de la página anterior (entonces no necesita agregar un cancelcampo en su clase de formulario). De esta manera, no puede usar wtf.quick_form(), en su lugar, deberá representar cada campo manualmente con wtf.form_field():

<form method="post">
    {{ wtf.form_field(form.id) }}
    {{ wtf.form_field(form.name) }}
    {{ wtf.form_field(form.manager_name) }}
    {{ wtf.form_field(form.address) }}
    ...
    {{ wtf.form_field(form.submit) }}
    <a href="{{ url_for('previous_page_view_name') }}" class="btn btn-secondary">Cancel</a>
</form>
3 Ben Aug 17 2020 at 08:06

Así es como esto funciona para mí.

En mi forma...

btn_cancel = SubmitField(label='Cancel',
                         render_kw={'formnovalidate': True})

En mi código de Python (views.py en su caso)...

if request.method == 'POST':
    if form.btn_cancel.data:
        return redirect(url_for('data'))

Edición de última hora: la nota de Gray Li a continuación sobre permitir que su función de vista acepte solicitudes POST también es importante. Asegúrate de comprobarlo.