Dodaj przycisk anulowania w Flask z Flask-WTF / WTForms

Aug 16 2020

Chciałbym dodać przycisk anulowania, który powoduje powrót do poprzedniej strony. Mój kod to: forms.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')

i strona szablonu:

{% 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 %}

widoki, py

@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)

Po kliknięciu przycisku anulowania pojawia się błąd 405: Metoda niedozwolona.

Gdzie jest mój błąd? a co powinienem dodać, aby wrócić do poprzedniej strony po kliknięciu przycisku Anuluj?

dzięki

Odpowiedzi

baldy Sep 16 2020 at 10:12

Nie, używam TimeField do wymuszenia przechwytywania prawidłowego czasu. Nie próbowałem zmienić tego na zwykłe pole tekstowe, więc zamiast tego skorzystałem z opcji Anuluj link powyżej. Jednak nadal wolę mieć przycisk Anuluj.

3 GreyLi Aug 17 2020 at 13:19

Po kliknięciu przycisku anulowania pojawia się błąd 405: Metoda niedozwolona. Gdzie jest mój błąd?

When you submit the form, the data will be sent as a POST request (because the rendered form element will use <form method="post">). However, your view function only allow GET request as default, to accept POST request, you have to specified the methods parameter like this:

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

and what should I add to have a go back previous page when I click on Cancel?

Any field created with SubmitField will rendered as a submit button (<input type="submit">), so it will submit the form when you click it.

To make it go back to the previous page when you click the cancel button, there are normally two methods to achieve this:

1. Catch the button submit in view function

Like the method in Ben's answer. You can just catch the submit then redirect the user to previous page:

@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'))
    # ...

PS Skoro masz już ustawione novalidate=Truew wtf.quick_form, nie trzeba ustawić render_kw={'formnovalidate': True}na cancelprzycisk w klasie formularza.

2. Utwórz <a>przycisk zamiast cancelpola

Możesz utworzyć zwykły <a>element jako przycisk anulowania ( class="btn btn-secondary") i wypełnić hrefparametr adresem URL poprzedniej strony (wtedy nie musisz dodawać cancelpola w swojej klasie formularza). W ten sposób nie możesz użyć wtf.quick_form(), zamiast tego będziesz musiał renderować każde pole ręcznie za pomocą 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

Oto jak to działa w moim przypadku.

W mojej formie ...

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

W moim kodzie Pythona (w twoim przypadku views.py) ...

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

Edycja z ostatniej chwili: Ważna jest również uwaga Graya Li poniżej o zezwoleniu funkcji widoku na akceptowanie żądań POST. Koniecznie sprawdź to.