2012-08-01 8 views
8

Ho una forma frutti che ha un oggetto FieldList per le banane:Howto: dinamicamente generare CSRF-token in WTForms con la boccetta

bananas = FieldList(FormField(BananaForm)) 

Nel frontend, inizialmente, aggiungo uno di quei campi a FieldList

form.append_entry() 

Ora con JavaScript sono riuscito a creare funzioni, che possono aggiungere dinamicamente (pulsante più) o rimuovere (tasto meno) il numero di campi BananaForm che possono essere riempiti con le informazioni.

FielstList crea automaticamente ID per tutti i suoi campi. Quindi, per fare dinamica aggiungendo con js, ho duplicare il codice HTML e impostare il campo id + = 1, come:

primo campo:

<tr> 
    <td><input id="bananas-0-originCountry" type="text" /></td> 
</tr> 

campo duplicato con + = 1:

<tr> 
    <td><input id="bananas-1-originCountry" type="text" /></td> 
</tr> 

Quando li chiamo di conseguenza e invio il modulo, WTForms riconoscerà automaticamente i campi aggiunti nel backend (funziona bene).

Fin qui tutto bene, ma ecco il mio problema: Per un modulo valido, devo aggiungere campi CSRF a ogni WTForm. Nel modello di Jinja faccio questo con:

{{ form.hidden_tag() }} 

Tuttavia, quando basta copiare il codice HTML con la mia funzione js, mi manca i CSRF-campi (perché fino presentata, l'oggetto modulo backend non lo sa circa i campi di campi aggiunti). Quindi, come posso generare questi campi CSRF in modo dinamico? (Una richiesta Ajax? Se sì, come?)

Questo dovrebbe essere un caso di uso standard con forme e fiaschi. Spero che la mia descrizione sia comprensibile, altrimenti ti prego di farmelo sapere. Qualsiasi aiuto apprezzato!

UPDATE: Ecco il mio codice

JS-funzioni Template

function addBanana(){ 
    // clone and insert banana node 
    var node = document.getElementById("fruitTable"); 
    var trs = node.getElementsByTagName("tr"); 
    var tr = trs[trs.length-2]; 
    var tr2 = tr.cloneNode(true); 
    tr.parentNode.insertBefore(tr2, tr); 

    // in order to increment label and input field ids 
    function plusone(str){ 
     return str.replace(
      new RegExp("-(\\d+)-", "gi"), 
      function($0, $1){ 
       var i = parseInt($1) + 1; 
       return "-" + i + "-"; 
      } 
     ); 
    } 

    // change inputs 
    var inputs = tr.getElementsByTagName("input"); 

    for (var i = 0; i < inputs.length; i++){ 
     inputs[i].setAttribute("id", plusone(inputs[i].getAttribute("id"))); 
    } 

    var minusbutton = 
     ['<td>', 
     '<button class="btn" type="button" onClick="removeBanana()"><i class="icon-black icon-minus"></i></button>', 
     '</td>' 
     ].join('\n'); 

    // only append at the first add 
    // second add automatically copies minus button 
    if (trs.length < 6){ 
     tr.innerHTML += minusbutton 
    } 
} 

function removeBanana(){ 
    var node = document.getElementById("fruitTable"); 
    var trs = node.getElementsByTagName("tr"); 
    var tr = trs[trs.length-2]; 
    var trParent = tr.parentNode; 
    trParent.removeChild(tr); 
} 

Jinja:

<form method="POST" action="newsubmit"> 
    {{ form.hidden_tag() }} 
    <table id="fruitTable" class="table"> 
    {{ render_field(form.description) }} 
    <tr><td><h3>Bananas</h3></td></tr> 
    {% set counter = 0 %} 
    {% for banana in form.bananas %} 
     <tr> 
     {{ banana.hidden_tag() }} 
     {% set counter = counter + 1%} 
     {% for field in banana if field.widget.input_type != 'hidden' %} 
      {{ render_field_oneline(field) }} 
     {% endfor %} 
     {% if counter > 1 %} 
      <td> 
      <button class="btn" type="button" onClick="removeBanana()"><i class="icon-black icon-minus"></i></button> 
      </td> 
     {% endif %} 
     </tr> 
    {% endfor %} 
     <tr><td></td><td><button class="btn" type="button" onClick="addBanana()"><i class="icon-black icon-plus"></i></button></td></tr> 
    </table> 
<input class="btn btn-primary" style="margin-left:300px;"type="submit" value="Submit" /> 
</form> 

Jinja Macro dei modelli:

{% macro render_field_oneline(field) %} 
<td>{{ field.label }}</td> 
<td>{{ field(**kwargs)|safe }} 
    {% if field.errors %} 
    <ul class=errors> 
    {% for error in field.errors %} 
    <li>{{ error }}</li> 
    {% endfor %} 
    </ul> 
    {% endif %} 
</td> 
{% endmacro %} 

{% macro render_field(field) %} 
<tr> 
    {{ render_field_oneline(field) }} 
</tr> 
{% endmacro %} 
+1

Dal suono delle cose il problema è con il tuo codice HTML o il tuo JavaScript - potresti postare quelli in modo che possiamo dare un'occhiata più profonda? (La mia prima ipotesi è che stai sostituendo l'intero codice HTML interno del modulo con il tuo codice rigenerato cancellando così il tag CSFR). –

+0

Ho aggiornato la mia domanda con il codice.Ho scoperto che nonostante 'hidden_tag()' dovrebbe rendere il tag CSRF all'interno del copiato e anche copiato (il che probabilmente non è la strada da percorrere, perché avrebbe lo stesso hash quindi), ma in realtà non lo è anche copiato! Non capisco davvero la magia che sta succedendo qui. Tuttavia, quello che posso sicuramente dire è che il tag CSRF non viene cancellato o sostituito! – kadrian

risposta

4

ho scoperto come funziona :

Il tag CSRF può essere semplicemente copiato. L'id deve essere modificato e incrementato di conseguenza, ma l'hash potrebbe rimanere lo stesso.

Non pensavo fosse possibile avere molti campi con lo stesso hash del tag CSRF, ma in realtà lo fa!