Таблица на django, позволяющая редактировать, добавлять и удалять строки

Я только начинаю изучать django, подскажите, пожалуйста, какой способ лучше всего подойдет и будет проще всего в реализации следующей задачи:

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

Не сердитесь, если данная тема уже была затронута в обсуждении. Ранее я нашел решение своей проблемы по следующей ссылке (https://stackoverflow.com/a/70352509/17641696), но так и не смог понять, зачем автор использует скрипт: разве он не дублирует то, что описано в views.py?

Также прошу Вас, если вы заметите какую-то глупость в моем коде, пожалуйста, укажите мне на это.

На текущий момент у меня имеется следующий код:

Forms.py

class AkpGroupForm(ModelForm):
    required_css_class = 'required'

    class Meta:
        model = AkpGroup
        fields = ['Id_Incidents', 'Type_Participation', 'Id_People', 'Competencies']
        exclude = ('Id_Incidents',)

        widgets = {
            "Id_Incidents": Select(attrs={
                'class': 'form-select'
            }),

            "Type_Participation": Select(attrs={
                'class': 'form-select',
                'style': 'height: 40px'
            }),

            "Id_People": Select(attrs={
                'class': 'form-select',
                'style': 'height: 40px'
            }),

            "Competencies": Textarea(attrs={
                'class': 'form-select',
                'style': 'height: 40px'
            })
        }


class AkpCheckResultForm(ModelForm):
    required_css_class = 'required'

    class Meta:
        model = AkpCheckResult
        fields = ['Id_Incidents', 'Inspector', 'Company', 'Post', 'Basis_Attraction', 'Check_Area']
        exclude = ('Id_Incidents',)

        widgets = {
            "Id_Incidents": Select(attrs={
                'class': 'form-select'
            }),

            "Inspector": Select(attrs={
                'class': 'form-select',
                'style': 'height: 60px'
            }),

            "Company": Textarea(attrs={
                'class': 'form-select',
                'style': 'height: 60px'
            }),

            "Post": Textarea(attrs={
                'class': 'form-select',
                'style': 'height: 60px'
            }),

            "Basis_Attraction": Textarea(attrs={
                'class': 'form-select',
                'style': 'height: 60px'
            }),

            "Check_Area": Textarea(attrs={
                'class': 'form-select',
                'style': 'height: 60px'
            })
        }


class AkpMeetingForm(ModelForm):
    required_css_class = 'required'

    class Meta:
        model = AkpMeeting
        fields = ['Id_Incidents', 'Date_Time', 'Location', 'Responsible']
        exclude = ('Id_Incidents',)

        widgets = {
            "Id_Incidents": Select(attrs={
                'class': 'form-select'
            }),

            "Date_Time": DateTimeInput(attrs={
                'class': 'form-control',
                'type': 'Date'
            }),

            "Location": TextInput(attrs={
                'class': 'form-select',
                'style': 'height: 40px'
            }),

            "Responsible": TextInput(attrs={
                'class': 'form-select'
            })
        }


class GroupCheckResultMeetingCreationMultiForm(MultiModelForm):
    form_classes = {
        'Group': AkpGroupForm,
        'CheckResult': AkpCheckResultForm,
        'Meeting': AkpMeetingForm
    }

Models.py

class AkpGroup(models.Model):
    Id_Group = models.AutoField(primary_key=True, verbose_name='Идентификатор участника группы АКП')
    Id_Incidents = models.ForeignKey('AkpIncidents', models.DO_NOTHING, verbose_name='Идентификатор инцидента')
    # stage 3 fields
    Id_People = models.ManyToManyField('AkpPeople', verbose_name='Ф.И.О. участника')
    Competencies = models.CharField(max_length=256, verbose_name='Компетенции')

    LOAN_TYPE_PARTICIPATION = (
        ('d', 'Руководитель группы'),
        ('p', 'Член группы')
    )
    Type_Participation = models.CharField(max_length=1, choices=LOAN_TYPE_PARTICIPATION, default='p',
                                          verbose_name='Тип участия')
    # Вспомогательные
    Change_Time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name='Время изменения')
    Change_User = models.CharField(max_length=256, verbose_name='Пользователь, внесший изменения')
    Del_Date = models.DateTimeField(auto_now=False, blank=True, null=True, verbose_name='Дата удаления')
    Del_User = models.CharField(max_length=256, verbose_name='Пользователь, удаливший данные')
    Is_Delete = models.BooleanField(default=False, verbose_name='Удален')

    Is_Posted = models.BooleanField(default=False, verbose_name='Опубликовано')

    objects = models.Manager()

    def display_id_people(self):
        """
        Creates a string for the Genre. This is required to display genre in Admin.
        """
        return ', '.join([Id_People.Name for Id_People in self.Id_People.all()[:10]])
    display_id_people.short_description = 'AkpGroup'

    def __str__(self):
        return self.Competencies

    class Meta:
        db_table = 'Akp_Group'
        verbose_name = 'Группа АКП'
        verbose_name_plural = 'Группы АКП'

    # hidden_fields = ['stage']
    # required_fields = ['Id_People', 'Competencies']


