В Django один из способов предотвратить отправку одной и той же формы несколько раз — использовать функцию «отключить при отправке» формы Django. Этого можно добиться, добавив в шаблон функцию JavaScript, которая отключает кнопку отправки формы после нажатия на нее.
В шаблоне:
<form id="form" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="Submit" onclick="disableForm()"> </form> <script> function disableForm() { document.getElementById("form").submit.disabled = true; } </script>
Другой способ — использовать подход на основе токенов, при котором для формы создается уникальный токен, который связывается с сеансом пользователя. Затем токен передается в форму как скрытое поле. При отправке формы сервер сверяет токен с сеансом пользователя и гарантирует его соответствие перед сохранением данных формы в базе данных. Если токен не совпадает, форма считается повторной отправкой и отклоняется.
В представлениях.py
from django.http import JsonResponse def get_token(request): token = uuid.uuid4().hex request.session['form_token'] = token return JsonResponse({'token': token}) def submit_form(request): if request.method == 'POST': token = request.POST.get('token') if token == request.session.get('form_token'): form = MyForm(request.POST) if form.is_valid(): form.save() request.session['form_token'] = None return JsonResponse({'status': 'success'}) return JsonResponse({'status': 'error'})
В шаблоне:
<form id="form" method="post"> {% csrf_token %} {{ form.as_p }} <input type="hidden" name="token" id="token"> <input type="submit" value="Submit"> </form> <script> $(document).ready(function() { $.get("/get_token/", function(data) { $("#token").val(data.token); }); }); </script>
Другой подход заключается в использовании декоратора @atomic
или диспетчера контекста transaction.atomic()
в представлениях. Это предотвратит отправку одной и той же формы несколько раз путем отката транзакции, если происходит одновременное обновление одних и тех же данных.
from django.db import transaction @transaction.atomic def submit_form(request): if request.method == 'POST': form = MyForm(request.POST) if form.is_valid(): form.save() return JsonResponse({'status': 'success'}) return JsonResponse({'status': 'error'})
Вы можете использовать любой из вышеперечисленных методов, чтобы предотвратить отправку нескольких форм в Django, в зависимости от конкретных требований вашего приложения.
Для существующих проектов я использую последний вариант, а для новых проектов выбираю один из первых двух вариантов.