Страница с динамическим количеством форм, каждая форма для каждой строки таблицы

В компании есть работники, выполняющие различные виды деятельности в течение дня. У каждого вида деятельности есть start_time и finish_time. Обычно работники забывают подать звуковой сигнал об окончании деятельности (finish_time), и это потому, что существует хранимая процедура read_unended time_from time_to, которая считывает записи между time_from и time_to, в которых нет finish_time (есть NULL). Например

id  name    day         start_time              finish_time place   activity
38  Thomas  2021-12-03  2021-12-03 08:51:38.000 NULL    p1  a1
28  Charles 2021-12-02  2021-12-02 12:29:03.000 NULL    p2  a2
49  John    2021-12-06  2021-12-06 11:59:48.000 NULL    p3  a3
68  Jessie  2021-12-08  2021-12-08 10:55:12.000 NULL    p4  a4
82  Susanne 2021-12-10  2021-12-10 12:38:03.000 NULL    p5  a5

Существует форма в (forms.py)

class FromToForm(Form):
    start_date = DateField(widget=AdminDateWidget())
    start_time = TimeField(widget=AdminTimeWidget())
    end_date = DateField(widget=AdminDateWidget())
    end_time = TimeField(widget=AdminTimeWidget())

Существует представление в (views.py), которое отображает такую таблицу.

def ending(req):
    from_to_form = FromToForm()
    result = []
    context = {
                'form': from_to_form,
                'result': result
              }
    if req.method == "POST":
        from_to_form = FromToForm(req.POST)
        if from_to_form.is_valid():
            start = datetime.combine(from_to_form.cleaned_data['start_date'], from_to_form.cleaned_data['start_time']).isoformat()
            end = datetime.combine(from_to_form.cleaned_data['end_date'], from_to_form.cleaned_data['end_time']).isoformat()
            with connections["mssql_database"].cursor() as cursor:
                cursor.execute("EXEC read_unended @dt_od='%s', @dt_do='%s'" % (start, end))
                result = cursor.fetchall()
            context['result'] = result
            return render(req, 'ending.html', context)
        else:
            return render(req, 'ending.html', context)
    else:
        return render(req, 'ending.html', context)

и связанный с ним шаблон в templates.py.

<form action='.' method='POST'>{% csrf_token %}
                {{ form.media }}
                {{ form.as_p }}
                <input type='submit' value='Read unended' class="btn btn-secondary" />
        </form>
{% if result %}
        <table class="table mb-0">
                <thead>
                        <tr>
                                <th>id</th>
                                <th>name</th>
                                <th>day</th>
                                <th>start_time</th>
                                <th>finish_time</th>
                                <th>place</th>
                                <th>activity</th>
                        </tr>
                </thead>
                <tbody>
                   {%for i in result %}
                     <tr>
                           <td>{{i.0}}</td>
                           <td>{{i.1}}</td>
                           <td>{{i.2}}</td>
                           <td>{{i.3}}</td>
                           <td>CELL TO INSERT END TIME*</td>
                           <td>{{i.5}}</td>
                           <td>{{i.6}}</td>
                           <td>BUTTON TO FINISH THIS ACTIVITY**<td/>
                     </tr>
                   {% endfor %}
                </tbody>
        </table>
        {% else %}
           Every activity is ended
        {% endif %}

** и * пока не реализованы. Я хотел бы реализовать следующую функциональность. В каждой строке динамически генерируемой таблицы должна быть кнопка ** для завершения этой активности (этой строки) со временем * вставки пользователем приложения. В этот момент страница должна обновиться и эта строка больше не должна отображаться, так как эта активность уже finish_time назначена. Как я могу реализовать такое представление и шаблон? Нужно ли мне добавить динамически генерируемые поля в существующую форму? Что вы посоветуете?

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

template.html