# Основная таблица: 4) Проверка результатов
class AkpCheckResult(models.Model):
    Id_CheckResult = models.AutoField(primary_key=True, verbose_name='Идентификатор проверки результатов')
    Id_Incidents = models.ForeignKey('AkpIncidents', models.DO_NOTHING, verbose_name='Идентификатор инцидента')
    # stage 3 fields
    LOAN_INSPECTOR = (
        ('n', 'Независимый эксперт'),
        ('z', 'Заинтересованная сторона'),
    )
    Inspector = models.CharField(max_length=1, choices=LOAN_INSPECTOR, verbose_name='Тип участия')
    Company = models.CharField(max_length=256, verbose_name='Организация')
    Post = models.CharField(max_length=256, verbose_name='Должность:')
    Basis_Attraction = models.CharField(max_length=256, verbose_name='Основание для привлечения:')
    Check_Area = models.CharField(max_length=256, verbose_name='Область проверки:')

    # Вспомогательные
    Change_Time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name='Время изменения')
    Change_User = models.CharField(max_length=256, verbose_name='Пользователь, внесший изменения')
    Del_Date = models.DateTimeField(auto_now=False, blank=True, null=True, verbose_name='Дата удаления')
    Del_User = models.CharField(max_length=256, verbose_name='Пользователь, удаливший данные')
    Is_Delete = models.BooleanField(default=False, verbose_name='Удален')

    Is_Posted = models.BooleanField(default=False, verbose_name='Опубликовано')

    objects = models.Manager()

    def __str__(self):
        return self.Check_Area

    class Meta:
        db_table = 'Akp_Check_Result'
        verbose_name = 'Проверка результатов'
        verbose_name_plural = 'Проверка результатов'

    # hidden_fields = ['stage']
    # required_fields = ['Id_Inspector', 'Company', 'Post', 'Basis_Attraction', 'Check_Area']


# Основная таблица: 5) Совещание
class AkpMeeting(models.Model):
    Id_Meeting = models.AutoField(primary_key=True, verbose_name='Идентификатор совещания')
    Id_Incidents = models.ForeignKey('AkpIncidents', models.DO_NOTHING, verbose_name='Идентификатор инцидента')
    # stage 3 fields
    Date_Time = models.DateTimeField(auto_now=False, blank=True, null=True, verbose_name='Дата/время совещания')
    Location = models.CharField(max_length=256, verbose_name='Место проведения совещания:')
    Responsible = models.CharField(max_length=256, verbose_name='Ответственный за организацию совещания:')

    # Вспомогательные
    Change_Time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name='Время изменения')
    Change_User = models.CharField(max_length=256, verbose_name='Пользователь, внесший изменения')
    Del_Date = models.DateTimeField(auto_now=False, blank=True, null=True, verbose_name='Дата удаления')
    Del_User = models.CharField(max_length=256, verbose_name='Пользователь, удаливший данные')
    Is_Delete = models.BooleanField(default=False, verbose_name='Удален')

    Is_Posted = models.BooleanField(default=False, verbose_name='Опубликовано')

    objects = models.Manager()

    def __str__(self):
        return self.Location

    class Meta:
        db_table = 'Akp_Meeting'
        verbose_name = 'Совещание'
        verbose_name_plural = 'Совещания'

    # hidden_fields = ['stage']
    # required_fields = ['Date_Time', 'Location', 'Responsible']

Urls.py

app_name = "main"

urlpatterns = [
    path('', views.start, name="start"),
    path('incident', views.incident, name="incident"),
    path('victim', views.victim, name="victim"),

    path('group', views.Groups.as_view(), name='group'),

    path('AdditionalDetail', views.additional_detail, name='AdditionalDetail'),
    path('events', views.events, name='events'),
    path('monitoring', views.monitoring, name='monitoring'),

    path(
        'url_to_django/delete-person/<int:Id_Group>',
        views.delete_person,
        name='delete_person'),
    path(
        'url_to_django/add-person/',
        views.add_person,
        name='add_person'),
    path(
        'url_to_django/load_table/',
        views.load_table,
        name='load_table')

html

{% block content %}
            <!--В цикле перечисленные все скрытые поля-->
            {% for hidden in form.hidden_fields %}
                {{ hidden }}
            {% endfor %}

                <!--В цикле перечисленные все видимые поля указанные в AkpGroupForm в forms.py-->

                <table class="table align-middle" id="table_person_id">
                  <thead>
                    <tr>
                        <th scope="col"></th>
                        <th scope="col">#</th>
                        {% if form.Group.visible_fields %}
                        {% for field in form.Group.visible_fields %}
                        <th scope="col">{{ field.label }}</th>
                        {% endfor %}
                        {% endif %}
                        <th>Действие</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                        <th scope="row"><div><input class="form-check-input" type="checkbox" id="checkboxNoLabel1" value="" aria-label="..."></div></th>
                        <th scope="row">1</th>
                        {% if form.Group.visible_fields %}
                        {% for field in form.Group.visible_fields %}
                        <td>{{ field }}</td>
                        {% endfor %}
                        {% endif %}
                        <td>
                            <button value="{{AkpGroup.Id_Group}}" onclick=delete_person>Удалить</button>
                        </td>
                    </tr>
                  </tbody>
                    <tfoot>
                        <form method="POST" onsubmit=add_person>
                            <tr>
                                <th scope="row"></th>
                                <th scope="row"></th>
                                {% if form.Group.visible_fields %}
                                {% for field in form.Group.visible_fields %}
                                <td>{{ field }}</td>
                                {% endfor %}
                                {% endif %}
                                <td>
                                    <button type="submit">Добавить</button>
                                </td>
                            </tr>
                        </form>
                    </tfoot>
                </table>
  <div class="container overflow-hidden">
    <div class="row gy-5">
      <div class="col-md-6">
        <div class="p-3 bg-light"><span class="pull-right"></span>
          <a href="{% url 'main:start' %}" class="p-3 bg-light"><button type="button" class="btn btn-outline-secondary">Отмена</button></a>
        </div>
      </div>
      <div class="col-md-6">
        <div class="p-3 bg-light"><span class="pull-right"></span>
          <div class="btn-group" role="group" aria-label="Basic mixed styles example">
            <button type="submit" class="btn btn-outline-success" name="back">Предыдущий шаг</button>
            <button type="submit" class="btn btn-outline-warning" name="next">Следующий шаг</button>
          </div>
        </div>
      </div>
    </div>
  </div>
<!--</form>-->
{% endblock %}

Views.py

# Страница 3 из 6
class Groups(CreateView):
    error = ''
    form_class = GroupCheckResultMeetingCreationMultiForm
    success_url = reverse_lazy('group')
    template_name = 'main/group.html'

    def form_valid(self, form):
        if form.is_valid() and 'next':

            group_created = form['Group'].save(commit=False)
            group_created.Id_Incidents = get_object_or_404(AkpIncidents, Id_Incidents=id_incidents)
            group_created.save()
            
            # check_result_created = form['CheckResult'].save(commit=False)
            # check_result_created.Id_Incidents = get_object_or_404(AkpIncidents, Id_Incidents=id_incidents)
            # check_result_created.save()
            #
            # meeting_created = form['Meeting'].save(commit=False)
            # meeting_created.Id_Incidents = get_object_or_404(AkpIncidents, Id_Incidents=id_incidents)
            # meeting_created.save()

        else:
            error = 'Форма заполнена некорректно'

        # elif 'back' in request.POST:
        #     return redirect('main:incident')

        data = {
            'form': 'form',
            'error': 'error'
        }
        return redirect(self.get_success_url(), data)


def load_table(request, Id_Group):
    if request.method == "GET":
        if request.user:
            person = AkpGroup.objects.get(id=Id_Group)  # запрос в базу данных
            return render(request, 'main/group.html', {"person": person})
        else:
            return HttpResponse(status=403)
    else:
        return HttpResponse(status=405)


def delete_person(request, Id_Group):
    if request.method == "DELETE":
        if request.user:
            person_to_delete = AkpGroup.objects.get(id=Id_Group)
            person_to_delete.delete()
            return HttpResponse(status=200)
        else:
            return HttpResponse(status=403)
    else:
        return HttpResponse(status=405)


def add_person(request, codorcam):
    if request.method == "POST":
        if request.user:
            form = AkpGroupForm(request.POST)  # форма, созданная в forms.py чтобы добавить участника
            if form.is_valid():
                group_created = form['Group'].save(commit=False)
                group_created.Id_Incidents = get_object_or_404(AkpIncidents, Id_Incidents=id_incidents)
                group_created.save()
                
                return HttpResponse(status=201)
            else:
                return HttpResponse(status=400)
        else:
            return HttpResponse(status=403)
    else:
        return HttpResponse(status=405)
Вернуться на верх