WTForms:取消

时间:2016-12-23 11:30:46

标签: python flask wtforms flask-wtforms flask-bootstrap

我要求的其实很简单。我想创建一个包含一些字段和提交以及取消按钮的表单。我想使用Flask-Bootstrap的quick_form模板函数来保持模板中的开销很低。我的表格如下:

from flask_wtf import FlaskForm
from wtforms.validators import Required, Length


class SequenceForm(FlaskForm):
    name = StringField('Name:', validators=[Required(), Length(1, 128)])

    # some other fields here

    submit = SubmitField('submit')
    cancel = SubmitField('cancel')

模板:

{% extends 'base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}

{% block content %}
  <div class="container">
    <form method="POST">
      <div class="row">
        <div class="col-xs-12">
          {{ wtf.quick_form(form, button_map={'submit': 'primary'}) }}
        </div>
      </div>
    </form>
  </div>
{% endblock %}

有人怀疑我想验证并接受 submit 上的输入值,并跳过 cancel 上的验证。所以我的视图功能看起来如预期。

@main.route('sequence/', methods=['GET', 'POST'])
def sequence():
    form = SequenceForm()
    if request.method == 'POST':
        if 'submit' in request.form:
            if form.validate_on_submit():
                print(form.duration.data)
        else:
            return redirect(url_for('main.index'))
    return render_template('sequence.html', form=form)

现在,如果按 cancel ,逻辑上应该没有验证,应该进行重定向。但是,由于客户端验证,如果我按提交取消,我遇到的问题是我的视图功能甚至都没有被调用。

<input class="form-control" id="name" name="name" required="" type="text" value="">

有没有办法在WTForms上禁用客户端验证?

4 个答案:

答案 0 :(得分:2)

由于您使用的是Flask-Bootstrap的quick_form()宏,因此只需将novalidate参数设置为True即可禁用客户端验证(它将novalidate属性设置为您的HTML <form>元素):

{{ wtf.quick_form(form, novalidate=True) }}

如果您使用的是Bootstrap-Flask,则方法类似:

{{ render_form(form, novalidate=True) }}

答案 1 :(得分:1)

Required验证程序以及DataRequiredInputRequired自WTForms版本3起取代Required设置了替换标志领域。此标志用于将 required 属性添加到字段的HTML表示中。我的解决方法是手动创建验证功能。

from wtforms.validators import ValidationError

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

class SequenceForm(FlaskForm):
    name = StringField('Name:', validators=[_required, Length(1, 128)])

    # some other fields here

    submit = SubmitField('submit')
    cancel = SubmitField('cancel')

这种方式在客户端没有验证,并且确保在每个提交取消上调用视图函数。

注意

更简单的解决方案是继承InputRequired验证器并覆盖field_flags字典。

from wtforms.validators import InputRequired

class MyInputRequired(InputRequired):
    field_flags = ()

class SequenceForm(FlaskForm):
    name = StringField('Name:', validators=[MyInputRequired(), Length(1, 128)])

答案 2 :(得分:1)

您可以禁止呈现required attr。

class MyTextInput(wtforms.widgets.TextInput):
    def __call__(self, field, **kwargs):
        kwargs['required'] = False
        return super().__call__(field, **kwargs)

对于Python2,添加如下所示的参数:super(MyTextInput, self)

然后:

name = StringField('Name:', validators=[Required(), Length(1, 128)], widget=MyTextInput())

答案 3 :(得分:0)

要禁用客户端表单验证,请将'novalidate'属性添加到模板中的HTML import android.content.Intent; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.RadioButton; import android.widget.Spinner; import android.widget.Toast; import com.google.android.gms.dynamic.ObjectWrapper; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.google.firebase.firestore.FirebaseFirestore; import java.util.HashMap; import java.util.Map; public class ProviderSignUp extends AppCompatActivity implements AdapterView.OnItemSelectedListener { private static final String TAG = "MainActivity"; private static final String KEY_FNAME = "First Name"; private static final String KEY_LNAME = "Last Name"; private static final String KEY_ADDRESS = "Address"; private static final String KEY_SPINNER_VALUE = "Spinner Value"; private static final String KEY_FIXED= "Fixed Rate"; private static final String KEY_HOURLY = "Hourly Rate"; private static final String KEY_AGE_VALE= "Age Value"; private static final String KEY_DOLLAR_VALUE = "Dollar Value"; private static final String KEY_YES_INSURED = "Yes Insured"; private static final String KEY_NO_INSURED = "No Insured"; private EditText fName; private EditText lName; private EditText address; private Spinner my_spinner; private RadioButton fixedRadioButton; private RadioButton hourlyRadioButton; private EditText ageEditText; private EditText dollarEditText; private RadioButton yesButton; private RadioButton noButton; // Reference to firestore database private FirebaseFirestore db = FirebaseFirestore.getInstance(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.provider_signup); Spinner spinner = findViewById(R.id.mySpinner); ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, R.array.provider_choices, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); spinner.setOnItemSelectedListener(this); // FireStore Storage for Provider fName = findViewById(R.id.firstName); lName = findViewById(R.id.lastName); address = findViewById(R.id.Address); my_spinner = (Spinner)findViewById(R.id.mySpinner); fixedRadioButton = findViewById(R.id.fixedRadioButton); hourlyRadioButton = findViewById(R.id.hourlyRadioButton); ageEditText = findViewById(R.id.ageEditText); dollarEditText = findViewById(R.id.dollarEditText); yesButton = findViewById(R.id.yesRadioButton); noButton = findViewById(R.id.noRadioButton); } @Override public void onBackPressed() { startActivity(new Intent(ProviderSignUp.this,PreSignUp.class)); finish(); } // These two methods below are for the spinner in the ProviderSignUp @Override // Will show a toast message after user selects spinner item public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) { String text = adapterView.getItemAtPosition(position).toString(); Toast.makeText(adapterView.getContext(), text, Toast.LENGTH_SHORT).show(); } @Override public void onNothingSelected(AdapterView<?> adapterView) { } String fname = fName.getText().toString(); String lname = lName.getText().toString(); String my_address = address.getText().toString(); String spinner = my_spinner.getSelectedItem().toString(); String fixed_radioButton = fixedRadioButton.getText().toString(); String hourly_Radiobutton = hourlyRadioButton.getText().toString(); String age = ageEditText.getText().toString(); String dollar = dollarEditText.getText().toString(); String yes_button = yesButton.getText().toString(); String no_button = noButton.getText().toString(); Map<String,Object> myMap = new HashMap<String,Object>(); myMap.put(KEY_FNAME,fname); myMap.put(KEY_LNAME,lname); myMap.put(KEY_ADDRESS, my_address); myMap.put(KEY_FIXED, fixed_radioButton); myMap.put(KEY_HOURLY, hourly_Radiobutton); myMap.put(KEY_AGE_VALE, age); myMap.put(KEY_DOLLAR_VALUE, dollar); myMap.put(KEY_YES_INSURED, yes_button); myMap.put(KEY_NO_INSURED, no_button); myMap.put(KEY_SPINNER_VALUE , spinner); db.collection("demoProviders").document("First Provider") .set(myMap).addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { Toast.makeText(ProviderSignUp.this, "User Saved", Toast.LENGTH_SHORT).show(); } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { Toast.makeText(ProviderSignUp.this, "Error!", Toast.LENGTH_SHORT).show(); Log.d(TAG, e.toString()); } }); } } 元素中:

<form>