I'm having trouble passing through validation when using a FieldList
with WTForms. I keep getting this error. {'csrf_token': [u'CSRF token missing']}
. The problem is if I do not have any data to validate in the FieldList
field, the validation passes and there are no issues. But when I try to validate the form with any data I get that error.
Here are my forms:
class FilterForm(wtf.Form):
filter_value = wtf.TextField('Value', validators=[validators.Required()])
filter_operator = wtf.SelectField('Operator', validators=[validators.Required()])
filter_compare_value=wtf.TextField('Compare Value', validators=[validators.Required()])
class RedirectForm(wtf.Form):
redirect_id = wtf.HiddenField('id')
redirect_name = wtf.TextField('Name', validators=[validators.Required()])
redirect_url = wtf.TextField('URL', validators=[validators.Required()])
redirect_type = wtf.SelectField('Type', validators=[validators.Required()])
redirect_method = wtf.SelectField('Method', validators=[validators.Required()])
redirect_active = wtf.BooleanField('Is Active')
redirect_filters_any = wtf.FieldList(wtf.FormField(FilterForm))
redirect_filters_all = wtf.FieldList(wtf.FormField(FilterForm))
The form seems to display correctly and works fine until I add data to either redirect_filters_any
or redirect_filters_all
Is there a way to disable csrf for the FieldList
or pass a CSRF value to the FieldList
? I want to keep CSRF protection enabled but can not seem to get past this validation problem.
Here is the Jinja2 template
{% extends "base.html" %}
{% set active_page = "endpoints" %}
{% block tail_script %}
<script src="/static/js/page/redirects.js"></script>
{% endblock %}
{% block content %}
<div class="row12">
<div class="span12">
<ul class="breadcrumb">
<li><a href="{{ url_for('list_endpoints') }}">Endpoints</a> <span class="divider">/</span></li>
<li><a href="{{ url_for('show_endpoint', id=endpoint_id) }}">{{endpoint_name}}</a> <span class="divider">/</span></li>
{% if redirect_id != 'new' %}
<li class="active">{{ form.redirect_name.data }}</li>
{% else %}
<li class="active">New</li>
{% endif %}
</ul>
<form action="{{ url_for('edit_redirect', endpoint_id=endpoint_id, redirect_id=redirect_id) }}" class="form-horizontal" method="post">
<legend>General</legend>
{{ form.hidden_tag() }}
<div class="control-group {% if form.redirect_name.errors %}error{% endif %}">
<div class="control-label">{{ form.redirect_name.label }}</div>
<div class="controls">
{{ form.redirect_name|safe }}
{% if form.redirect_name.errors %}
<span class="help-inline">
<ul class="errors">
{% for error in form.redirect_name.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
{% endif %}
</div>
</div>
<div class="control-group {% if form.redirect_type.errors %}error{% endif %}">
<div class="control-label">{{ form.redirect_type.label }}</div>
<div class="controls">
{{ form.redirect_type|safe }}
{% if form.redirect_type.errors %}
<span class="help-inline">
<ul class="errors">
{% for error in form.redirect_type.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
{% endif %}
</div>
</div>
<div class="control-group {% if form.redirect_active.errors %}error{% endif %}">
<div class="control-label">{{ form.redirect_active.label }}</div>
<div class="controls">
{{ form.redirect_active|safe }}
{% if form.redirect_active.errors %}
<span class="help-inline">
<ul class="errors">
{% for error in form.redirect_active.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
{% endif %}
</div>
</div>
<div class="control-group {% if form.redirect_method.errors %}error{% endif %}">
<div class="control-label">{{ form.redirect_method.label }}</div>
<div class="controls">
{{ form.redirect_method|safe }}
{% if form.redirect_method.errors %}
<span class="help-inline">
<ul class="errors">
{% for error in form.redirect_method.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
{% endif %}
</div>
</div>
<div class="control-group {% if form.redirect_url.errors %}error{% endif %}">
<div class="control-label">{{ form.redirect_url.label }}</div>
<div class="controls">
{{ form.redirect_url|safe }}
{% if form.redirect_url.errors %}
<span class="help-inline">
<ul class="errors">
{% for error in form.redirect_url.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
{% endif %}
</div>
</div>
<legend>Meet All Filters <a href="#" class="btn addAllFilter">Add</a></legend>
<table class="stable-striped" id="all_filter_table">
<tbody>
{% for f in form.redirect_filters_all %}
<tr style="vertical-align:top;">
<td>
{{ f.filter_value }}
{% if f.filter_value.errors %}
<br>
<div class="control-group error">
<span class="help-inline">
<ul class="errors">
{% for error in f.filter_value.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
</div>
{% endif %}
</td>
<td>
{{ f.filter_operator }}
{% if f.filter_operator.errors %}
<br>
<div class="control-group error">
<span class="help-inline">
<ul class="errors">
{% for error in f.filter_operator.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
</div>
{% endif %}
</td>
<td>
{{ f.filter_compare_value }}
{% if f.filter_compare_value.errors %}
<br>
<div class="control-group error">
<span class="help-inline">
<ul class="errors">
{% for error in f.filter_compare_value.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
</div>
{% endif %}
</td>
<td><a href="#" class="btn remove">Remove</a></td>
</tr>
{% endfor %}
</tbody>
</table>
<legend>Meet Any Filters <a href="#" class="btn addAnyFilter">Add</a></legend>
<table class="stable-striped" id="any_filter_table">
<tbody>
{% for f in form.redirect_filters_any %}
<tr style="vertical-align:top;">
<td>
{{ f.filter_value }}
{% if f.filter_value.errors %}
<br>
<div class="control-group error">
<span class="help-inline">
<ul class="errors">
{% for error in f.filter_value.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
</div>
{% endif %}
</td>
<td>
{{ f.filter_operator }}
{% if f.filter_operator.errors %}
<br>
<div class="control-group error">
<span class="help-inline">
<ul class="errors">
{% for error in f.filter_operator.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
</div>
{% endif %}
</td>
<td>
{{ f.filter_compare_value }}
{% if f.filter_compare_value.errors %}
<br>
<div class="control-group error">
<span class="help-inline">
<ul class="errors">
{% for error in f.filter_compare_value.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</span>
</div>
{% endif %}
</td>
<td><a href="#" class="btn remove">Remove</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% if g.user.user_type == 'admin' %}
<div class="control-group">
<div class="controls">
<input class="btn btn-primary" type="submit" value="Save"/>
<a href="{{url_for('show_endpoint', id=endpoint_id)}}" class="btn">Cancel</a>
</div>
</div>
{% endif %}
</form>
</div>
</div>
{% endblock %}
The issue seems to be that Flask-WTForms Form
is actually a subclass of wtforms.ext.SecureForm
- and the only way to disable the csrf protection on a form is to pass the keyword argument csrf_enabled=False
to the form when constructing it. Since FormField
actually handles instantiating the form and you can either:
FormField
that will let you pass in form keyword argumentswtforms.Form
rather than flask.ext.wtforms.Form
for your FilterForm
(as long as you never display a FilterForm
on its own you won't need to worry about CSRF).After encountering the same problem, I wanted to to supply a third option to the solution above
You can also override the constructor in your form class to replace the default value of csrf_enabled. This has the advantage that you can use the the same form definition as both a fieldlist member, and a standalone form with CSRF enabled by passing csrf_enabled=True.
class FilterForm(wtf.Form):
field = wtf.Form ...
def __init__(self, csrf_enabled=False, *args, **kwargs):
super(FilterForm, self).__init__(csrf_enabled=csrf_enabled, *args, **kwargs)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With