<table class="table mb-0">
        <thead>
            <tr>
                <th>id</th>
                <th>name</th>
                <th>day</th>
                <th>start_time</th>
                <th>finish_time</th>
                <th>place</th>
                <th>activity</th>
            </tr>
        </thead>
        <tbody id="tbodyId">
            {% for i in result %}
            <tr>
                <td id="tdId_{{ i.id }}0">{{i.0}}</td>
                <td id="tdId_{{ i.id }}1">{{i.1}}</td>
                <td id="tdId_{{ i.id }}2">{{i.2}}</td>
                <td id="tdId_{{ i.id }}3">{{i.3}}</td>
                <td id="tdId_{{ i.id }}4">CELL TO INSERT END TIME*</td>
                <td id="tdId_{{ i.id }}5">{{i.5}}</td>
                <td id="tdId_{{ i.id }}6">{{i.6}}</td>
                <td><button value="{{i.id}}" type="button" onclick="setEndActivity(this.value)">End</button><td/>
            </tr>
            {% endfor %}
        </tbody>
    </table>
<script>
function loadResults() {
        let xhttpRequest = new XMLHttpRequest()
        xhttpRequest.onreadystatechange = function (data) {
            if (this.readyState === 4 && this.status === 200) {
                document.getElementById("tbodyId").innerHTML = this.response
            }
        }
        xhttpRequest.open("GET", "./ajax/load-results/", true)
        xhttpRequest.send()
    }

    function setEndActivity(activityId) {
        const dataToBackEnd = new FormData()
        dataToBackEnd.append("activity", activityId)
        dataToBackEnd.append("start_date", document.getElementById(`tdId_${i.id}2`).value)
        dataToBackEnd.append("start_time", document.getElementById(`tdId_${i.id}2`).value)
        dataToBackEnd.append("end_date", document.getElementById(`tdId_${i.id}2`).value)
        dataToBackEnd.append("end_time", document.getElementById(`tdId_${i.id}2`).value)
        const request = new Request('./ajax/end-activity/',
        {
            method: 'POST',
            headers: { 'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value },
            body: dataToBackEnd
        })
        fetch(request, {
            method: 'POST',
            mode: 'same-origin'
        }).then(
            function(response) {
                if (response.status === 200) {
                    loadResults()
                } else {
                    alert("Error")
                }
            }
        )
    }
</script>

В ваших представлениях вы добавите 2 представления, или только 1, если вы измените представление "ending" для получения поста и возврата http-ответа

views.py

def ajax_ending(req):
    if req.method == "POST":
        from_to_form = FromToForm(req.POST)
        if from_to_form.is_valid():
            start = datetime.combine(from_to_form.cleaned_data['start_date'], from_to_form.cleaned_data['start_time']).isoformat()
            end = datetime.combine(from_to_form.cleaned_data['end_date'], from_to_form.cleaned_data['end_time']).isoformat()
            # i don't understand why you are executing queries like this, so i assume they work
            with connections["mssql_database"].cursor() as cursor:
                cursor.execute("EXEC read_unended @dt_od='%s', @dt_do='%s'" % (start, end))
                result = cursor.fetchall()
            context['result'] = result
            return HttpResponse(status=200)
        else:
            return HttpResponse(status=400)
    else:
        return HttpResponse(status=405)


def ajax_load_results(request):
    if request.method == "GET":
        if request.user:
            # get the activities
            context = 
            return render(request, 'ajax-ending.html', {"context": context})
        else:
            return HttpResponse(status=403)
    else:
        return HttpResponse(status=405)

И у вас будет еще один template.html только для tbody таблицы

ajax-ending.html

{% for i in result %}
    <tr>
        <td id="tdId_{{ i.id }}0">{{i.0}}</td>
        <td id="tdId_{{ i.id }}1">{{i.1}}</td>
        <td id="tdId_{{ i.id }}2">{{i.2}}</td>
        <td id="tdId_{{ i.id }}3">{{i.3}}</td>
        <td id="tdId_{{ i.id }}4">CELL TO INSERT END TIME*</td>
        <td id="tdId_{{ i.id }}5">{{i.5}}</td>
        <td id="tdId_{{ i.id }}6">{{i.6}}</td>
        <td><button value="{{i.id}}" type="button" onclick="setEndActivity(this.value)">End</button><td/>
    </tr>
{% endfor %}

(Не тестировалось, если возникнет ошибка, дайте мне знать)

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