2012-08-01 6 views
8

Ich habe eine Früchte bilden, die ein Fieldlist-Objekt für die Bananen hat:Howto: Dynamisch erzeugen CSRF-Token in WTForms mit Flask

bananas = FieldList(FormField(BananaForm)) 

Im Frontend zunächst, füge ich eines dieser Felder auf die Fieldlist

form.append_entry() 

Jetzt mit Javascript habe ich es geschafft Funktionen zu erstellen, die dynamisch hinzufügen (Plus-Taste) oder (minus-Taste), um die Anzahl der BananaForm Felder entfernen, die mit Informationen gefüllt werden kann.

FielstList erstellt automatisch IDs für alle Felder. So dynamisch zu tun mit js hinzufügen, ich duplizieren den HTML-Code und setzen Sie das Feld id + = 1, wie:

erstes Feld:

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

dupliziert Feld mit + = 1:

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

Wenn ich sie entsprechend benenne und das Formular abschicke, erkennt WTForms automatisch die hinzugefügten Felder im Backend (funktioniert gut).

So weit so gut, aber hier ist mein Problem: Damit ein Formular gültig ist, muss ich jedem WTForm ein CSRF-Feld hinzufügen. In der Jinja Vorlage kann ich dies mit:

{{ form.hidden_tag() }} 

Allerdings, wenn ich kopieren Sie einfach den HTML-Code mit meiner js Funktion, fehle ich die CSRF-Felder (weil bis vorgelegt, wird das Back-End-Form-Objekt nicht wissen über die hinzugefügten FormFields). Wie kann ich diese CSRF-Felder dynamisch erzeugen? (Eine Ajax Anfrage? Wenn ja, wie?)

Dies sollte ein Standard-Anwendungsfall mit Formen und Kolben sein. Ich hoffe meine Beschreibung war verständlich, wenn nicht, lass es mich wissen. Jede Hilfe wird geschätzt!

UPDATE: Hier ist mein Code

JS-Funktionen

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 Vorlage:

<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 Vorlage Makros:

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

Durch den Klang der Dinge ist das Problem mit Ihrem HTML oder Ihrem JavaScript - könnten Sie diese posten, damit wir einen tieferen Blick darauf werfen können? (Meine erste Vermutung ist, dass Sie den gesamten inneren HTML-Code des Formulars durch Ihren neu generierten Code ersetzen und somit das CSFR-Tag löschen). –

+0

Meine Frage mit dem Code aktualisiert.Ich entdeckte, dass trotz des 'hidden_tag()' das CSRF-Tag innerhalb der kopierten gerendert werden sollte und auch kopiert werden sollte (was wahrscheinlich nicht der richtige Weg ist, da es dann den gleichen Hash hätte), aber eigentlich ist es nicht ' t sogar kopiert! Ich verstehe die Magie hier wirklich nicht. Was ich jedoch definitiv sagen kann, ist, dass das CSRF-Tag nicht ausgelöscht oder ersetzt wird! – kadrian

Antwort

4

entdeckte ich, wie es funktioniert :

Der CSRF-Tag kann einfach kopiert werden. Die ID muss entsprechend geändert und inkrementiert werden, aber der Hash kann gleich bleiben.

Ich dachte nicht, dass es möglich ist, viele Felder mit dem gleichen CSRF-Tag-Hash zu haben, aber das tut es tatsächlich!

Verwandte Themen