Bootstrap Проводка модальных форм дважды Django - PullRequest
0 голосов
/ 17 февраля 2020

Я следую инструкциям django - bootstrap -modal-forms , и я обнаружил, что моя форма публикуется или отправляется дважды, когда я отправляю форму. Во-первых, объект просто создавался дважды, я мог видеть это от администратора. Теперь кажется, что форма создает объект, но также входит в его состояние проверки, которое я, очевидно, не хочу, если форма была успешной, и это так.

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

Вот мой код:

home. html

<a href="#" class="create-shipment dropdown-itemcreatenew" onclick="closeNav()">Shipment</a>

<div class="modal fade" tabindex="-1" role="dialog" id="modal">
  <div class="modal-dialog" role="document">
    <div class="modal-content">

    </div>
  </div>
</div>

<script>
$(document).ready(function() {

    $(".create-shipment").modalForm({
        formURL: "{% url 'CreateShipmentView' %}"
    });

});
</script>

views.py

class CreateShipmentView(BSModalCreateView):
    template_name = 'create_shipment.html'
    form_class = CreateShipmentForm
    success_message = 'Success: Shipment Has Been Created!'
    success_url = reverse_lazy('HomeView')

create_shipment. html (шаблон для модальной формы)

{% load crispy_forms_tags %}
<form method="post" action="">
  {% csrf_token %}

 <div class="modal-header">
    <h5 class="modal-title">Create New Shipment</h5>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">
    {{form|crispy}}
  </div>

  <div class="modal-footer">
    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
    <button type="button" class="submit-btn btn btn-primary">Create</button>
  </div>

</form>

forms.py

class CreateShipmentForm(BSModalForm):
    class Meta:
        model = Shipment
        fields = ['Reference_Number', 'Ultimate_Consignee']

urls.py

url(r'^create_shipment/', views.CreateShipmentView.as_view(), name='CreateShipmentView'),

Прослушиватели событий при нажатии кнопки Отправить

 // Add click listener to the submitBtn
    var ajaxSubmit = function (modalID, modalContent, modalForm, formURL, errorClass, submitBtn) {
        $(submitBtn).on("click", function () {
            // Check if form.is_valid() via ajax request when submitBtn is clicked
            isFormValid(modalID, modalContent, modalForm, formURL, errorClass, submitBtn, submitForm);
        });
    };

    // Check if form.is_valid() & either show errors or submit it
    var isFormValid = function (modalID, modalContent, modalForm, formURL, errorClass, submitBtn, callback) {
        $.ajax({
            type: $(modalForm).attr("method"),
            url: $(modalForm).attr("action"),
            // Serialize form data
            data: $(modalForm).serialize(),
            success: function (response) {
                if ($(response).find(errorClass).length > 0) {
                    // Form is not valid, update it with errors
                    $(modalID).find(modalContent).html(response);
                    $(modalForm).attr("action", formURL);
                    // Reinstantiate click listener on submitBtn
                    ajaxSubmit(modalID, modalContent, modalForm, formURL, errorClass, submitBtn);
                } else {
                    // Form is valid, submit it
                    callback(modalForm);
                }
            }
        });
    };

Ответы [ 2 ]

1 голос
/ 18 февраля 2020

После прочтения исходного кода для пакета, я считаю, что получение двух запросов на бэкэнд - это нормально.

Ваш код

$(document).ready(function() {

    $(".create-shipment").modalForm({
        formURL: "{% url 'CreateShipmentView' %}"
    });

});

вызывает функцию modalForm, где он берет ваши параметры (formURL) и назначает функцию newForm событию щелчка.

Затем в функции newForm он вызывает функцию addListeners, чтобы связать событие щелчка к кнопке отправки в модале, и событие вызывается следующим образом:

isFormValid(modalID, modalContent, modalForm, formURL, errorClass, submitBtn, submitForm);

Обратите внимание, что последний параметр submitForm указывает на следующую функцию

var submitForm = function(modalForm) {
      $(modalForm).submit();
    };

