Django получает несколько сообщений от браузера, Кэширует ли браузер POST-ы?

Во время разработки это происходит так: если я работаю над куском кода для получения POST-запроса, Django выдаст страницу с ошибкой, потому что код глючный. Затем я исправляю синтаксическую ошибку, обновляю, другая ошибка, исправляю эту, повторяю процесс, скажем, 8 раз

Но на 8-й раз код срабатывает, и тогда Django получает и сохраняет 8 записей Post, а не только последнюю!

Подобное поведение происходит в продакшене очень иногда. Я не уверен, что это браузер кэширует POST-ы, затем отправляет их все одновременно или Django?

У меня больше проблем с этим вопросом при работе с автономной функциональностью. Если POST не удался, я кэширую его, а затем повторно отправляю, когда он снова в сети. Но иногда неудачный POST возвращается из мертвых из другого измерения и отправляется в Django, как и Sync offline POST, так что теперь он дублируется.

Я написал код javascript, чтобы отключить кнопку отправки после нажатия. Я также проверяю наличие дубликатов записей (в течение 5 секунд) перед сохранением, но это работает, только если кто-то вручную отправляет два раза подряд, а не если он автоматически отправляет кучу POST одновременно. Оба эти способа являются "хаками", которые не устраняют основную причину.

Есть подсказки о том, как отладить или как попытаться решить/отладить проблему?

Это происходит на нескольких моих представлениях, но вот одно из них я сейчас пытаюсь исправить, ScrapEntryView - это представление, и оно является подклассом BaseFactCreateView:

from django.views import generic

from .apps import ScrapConfig as AppConfig
from .forms import ScrapEntryForm
from core.gui.apps import SESSION_FEEDBACK
from dist.machine.fact.views import BaseFactCreateView
from utils.time import ttb
from utils.validation import form_validation
from utils.web import HTTP_OK_NO_CONTENT


class BaseFactCreateView(generic.CreateView):
    def form_invalid(self, form):
        if form.is_sync_post:
            # If it is a sync post, can't ask the user to correct it, accept it and log to SysEvent table
            from core.base.models import SysEvent

            SysEvent.objects.create(
                name="Sync POST failed",
                note=str(
                    f'Form errors: {form_validation.plain_text_errors(form)}, Request.POST{self.request.POST}'
                ),
            )
            return HTTP_OK_NO_CONTENT
        return super().form_invalid(form)

    def get_feedback(self):
        raise NotImplementedError

    def get_success_url(self):
        return self.request.get_full_path_info()

    def form_valid(self, form):
        """If the form is valid, save the associated model."""
        response = super().form_valid(form)  # will create self.object
        self.request.session[SESSION_FEEDBACK] = self.get_feedback()
        return response


class ScrapEntryView(BaseFactCreateView):
    form_class = ScrapEntryForm
    template_name = f'{AppConfig.name}/entry.html'

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        kwargs['site_area_id'] = self.kwargs['site_area_id']
        kwargs['request'] = self.request
        return kwargs

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['site_area_id'] = self.kwargs['site_area_id']
        context['page_title'] = "Scrap Entry"
        context[SESSION_FEEDBACK] = self.request.session.pop(SESSION_FEEDBACK, None)
        return context

    def get_feedback(self):
        obj = self.object
        return {
            'type': 'success',
            'heading': "Scrap Entry Saved",
            'body': f"<b>{obj.weight_kg}</b>kg for machine <b>{obj.machine_setup.machine.name}</b><br>due to <b>{obj.scrap_reason.name}</b>",
            'created_dtz': ttb.to_dstr(obj.created_utc, 'DATETIME_FORMAT'),
        }

Вернуться на верх