Невозможно заставить кнопки отправки работать с помощью библиотеки django-formset (при нажатии ничего не происходит)

Я использую библиотеку django-formset для разработки программы выставления счетов. Когда я заполняю новую форму и нажимаю кнопку отправки, ничего не происходит. Я изучил документацию и следовал примерам, но безуспешно. Django(5.0.2) и django-formset(1.3.8) обновлены.

У меня есть несколько идей, что может вызвать проблему, и соответствующие вопросы, но я не знаю, как их проверить, поскольку я впервые работаю с css / bootstrap / javascript / typescript (у меня есть только небольшой опыт работы с Python).

  1. Имеет ли значение, где загружать скрипты - в базовом или дочернем шаблоне?
  2. Имеет ли значение порядок следования скриптов, и имеет ли значение, где в голове мы загружаем скрипты относительно других элементов?
  3. Нужно ли перемещать статические файлы из библиотеки formset в папку static в проекте? (Я пробовал копировать-вставлять, но безрезультатно)

Свежий взгляд на это был бы очень признателен, потому что я застрял! У меня такое чувство, что это что-то очень простое, что я упускаю из виду.

models.py:

class Customer(models.Model):
    first_name = models.CharField('First Name', max_length=55, blank=True)
    last_name = models.CharField('Last Name', max_length=55, blank=True)
    phone = models.CharField('Phone Number', max_length=10, blank=True)
    alt_phone = models.CharField('Alt Phone Number', max_length=10, blank=True)
    company = models.CharField('Company', max_length=55, blank=True)
    email = models.EmailField('Email', null=True, blank=True)
    address = models.CharField('Address', max_length=55, blank=True)
    city = models.CharField('City', max_length=55, blank=True)
    state = models.CharField('State', max_length=55, blank=True)
    zip = models.CharField('Zip Code', max_length=9, blank=True)
    customer_notes = models.TextField('Customer Notes', blank=True)
    date_created = models.DateTimeField(auto_created=True, null=True, blank=True)

    def __str__(self):
        return f'{self.first_name} {self.last_name}'

forms.py:

class CustomerForm(ModelForm):
    default_renderer = FormRenderer(
        form_css_classes='row border p-1 m-1',
        field_css_classes={
            '*': 'mb-1 col-4',
            'city': 'mb-1 col-3',
            'state': 'mb-1 col-1',
            'customer_notes': 'mb-1 col-12',
            'new': 'mb-5'
        },
    )

    hide_if = 'new_customer.extant'


    class Meta:
        model = Customer
        fields = [
            'first_name',
            'last_name',
            'company',
            'phone',
            'alt_phone',
            'email',
            'address',
            'city',
            'state',
            'zip',
            'customer_notes',
        ]
        widgets = {
            'first_name': forms.TextInput(attrs={
                'class': 'form-control',
                'id': 'first_name',
                'placeholder': 'Customer First Name',
            }),
            'last_name': forms.TextInput(attrs={
                'class': 'form-control',
                'id': 'last_name',
                'placeholder': 'Customer Last Name',
            }),
            'phone': forms.NumberInput(attrs={
                'class': 'form-control',
                'id': 'phone',
            }),
            'alt_phone': forms.NumberInput(attrs={
                'class': 'form-control',
                'id': 'alt_phone',
            }),
            'company': forms.TextInput(attrs={
                'class': 'form-control',
                'id': 'company',
            }),
            'email': forms.EmailInput(attrs={
                'class': 'form-control',
                'id': 'email',
            }),
            'address': forms.TextInput(attrs={
                'class': 'form-control',
                'id': 'address',
            }),
            'city': forms.TextInput(attrs={
                'class': 'form-control',
                'id': 'city',
            }),
            'state': forms.TextInput(attrs={
                'class': 'form-control',
                'id': 'state',
                'value': 'CA',
            }),
            'zip': forms.TextInput(attrs={
                'class': 'form-control',
                'id': 'zip',
            }),
            'customer_notes': forms.Textarea(attrs={
                'class': 'form-control',
                'id': 'customer_notes',
                'placeholder': 'Enter customer notes',
                'rows': '1'
            }),
            'date_created': forms.DateTimeInput(attrs={
                'class': 'form-control',
                'id': 'date_created',
                'value': datetime.now()
            })
        }

views.py:

class EditView(UpdateView, FormViewMixin):
    def get_object(self, queryset=None):
        if self.extra_context['add'] is False:
            return super().get_object(queryset)

    def form_valid(self, form):
        if extra_data := self.get_extra_data():
            if extra_data.get('delete') is True:
                self.object.delete()
                success_url = self.get_success_url()
                response_data = {'success_url': force_str(success_url)} if success_url else {}
                return JsonResponse(response_data)
        return super().form_valid(form)

class CustomerEditView(EditView):
    model = Customer
    template_name = 'invoice/customer-add.html'
    form_class = CustomerForm
    extra_context = None

    def get_success_url(self):
        if pk := self.object.id:
            return reverse('customer-edit', kwargs={'pk': pk})
        else:
            return reverse('customer-list')

urls.py

urlpatterns = [
    path('customers', CustomerListView.as_view(), name='customer-list'),  # list view not handled here
    path('customer/add/', CustomerEditView.as_view(extra_context={'add': True}), name='customer-add', ),
    path('customer/<int:pk>/', CustomerEditView.as_view(extra_context={'add': False}), name='customer-edit', ),
]

base.html

{% load static %}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <title>Invoice Management</title>

    <!-- bootstrap5 css -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
    <link href="{% static '/css/sb-admin-2.css' %}" rel="stylesheet"></link>
    <link href="{% static '/css/style.css' %}" rel="stylesheet">

    <!-- FONT AWESOME -->
    <script src="https://kit.fontawesome.com/016d1bf7c0.js" crossorigin="anonymous"></script>
    <!-- bootstrap5 javascript -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"
            integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz"
            crossorigin="anonymous"></script>

    <!-- django-formset -->
    <script type="module" src="{% static 'formset/js/django-formset.js' %}"></script>


    {% block head_script %}
    {% endblock %}
</head>

<div class="card w-100 shadow my-2">
    {% block content %}{% endblock %}
</div>

customer-add.html

{% extends "invoice/base/base.html" %}
{% load i18n %}
{% load static %}


<!-- Content Row -->
{% block content %}
    <!-- CUSTOMER FORM -->
    <div id="customer-info" class="card-body collapse show">
        {% load render_form from formsetify %}
        <django-formset endpoint="{{ request.path }}" csrf-token="{{ csrf_token }}">
            {% render_form form %}

            {% if add %}
                <button type="button" df-click="submit({add: true}) -> proceed">{% trans "Add" %}</button>
            {% else %}
                <button type="button" df-click="submit({update: true}) -> proceed">{% trans "Update" %}</button>
                <button type="button" df-click="submit({delete: true}) -> proceed">{% trans "Delete" %}</button>
            {% endif %}
        </django-formset>
    </div>
{% endblock %}
Вернуться на верх