具有动态数量表单的页面,每个表单对应 table 行
Page with a dynamic number of forms, each form for each table row
公司有工人在一天中进行各种活动。每个 activity 有 start_time
和 finish_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'),
]
(未测试,如果抛出错误请告诉我)
公司有工人在一天中进行各种活动。每个 activity 有 start_time
和 finish_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
的 tbodyajax-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'),
]
(未测试,如果抛出错误请告诉我)