具有动态数量表单的页面,每个表单对应 table 行

Page with a dynamic number of forms, each form for each table row

公司有工人在一天中进行各种活动。每个 activity 有 start_timefinish_time。通常工作人员忘记在 activity (finish_time) 结束时发出哔哔声,那是因为有一个存储过程 read_unended time_from time_to 读取 time_from 和 [=20= 之间的记录] 没有 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) 中有一个视图显示这样一个 table。

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 %}

** 和 * 尚未实现。 我想实现以下功能。在动态生成的 table 的每一行中,应该有一个按钮 ** 来完成这个 activity (这一行)与时间 * 应用程序的用户插入。在那一刻页面应该刷新并且该行不应该再显示,因为这个 activity 已经被分配 finish_time。我怎样才能实现这样的视图和模板?我是否需要向现有表单添加动态生成的字段?你有什么建议?

您必须创建一个函数来 post 您的数据,另一个函数来获取 table 正文

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.0 }}0">{{i.0}}</td>
            <td id="tdId_{{ i.0 }}1">{{i.1}}</td>
            <td id="tdId_{{ i.0 }}2">{{i.2}}</td>
            <td id="tdId_{{ i.0 }}3">{{i.3}}</td>
            <td><input type="date" id="tdId_{{i.0}}4"/></td>
            <td id="tdId_{{ i.0 }}5">{{i.5}}</td>
            <td id="tdId_{{ i.0 }}6">{{i.6}}</td>
            <td><button value="{{i.0}}" type="button" onclick="setEndActivity(this.value)">End</button><td/>
        </tr>
        {% endfor %}
    </tbody>
</table>
<script>
function loadResults(activityId) {
    let xhttpRequest = new XMLHttpRequest()
    const start_date = document.getElementById(`tdId_${activityId}2`).value
    const start_time = document.getElementById(`tdId_${activityId}3`).value
    const end_date = document.getElementById(`tdId_${activityId}2`).value
    const end_time = document.getElementById(`tdId_${activityId}4`).value
    xhttpRequest.onreadystatechange = function (data) {
        if (this.readyState === 4 && this.status === 200) {
            document.getElementById("tbodyId").innerHTML = this.response
        }
    }
    xhttpRequest.open("GET", `./ajax/load-results?start_date=${start_date}&end_date=${end_date}&start_time=${start_time}&end_time=${end_time}`, true)
    xhttpRequest.send()
}

function setEndActivity(activityId) {
    const dataToBackEnd = new FormData()
    dataToBackEnd.append("activity", activityId)
    dataToBackEnd.append("start_date", document.getElementById(`tdId_${activityId}2`).value)
    dataToBackEnd.append("start_time", document.getElementById(`tdId_${activityId}3`).value)
    dataToBackEnd.append("end_date", document.getElementById(`tdId_${activityId}2`).value)
    dataToBackEnd.append("end_time", document.getElementById(`tdId_${activityId}4`).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(activityId)
            } else {
                alert("Error")
            }
        }
    )
}
</script>

在您的视图中,您将添加 2 个视图,如果您修改“结束”视图以接收 post 和 return 一个 http 响应,则仅添加 1 个视图

views.py

def ajax_ending(req):
    if req.method == "POST":
        from_to_form = FromToForm(req.POST)
        if from_to_form.is_valid():
            # save in database
            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
        start_date = request.GET['start_date']
        start_time = request.GET['start_time']
        start_date_time = f'{start_date} {start_time}'
        end_date = request.GET['end_date']
        end_time = request.GET['end_time']
        end_date_time = f'{end_date} {end_time}'
        # this datetime.strptime depends of how you write your date and time
        start = datetime.strptime(start_date_time, "%d-%m-%Y %H:%M:%S").isoformat()
        end = datetime.strptime(end_date_time, "%d-%m-%Y %H:%M:%S").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 render(request, 'ajax-ending.html', {"context": context})
    else:
        return HttpResponse(status=403)
else:
    return HttpResponse(status=405)

并且您将有另一个 template.html 仅供 table

的 tbody

ajax-ending.html

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

ulrs.py

from django.urls import path
from . import views


app_name = 'your_app_name'

urlpatterns = [
        'ending/',
        views.ending, 
        name='ending'),
    path(
        'ending/ajax/end-activity/',
        views.ajax_ending, 
        name='ajax_ending'),
    path(
        'ending/ajax/load-results/',
        views.ajax_load_results, 
        name='ajax_load_results'),
]

(未测试,如果抛出错误请告诉我)