Howto: динамически генерировать CSRF-токен в WTForms с колбой
у меня есть форма фруктов, которая имеет один объект FieldList для бананов:
bananas = FieldList(FormField(BananaForm))
в интерфейсе, первоначально, я добавляю одно из этих полей в список полей
form.append_entry()
теперь с помощью Javascript мне удалось создать функции, которые могут динамически добавлять (кнопка плюс) или удалять (кнопка минус) количество полей BananaForm, которые могут быть заполнены информацией.
FielstList автоматически создает идентификаторы для всех своих полей. Так сделать динамическое добавление с js, я дублирую HTML-код и устанавливаю поле id += 1, например:
первое поле:
<tr>
<td><input id="bananas-0-originCountry" type="text" /></td>
</tr>
Дублированное поле с += 1:
<tr>
<td><input id="bananas-1-originCountry" type="text" /></td>
</tr>
когда я назову их соответствующим образом и отправлю форму, WTForms автоматически распознает добавленные поля в бэкэнде (отлично работает).
пока все хорошо, но вот моя проблема: Чтобы форма была действительной, я должен добавить CSRF-поля в каждую WTForm. В шаблоне Jinja я делаю это с:
{{ form.hidden_tag() }}
однако, когда я просто копирую HTML с помощью моей функции js, мне не хватает CSRF-полей (потому что до отправки объект backend form не знает о добавленных полях формы). Итак, как я могу генерировать эти CSRF-поля динамически? (Запрос Ajax? Если да, то как?)
это должен быть стандартный случай использования с формами и колбой. Надеюсь, мое описание было понятным, если нет, пожалуйста, дайте мне знать. Любая помощь ценится!
UPDATE: вот мой код
в JS-функции
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(, ){
var i = parseInt() + 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 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 ответов
Я обнаружил, как это работает:
CSRF-Tag можно просто скопировать. Идентификатор должен быть изменен и увеличен соответственно, но хэш может оставаться неизменным.
Я не думал, что можно иметь много полей с тем же хэшем CSRF-Tag, но на самом деле это так!