Наконец, в Функция isFormValid, все данные, введенные вами в форму, будут опубликованы по URL-адресу, который вы определили в атрибуте action для проверки, и если ошибки не будет, форма будет отправлена ​​по тому же URL-адресу.

Если вы покопаетесь в коде python в этом пакете, все станет интересно. BSModalForm основан на двух классах в mixins.py и в здесь он говорит, что когда запрос был сделан чем-то отличным от ajax, сохраните экземпляр, созданный с использованием данных формы, или иным образом ( если запрос ajax call), не сохраняйте экземпляр и не возвращайте его. Вот почему она сначала проверяла форму, но никогда не должна сохранять ее (помните, что первый вызов действительно был сделан с помощью вызова ajax в jQuery).

Вы упомянули, что форма сохранялась дважды - попробуйте добавить строку в начале функции сохранения как

print(request.is_ajax())

, а затем проверьте вывод. возможно, что вызов не был отправлен как AJAX вызов. (если это так, обновите вашу версию jquery или используйте что-нибудь еще для совершения вызова, например ax ios)

Если вам не нравится, как идут дела, есть несколько вариантов (пакет под лицензией MIT ):

  1. Измените функцию save, чтобы проверить экземпляр, затем сохраните его как обычную функцию сохранения django, но для этого потребуется изменить часть кода JS.

  2. Создайте конечную точку API для получения данных и обмена данными, используя json вместо того, чтобы каждый раз возвращать код html (я думаю, это также причина, по которой автор написал JS в текущий путь, потому что тогда вы сталкиваетесь с проблемой рендеринга). Поскольку в настоящее время после отправки формы вам не нужно выполнять никаких других действий, возвращать экземпляр больше не имеет смысла. (нет необходимости в DRF, поскольку в django встроен класс JsonResponse, и если вам нужна только одна конечная точка)

  3. Используйте BootStrap напрямую, поскольку история здесь довольно просто: модальное на странице, кнопка для запуска модального, форма в модальном и вы можете отправить его. Возможно, вам придется написать некоторые свои JS для отображения ошибок, но это все равно должно быть проще, чем изменить существующий пакет.


Пример

# forms.py
from django import forms


# use django ModelForm for creating the form based on model
class CreateShipmentForm(forms.ModelForm):
    class Meta:
        model = Shipment
        fields = ['Reference_Number', 'Ultimate_Consignee']

представление для визуализации формы (GET) и получения отправленных форм (POST)

# views.py
from yourapp.forms import CreateShipmentForm
from django.shortcuts import render


def create_shipment_view(request):
    # http POST request means that the form was submitted
    if request.method == 'POST':
        # create the form and map the data to CreateShipmentForm
        shipment_form = CreateShipmentForm(request.POST)
        # based on your design of the form/modal, validate the data passed into the form
        if shipment_form.is_valid():
            # create a new shipment object
            new_shipment = shipment_form.save()
            # form processing is finished now do something to alert user, for example redirect the user to the success page
            return redirect('success')
        # if the form is not valid, then shipment_form.errors contain all the errors
    else:
        # for all other accessing methods including GET
        # create an empty form
        shipment_form = CreateShipmentForm()

    # if the request was POST, the form contains errors, if request was GET, it's an empty form
    return render(request, 'path/to/template.html', {
        'form': shipment_form
    })

Наконец, в своем шаблоне вы можете просто отобразить форму, как обычно. Если вы не знаете или нуждаетесь в каких-либо других функциях для своей формы, продолжайте использовать хрустящие формы.

отметьте if shipment_form.errors в своем шаблоне и отобразите его в своем шаблоне, если хотите показать ошибки пользователям.

0 голосов
/ 25 марта 2020

У меня была похожая проблема. Мое решение было:

class AppCreateView(BSModalCreateView):
    template_name = 'apps/app_create.html'
    form_class = UserAppForm
    success_message = 'Success: App was created.'
    success_url = reverse_lazy('dashboard')

    def form_valid(self, form):
        if not self.request.is_ajax():
            app = form.save(commit=False)
            profile = Profile.objects.get(user=self.request.user)
            app.profile = profile
            app.save()
        return HttpResponseRedirect(self.success_url)
...