Решение для этого содержится в этот вопрос и ответ Терри . Плюс некоторая другая информация об обработке CSRF защиты в Django.
Краткий ответ - переопределить отправку обычной формы с помощью event.preventDefault()
в вашей собственной функции onsubmit
для каждой формы. , Затем выполните POST асинхронно с JQuery. Это избавляет сервер от необходимости возвращать HttpResponse со статусом 204 или что-то действительно, кроме пустого JsonResponse.
На моей веб-странице есть несколько форм, поэтому мне не назначено ни одной функции для каждой кнопки, как в приведенном выше связанном ответе, но некоторые из них меняют поведение отдельных кнопок. Также для Django добавлено рассмотрение включения токена CSRF в запрос POST.
Так, например, некоторые html с двумя кнопками;
<form id="form-a" onsubmit="submit_form_a(event)">{% csrf_token %}
<input type="hidden" name="button-a" value="some_value_for_a">
<button type="submit" class="w3-button">Button A</button>
</form>
<form id="form-z" onsubmit="submit_form_z(event)">{% csrf_token %}
<input type="hidden" name="button-z" value="some_value_for_z">
<button type="submit" class="w3-button">Button Z</button>
</form>
Затем Javascript, когда первая форма отправляет обратный вызов, например, отключает кнопку;
function submit_form_a(e){
e.preventDefault();
var url = "/main/a"
var formData = $(e.target).serialize();
var btn = $(e.target).find("button");
btn.prop("disabled", true);
myPost(url, formData);
}
И вторая отправляет обратный вызов, который выполняет некоторую анимацию, используя превосходный W3. CSS;
function submit_form_z(e){
e.preventDefault();
var url = "/main/z"
var formData = $(e.target).serialize();
var btn = $(e.target).find("button");
btn.toggleClass("w3-animate-fading").toggleClass("w3-text-red")
myPost(url, formData);
}
Оба этих сценария вызывают общий сценарий mypost
, который устанавливает заголовок XMLHttpResponse с маркером CSRF, затем отправляет;
// Make sure any AJAX POST requests are not going off-site. Prevents
// leaking the CSRF token.
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); }
function myPost(url, data) {
var csrftoken = $("[name=csrfmiddlewaretoken]").val();
// Set the header on the AJAX POST request with the CSRF token
$.ajaxSetup({beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}});
$.post(url, data);
}
Вернемся к стороне Django views.py
, посмотрите на данные <input>
из формы и сделайте то, что вам нужно сделать. Я только что обнаружил на iOS, что сами кнопки не включаются в данные формы POST, как это происходит с другими платформами, что делает необходимым ввод элементов скрытого текста;
if request.is_ajax() and request.method == 'POST':
if 'button-a' in request.POST:
# do something for A
elif 'button-z' in request.POST:
# do something for Z
return JsonResponse({})
И вуаля! Кнопки могут быть нажаты, фоновые вещи происходят, и страница не движется. Вы можете вернуть что-то, кроме пустого ответа JSON, и обработать его обратно в виде обратных вызовов, таких как повторное включение кнопки, но мне это не нужно. См. Ранее связанный ответ для деталей там.