Django表单记录签到数据--Mac系统下Django学习实践(六)
【前情提要】
Mac系统下Django学习实践(一)–安装搭建环境
Mac系统下Django学习实践(二)–实践第一个界面打印helloworld
Mac系统下Django学习实践(三)–搭建简单数据库
Mac系统下Django学习实践(四)–利用Django管理页面
Mac系统下Django学习实践(五)–多视图页面与URL
【代码托管–GitHub】
https://github.com/irishongyuan/Django_Sign/tree/master
—————————————————————————————————————————
今天我们将在昨天的基础上完成Django表单的设计,并实现签到数据从网页写入数据库并展示出来。
编写一个简单的表单
在昨天的acsign/templates/acsign/detail.html页面加入表单设计,实现用户可以通过输入自己的姓名进行签到。
<h1>{{activity.activity_theme}}</h1>
<h3>{{activity.pub_date}}</h3>
{% if error_message %}<p><strong>{{error_message}}</strong></p>
{% endif %}
<form action="{% url 'acsign:sign' activity.id %}" method="post">
{% csrf_token %}
sign_name: <input type="text" name="sign_name" value="InputYourName"><br>
<input type="submit" value="签到">
<ul>
{% for sign in activity.sign_set.all %}
<li>{{ sign.sign_name }} -- {{ sign.sign_date }}</li>
{% endfor %}
</ul>
</form>
这里表单是
<form action="{% url 'acsign:sign' activity.id %}" method="post">
... ...
</form>
的格式,其中action中的内容代表表单中的数据将流向哪里;method有Get和Post两种方式,Post方式更加宽泛,所有针对内部 URL 的 POST 表单都应该使用 {% csrf_token %} 模板标签;通过<input可以在表单中插入各种控件选项,包括text文本框、submit提交按钮、radio单选框、password密码输入框等等。
此时我们打开网页http://127.0.0.1:8000/acsign/1/,页面效果如下:
处理提交数据
我们把表单数据通过action="{% url ‘acsign:sign’ activity.id %}"传入到了acsign/views.py中的sign函数,于是我们在sign函数中进行对数据的接收和处理。
from django.shortcuts import get_object_or_404, render
from django.http import HttpResponseRedirect
from django.utils import timezone
from django.urls import reverse
from .models import Sign, Activity
def sign(request, activity_id):
activity = get_object_or_404(Activity, pk=activity_id)
sign_name = request.POST['sign_name']
#防止重复签到
for sign_object in activity.sign_set.all():
if sign_name == sign_object.sign_name:
return render(request, 'acsign/detail.html', {
'activity': activity,
'error_message': "You have signed, don't repeat sign.",
})
#防止签到数据为空
if "" == sign_name or "InputYourName" == sign_name :
return render(request, 'acsign/detail.html', {
'activity': activity,
'error_message': "You didn't sign by your name.",
})
else:
activity.sign_set.create(sign_name=sign_name, sign_date=timezone.now())
activity.save()
#返回签到成功后页面,即调用results函数
return HttpResponseRedirect(reverse('acsign:results', args=(activity_id,)))
其中我们用sign_name = request.POST[‘sign_name’]接收数据。
注意这里加入了重复数据和空数据的拦截,不然会出现如下错误:
Jack重复签了两次到,空名字也可以被签到。
修改后如若再重复签到会在当前页面提示错误:
签到后的跳转页面
在上面的代码中,我们在 HttpResponseRedirect 的构造函数中使用 reverse() 函数,避免了我们在视图函数中硬编码 URL,只需要我们给出1,想要跳转到的视图的名字 2,需要给该视图提供的参数。于是我们便在提交成功后将当前签到的activity_id传给results函数。
那么我们来看下acsign/views.py中的results函数:
def results(request, activity_id):
activity = get_object_or_404(Activity, pk=activity_id)
return render(request, 'acsign/results.html', {'activity':activity})
对应的acsign/templates/acsign/results.html页面如下:
<h1>{{activity.activity_theme}}</h1>
<h3>{{activity.pub_date}}</h3>
<ul>
{% for sign in activity.sign_set.all %}
<li>{{ sign.sign_name }} -- {{ sign.sign_date }}</li>
{% endfor %}
</ul>
<a href="{% url 'acsign:detail' activity.id %}">Sign again</a>
现在我们为Jack点击签到提交后跳转到http://127.0.0.1:8000/acsign/1/results/ 页面,如下:
点击Sign again返回之前的签到页面http://127.0.0.1:8000/acsign/1/ ,Jack的签到数据已经更新: