#本文欢迎转载,转载请注明出处和作者
课程选课页面,会用到查询后台数据库信息并且返回给前端展示,然后前端有按钮可以点击需要选修的课程,然后返回给后台写入数据库记录。是之前08、09的两篇的实际应用案例:
Python+Django网站开发系列08-JavaScript/JQuery前后端交互zhuanlan.zhihu.comPython+Django网站开发系列09-django前端展示后台数据zhuanlan.zhihu.com1、课程选课页面展示
依然在magicbox里面选取表格组件,这次我们选择一个带按钮的表格样式,方便后面做选课,然后复制代码粘贴到stuinfo/tchinfo的html页面。(就是<table>标签里面的内容)
{% extends 'BASE02.html' %}{% block content %}<table class="table table-bordered table7_demo"><thead><tr><th>课程ID</th><th>课程名称</th><th>学分</th><th>上课时间</th><th>上课地点</th><th>操作</th></tr></thead><tbody><tr>{% for i in courseinfo %}<td>{{ i.cno }}</td><td>{{ i.cname }}</td><td>{{ i.ccredit }}</td><td>{{ i.ctime }}</td><td>{{ i.cplace }}</td><td><button class="btn btn-xs btn-success" title="激活"><i class="glyphicon glyphicon-ok"></i></button><button class="btn btn-xs btn-danger" title="删除"><i class="glyphicon glyphicon-remove"></i></button></td></tr>{% endfor %}</tbody></table>
{% endblock %}
函数增加查询后台数据库表全部数据,并且返回给前端页面。
def selcourse(request):courseinfo = course.objects.all()return render_to_response('selcourse.html',locals())
效果如下:
2、按钮点击JS
2.1选课按钮业务逻辑
选课按钮的业务逻辑,有了前面的基础,就非常好弄了,与之前修改密码一样,通过JS进行编写,编写stumgrjs.js文件,增加addcourse函数。(也是通过.post向后台推送数据)
JS函数,注意也需要带参数输入,括号里面有个参数,将课程ID推送到selcourse后台函数。
function addcourse(cno) {$.post('/selcourse/', {'cno':cno,}, function (res) {if(res.result){alert("选课成功!");window.location.reload();}else{alert("选课失败!");window.location.reload();}}, 'json')
}
修改selcourse业务逻辑:这里涉及ORM查询数据库操作,而且课程表(course)与学生表(course)之间是没有直接关联的,是通过中间表-成绩表(score)进行关联的,所以需要插入数据的是score表。
def selcourse(request):if request.method == 'POST' and request.POST:cno = request.POST['cno']username = request.session['username']user = student.objects.get(username=username)sno = user.snoscore.objects.create(cno_id=cno,sno_id=sno)result = Truereturn JsonResponse({'result': result})courseinfo = course.objects.all()return render_to_response('selcourse.html',locals())
先查询当前登录用户的sno,然后cno与sno一切写入score表,创建一条数据,注意当前score表里面的sno叫sno_id,cno叫cno_id,因为是外键引用,所以会自动改了字段名。
前端selcourse.html页面按钮编辑:与之前的onclick唯一的区别,就是调用的js函数可以带参数将'{{ i.cno }}'输入到JS函数,然后JS将cno这个id字段通过post返回给后台,这样后台就能够知道是要选修哪一门课程了。
<button class="btn btn-xs btn-success" title="激活" onclick="addcourse('{{ i.no }}',)">
但是当前的业务逻辑存在Bug,1是同一个的课程可以多次选修,2是每个人可以无限选修课程。需要继续优化业务逻辑。
def selcourse(request):if request.method == 'POST' and request.POST:cno = request.POST['cno']username = request.session['username']user = student.objects.get(username=username)sno = user.sno# 判断当前课程是否已经选修selected = score.objects.filter(cno_id=cno,sno_id=sno)# 技术已选课程数量,counted.count()直接统计数字counted = score.objects.filter(sno_id=sno)if selected:result = '课程已选修,请勿重复选择!'return JsonResponse({'result': result})elif counted.count() >=2:result = '已达到最大选修课程数量!'return JsonResponse({'result': result})else:#选课成功,写入数据库score.objects.create(cno_id=cno,sno_id=sno)result = 'True'return JsonResponse({'result': result})courseinfo = course.objects.all()return render_to_response('selcourse.html',locals())
JS代码返回的显示内容适度修改:
function addcourse(cno) {$.post('/selcourse/', {'cno':cno,}, function (res) {if(res.result=='True'){alert("选课成功!");window.location.reload();}else{alert(res.result);window.location.reload();}}, 'json')
}
最终效果如下,重复选课提示已选,选修超过2门课程提示超过最大数量,选课成功提示成功。
2.2已选课程删除
同样删除按钮需要使用js向后端传输课程号,html按钮绑定delcourse的js函数,后台业务逻辑函数调用ORM的delete命令进行删除。
JS函数编辑:我们还是采用同样的.post向后台推送数据。
function delcourse(cno) {$.post('/delcourse/', {'cno':cno,}, function (res) {if(res.result=='True'){alert("删除成功!");window.location.reload();}else{alert(res.result);window.location.reload();}}, 'json')
}
编辑views.py业务逻辑:单独增加一个删除函数。
def delcourse(request):if request.method == 'POST' and request.POST:cno = request.POST['cno']username = request.session['username']user = student.objects.get(username=username)sno = user.sno# 判断当前要删除的课程是否已选择selected = score.objects.filter(cno_id=cno,sno_id=sno)if selected:score.objects.filter(cno_id=cno,sno_id=sno).delete()result = 'True'return JsonResponse({'result': result})else:#课程未选择,返回错误result = '课程未选修,无法删除!'return JsonResponse({'result': result})
views里面增加了函数,urls记得也要注册路由。
urlpatterns = [......url(r'^delcourse/', delcourse),
]
最后前端selcourse.html页面绑定到删除按钮:
<button class="btn btn-xs btn-danger" title="删除" onclick="delcourse('{{ i.cno }}',)">
最终效果如下:
3、已选课程展示
还是利用magicbox选择一个面板,拷贝代码,然后利旧一下stuinfo里面的<table>标签代码,拷贝一段,按照已选课程需要展示的字段进行修改。
这里的难点有一个关联查询,因为course只有课程内容,没有授课老师,需要通过tno进行跨表连接,而student与course也没有直接联系,需要通过score中间表来进行连接,因此需要进行多表的跨表查询。
(现实生产环境的数据库表与字段比这里的数量要多得多,因此,能够达到目标查询要求的SQL语句的编写,也是数据库开发岗位日常工作的一部分。)
前端页面:stuinfo.html原来</table>后面继续增加面板与表格。
<div class="king-panel8 m15"><div class="king-panel8-header"><h3 class="king-panel8-title king-info">已选课程</h3></div><div class="king-panel8-content pt25"><table class="table table-bordered"><thead><tr><th>课程ID</th><th>课程名称</th><th>学分</th><th>上课时间</th><th>上课地点</th><th>授课老师</th></tr></thead><tbody>{% for j in selcourse %}<tr><td>{{ j.score__cno }}</td><td>{{ j.score__cno__cname }}</td><td>{{ j.score__cno__ccredit }}</td><td>{{ j.score__cno__ctime }}</td><td>{{ j.score__cno__cplace}}</td><td>{{ j.score__cno__tno_id__tname }}</td></tr>{% endfor %}</tbody></table></div></div>
业务逻辑:
def stuinfo(request):username = request.session['username']userinfo = student.objects.filter(username=username)selcourse = student.objects.filter(username=username).values('score__cno','score__cno__cname','score__cno__ccredit','score__cno__ctime','score__cno__cplace','score__cno__tno_id__tname')print (selcourse)return render_to_response('stuinfo.html',locals())
以上述为例,关联查询,首先找student表进行查询,然后与student表直接关联的表格是score表,所以后面values首先写score,然后双下划线可以直接引用score表里面的字段cno。然后通过cno可以关联到course里面的字段吗,再双下划线引用,通过course里面的tno_id字段又可以关联到teacher表,最后引用teacher表字段。
最终刷新页面效果如下: