Django Bootstrap Modal: CRUD для модели с внешним ключом

Models.py:

class Dossier(models.Model):
name = models.CharField('Name', max_length=200)
class Meta:
    verbose_name = 'Dossier'
    verbose_name_plural = 'Dossiers'

def __str__(self):
    return self.name


class Activity(models.Model):
    dossier = models.ForeignKey(Dossier, on_delete=models.CASCADE, verbose_name='Dossier')
    detail = models.CharField('Activity', max_length=1000)
    topic = models.ForeignKey(Topic, on_delete=models.CASCADE, verbose_name='Topic')
    source_url = models.CharField('Source URL', max_length=1000, null=True, blank=True)
    class Meta:
        verbose_name = 'Activity'
        verbose_name_plural = 'Activities'

    def __str__(self):
        return self.detail

Github Repo: имя пользователя: admin пароль admin:

Я хочу асинхронно добавлять, редактировать и удалять Activity для Dossier при редактировании с помощью Bootstrap-modal. Я пытался следовать этой статье .

urls.py:

from django.urls import path
from bpsbpoliticaldb import views
urlpatterns = [    
    path('dossiers/edit/<str:pk>/', views.dossier_edit, name="dossier_edit"),
    path('dossiers/activity/<str:pk>/', views.dossier_activity_create, name="dossier_activity_create"),
    path('dossiers/activity/add/', views.dossier_activity_add, name="dossier_activity_add"),
]

views.py:

def dossier_edit(request, pk):
    dossier = get_object_or_404(Dossier, id=pk)
    activities = Activity.objects.filter(dossier=dossier)

    context = {'dossier': dossier, 'activities': activities}
    return render(request, 'bpsbpoliticaldb/dossier/dossier_edit.html', context)


def dossier_activity_create(request, pk):
    data = dict()
    if request.method == 'POST':
        form  = ActivityForm(request.POST)
        if form.is_valid():
            form.save()
            data['form_is_valid'] = True
        else:
            data['form_is_valid'] = False
    else:        
        form = ActivityForm()
    context = {'form': form}
    data['html_form'] = render_to_string('bpsbpoliticaldb/activity/partial_activity_create.html',
        context,
        request=request,
    )
    return JsonResponse(data)

forms.py:

from django.forms import ModelForm
from django import forms

class ActivityForm(ModelForm):
    class Meta:
        model = Activity
        widgets = {
            'detail': forms.Textarea(attrs={'class': 'form-control', 'rows': 5}),
            'topic': forms.Select(attrs={'class': 'form-control'}),
            'source_url': forms.TextInput(attrs={'class': 'form-control'}),
        }
        fields = ['detail', 'topic', 'source_url']

dossier_edit.html

{% extends 'bpsbpoliticaldb/base.html' %}
{% load static %}
{% load crispy_forms_tags %}

{% block content %}
<div class="">
    <div class="card">
        <div class="card-header">
            <div class="row">
                <div class="col-sm">
                  Dossier ID: {{ dossier.id }}
                </div>
                <div class="col-sm">
                    Dossier Name: {{ dossier.name }}                    
                    <a href="{% url 'dossier_update' dossier.id %}" type="button" class="update-book btn btn-sm btn-primary">
                        <i class="far fa-edit"></i>
                    </a>
                </div>
                <div class="col-sm">
                  Download Report
                </div>
            </div>
        </div>

            <div class="row">
                <div class="card-body shadow">
                    <ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
                        <li class="nav-item" role="presentation">
                            <a class="nav-link active" id="pills-activity-tab" data-toggle="pill" href="#pills-activity" role="tab" aria-controls="pills-activity" aria-selected="true">Activity</a>
                        </li>
                    </ul>
                    <div class="tab-content" id="pills-tabContent">
                        <div class="tab-pane fade show active" id="pills-activity" role="tabpanel" aria-labelledby="pills-activity-tab">
                            
                            <button type="button" data-url="{% url 'dossier_activity_create' dossier.id %}" class="btn btn-warning js-dossier-create">
                                <i class="fas fa-plus">Add Activity</i>
                            </button>
                            {% include 'bpsbpoliticaldb/dossier/activities.html' %}
                        </div>
                    </div>
                </div>
            </div>
            <!-- ============================================================== -->
            <!-- THE MODAL WE WILL BE USING -->
            <div class="modal fade" id="modal-dossier">
                <div class="modal-dialog modal-lg">
                    <div class="modal-content">
                    </div>
                </div>
            </div>
            <!-- ============================================================== -->
            
        </div>
    </div>
