2013-03-26 8 views
11

Ho problemi a passare attraverso la convalida quando si utilizza un FieldList con WTForms. Continuo a ricevere questo errore. {'csrf_token': [u'CSRF token missing']}. Il problema è che se non ho dati da convalidare nel campo FieldList, i passaggi di convalida e non ci sono problemi. Ma quando provo a convalidare il modulo con qualsiasi dato ottengo quell'errore.wtforms, CSRF, flask, FieldList

Qui sono le mie forme:

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

La forma sembra visualizzare correttamente e funziona bene fino a quando aggiungo i dati a uno redirect_filters_any o redirect_filters_all

C'è un modo per disattivare CSRF per la FieldList o passaggio un valore CSRF per FieldList? Voglio mantenere abilitata la protezione CSRF ma non riesco a superare questo problema di convalida.

Ecco il modello Jinja2

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

Hai aggiunto '{{form.hidden_tag()}}' al codice HTML del modulo? Che aspetto ha il modello Jinja2? – Blender

+0

Sto usando il tag. Ho aggiunto l'intero modello jinja2 per chiarezza. – MBeale

risposta

16

Il problema sembra essere che Flask-WTForms Form è in realtà una sottoclasse di wtforms.ext.SecureForm - e l'unico modo per disabilitare la protezione CSRF in un form è quello di passare la parola chiave argomento csrf_enabled=False al modulo durante la costruzione. Dal momento che FormField gestisce in realtà un'istanza forma e si può:

  • creare una sottoclasse di FormField che vi permetterà di passare in argomenti chiave forma
    o
  • sottoclasse wtforms.Form piuttosto che flask.ext.wtforms.Form per il vostro FilterForm (come Finché non visualizzi mai uno FilterForm da solo, non dovrai preoccuparti di CSRF).
+0

Ho cambiato la sottoclasse in wtforms.Form e questo ha risolto il problema. Grazie. – MBeale

+0

sottoclasse (che eredita da) wtforms.Form ha funzionato per me. Quindi per chi lavora, classe MyForm (wtforms.Form) invece di MyForm (Form) se si stesse usando l'estensione flask-wtf come ero io. – xamox

+1

Grazie per questo! Ho usato 'da wtforms import Form come NoCsrfForm' per evitare conflitti con' Form' di Flask –

7

Dopo aver incontrato lo stesso problema, ho voluto per la fornitura di una terza opzione per la soluzione di cui sopra

È anche possibile ignorare la costruzione nella classe form per sostituire il valore predefinito di csrf_enabled. Ciò presenta il vantaggio che è possibile utilizzare la stessa definizione di modulo sia di un membro della lista di campi sia di una forma autonoma con CSRF abilitato passando 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) 
0

Sembra che lo csrf_enabled sia obsoleto. Ecco una soluzione che funziona con Flask-WTForms 0.14.2, parzialmente basata su leebriggs answer. Invece di passare un parametro durante la creazione del modulo, ho appena creato una sottoclasse xNoCsrf, perché non volevo che qualcuno dimenticasse accidentalmente di includere il token CSRF quando lo desidera. In questo modo, è necessario digitare NoCsrf per ottenere la versione non CSRF.

class FilterForm(FlaskForm): 
    <some stuff here> 

class FilterFormNoCsrf(FilterForm): 
    def __init__(self, *args, **kwargs): 
     super(FilterFormNoCsrf, self).__init__(meta={'csrf':False}, *args, **kwargs) 

Here è la documentazione per csrf campo della classe meta.

Problemi correlati