</div>

{% endblock %}

activities.html:

<div style="overflow:auto">
    <table id="activity-table" class="my_table table table-striped table-hover">
        <thead>
            <tr>
                <th scope="col">Topic</th>
                <th scope="col">Detail</th>
                <th scope="col">Added At</th>
                {% for group in user.groups.all %}
                  {% if group.name == 'admin' or group.name == 'user' %}
                <th scope="col">Edit</th>
                <th scope="col">Delete</th>
                  {% endif %}
                {% endfor %}
            </tr>
        </thead>
        <tbody>
        {% for activity in activities %}
            <tr>
                <td>{{ activity.topic }}</td>
                <td>
                  <a href="{{ activity.source_url }}" target="_blank"><i class="fas fa-info-circle" style="color: #f4645f;"></i></a>
                  {{ activity.detail }}
                </td>
                <td>{{ activity.added_at }}</td>
                {% for group in user.groups.all %}
                  {% if group.name == 'admin' or group.name == 'user' %}
                <td class="text-center">
                    <a href="#" type="button" class="js-update-activity btn btn-sm btn-primary">
                      <i class="far fa-edit"></i>
                    </a>
                </td>
                <td class="text-center">
                    <a href="#" type="button" class="js-delete-activity btn btn-sm btn-danger">
                      <i class="fa fa-trash"></i>
                    </a>
                </td>
                  {% endif %}
                {% endfor %}
            </tr>
        {% endfor %}
        </tbody>
    </table>
</div>

partial_activity_create.html:

{% load crispy_forms_tags %}

<form action="{% url 'dossier_activity_create' dossier.id %}" method="POST" autocomplete="off" id="myForm">
    {% csrf_token %}
    
    <div class="modal-header">
        <h4 class="modal-title">Add Activity</h4>
    </div>
    <div class="modal-body">
        {{ form.as_p }}   
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="submit" class="btn btn-primary">Add Activity</button>
    </div>
</form>

main.js:

$(function () {

    var loadForm = function () {
        var btn = $(this);
        $.ajax({
            url: btn.attr("data-url"),
            type: 'get',
            dataType: 'json',
            beforeSend: function () {
                $("#modal-dossier").modal("show");
            },
            success: function (data) {
                $("#modal-dossier .modal-content").html(data.html_form);
            }
        });
    };

    var saveForm = function () {
        var form = $(this);
        $.ajax({
            url: form.attr("action"),
            data: form.serialize(),
            type: form.attr("method"),
            dataType: 'json',
            success: function (data) {
                if (data.form_is_valid) {
                    $("#dossier-table").html(data.html_dossier_list);
                    $("#modal-dossier").modal("hide");
                }
                else {
                    $("#modal-dossier .modal-content").html(data.html_form);
                }
            }
        });
        return false;
    };

    /* Binding */

    // Create activity
    $(".js-dossier-create").click(loadForm);
    $("#modal-dossier").on("submit", ".js-dossier-create-form", saveForm);
});

Как я могу добавлять, редактировать и удалять деятельность для досье? Любая помощь будет принята с благодарностью.

в urls.py:

from django.urls import path
from bpsbpoliticaldb import views

urlpatterns = [    
    path('dossiers/edit/<str:pk>/', views.dossier_edit, name="dossier_edit"),
    path('dossiers/activity/edit/', views.dossier_activity_create, name="dossier_activity_create"),
    path('dossiers/activity/add/', views.dossier_activity_add, name="dossier_activity_add"),
]

в partial_activity_create.html:

{% load crispy_forms_tags %}

<form action="{% url 'dossier_activity_create' %}" method="POST" autocomplete="off" id="myForm">
    {% csrf_token %}
    {% if dossier %}<input type="hidden" value="{{ dossier.id }}" name="id" />{% endif %}
    
    <div class="modal-header">
        <h4 class="modal-title">Add Activity</h4>
    </div>
    <div class="modal-body">
        {{ form.as_p }}   
    </div>
    <div class="modal-footer">
        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        <button type="submit" class="btn btn-primary">Add Activity</button>
    </div>
</form>

в представлениях измените def dossier_activity_create(request, pk): на def dossier_activity_create(request):

и в файле dossier_edit.html изменить {% url 'dossier_activity_create' dossier.id %} на {% url 'dossier_activity_create' %}

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