通过前面的教程,对 Django 开发应用的一般流程有了清晰的认识。本讲主要内容:

1.数据记录批量入库
2.用户自定义模板标签及过滤器
3.深入理解 MTV 模式

来看一个 MTV 模式图(来自互联网):

使用命令 django-admin startapp choicetest 来创建 choicetest 应用,并创建同名模板文件夹,结合选择题测试应用的开发过程展开本讲。本讲中的选择题来自卓帆系统和百日冲刺及高中信息技术教材的内容,特此鸣谢。

一、urls.py 部分

from django.urls import path
from choicetest.views import *
#choicequeston 路由
path('ch_index/', ch_index, name="chindex"),
path('ch_judge/', ch_judge, name="chjudge"),
path('ch_zhuofang/', ch_zhuofang, name="chzhuofang"),
path('ch_hundreday/', ch_hundreday, name="chhundreday"),
path('ch_correct/', ch_correct, name="chcorrect"),

path 函数有多个参数,这里介绍用到三个参数,第一个是给浏览器访问或 views.py 中 redirect()函数访问的地址、第二个是 views.py 中定义的视图函数、第三个参数 name 是这个 url 的名称,在模板文件中使用的形式为{% url ‘<name>’ [参数] %},当然你可以在模板文件中使用第一参数构成的绝对地址。

二、views.py 部分

from almond.models import  Choicetimu, Examination
def ch_index(request):pass
def ch_zhuofang(request):pass
def ch_hundreday(request):pass
def ch_correct(request):pass
def ch_judge(request):pass

1. 视图函数 ch_index 作用是查询学生完成选择题的进度、正确率,对应的模板让学生选择部分选择题来练习。看代码及解释。

def ch_index(request):curuser = request.user#获取选择题总数choiceset_count = Choicetimu.objects.all().count()#获取学生做对的选择题的 id 号的记录集rightset = Examination.objects.filter( Q( esid = curuser.sid ) & Q( whidname = 'chid' ) & Q( egrade = 2 ) ).distinct('whidval').order_by('whidval')rights = [v.whidval for v in rightset]#获取学生做错的选择的 id 号的记录集errorset = Examination.objects.filter( Q( esid = curuser.sid ) & Q( whidname = 'chid' ) & Q( egrade = 0 ) ).distinct('whidval').order_by('whidval')errors = [v.whidval for v in errorset]#错题集要减去订正的errors = sorted(list(set(errors) - set(rights)))#做对、做错、已做的题目数rightlen = len(rights);    errorlen = len(errors);    r_e_len = rightlen+errorlen#进度及正确率,把不需要的变量删除rightrate = 0 if r_e_len==0 else rightlen/r_e_len*100progressrate = r_e_len/choiceset_count*100del rightset,errorset,rightlen#准备好列表,在模板中应用。django 模板中没有生成列表字典的功能,可以这里传过去。或自定义模板标签定义过滤器zflist = list(range(1,16))chlist = list(range(1,choiceset_count+1))return render(request, 'choicetest/ch_index.html', locals() )

2. 视图函数 ch_zhuofang、ch_hundreday、cn_correct 的作用分别是根据用户选择卓帆、百日冲刺或订正选择题,它们的模板是 ch_test.html, 放在一起说吧。

  • 选择题目
#视图函数 ch_zhuofang 片断,卓帆题目中选择,百日冲刺的题目相似不列出
curuser = request.user
yourchoice = request.POST
if yourchoice['zhfan'] == '0':choicecount = int(yourchoice['choicecount0'])if choicecount<=0 or choicecount>50:choicecount=25##随机抽取题目 order_by('?')dxt = Choicetimu.objects.filter(Q( cbigitem = '卓帆')).order_by('?')[:choicecount]title =  "卓帆选择题测试随机抽取试题"
elif 1<= int( yourchoice['zhfan']) <=15:choicecount=25youch = str(yourchoice["zhfan"])#选择卓帆 15 套中的某一套选择题练习dxt = Choicetimu.objects.filter(Q( cbigitem='卓帆' ) & Q(  csmallitem = youch) )title = "卓帆选择题测试第"+ youch  +"套"#视图函数 ch_correct,订正题目的选择
curuser = request.userchoicecount=25#下面语句是选择做错的,排除已经订正的,抽取 25 道,不足以实际为准sqlstr = f"""select * from choicetimu where cid in (select distinct whidval from examination where esid={curuser.sid} and whidname='chid' and whidval>0 and egrade=0 and whidval not in (select distinct whidval from examination where esid={curuser.sid} and whidval>0 and egrade>0)) order by cid limit {choicecount} """
title = "选择题订正"
dxt = Choicetimu.objects.raw(sqlstr)
  • 整理试题集

选择题的顺序很重要,将来学生做完成提交到 ch_judge 视图时要评分,评分后还以一致顺序回馈到学生端。

#整理题目的顺序,id 号放在列表中 dxt_cid_lst
dxt_cid_lst = []
for item in dxt:dxt_cid_lst.append(item.cid)choicecount += 1
#实际试题数,若为 0 返回到本应用的首页
if choicecount == 0:return redirect('/ch_index')
#设置 session,评分时使用,确认试题顺序
request.session['dxt_cid_lst'] = str(dxt_cid_lst)
request.session['title'] = title
#这部分代码片断,三个视图是一致的
return render(request, 'choicetest/ch_test.html', locals() )

3. 视图函数 ch_judge 作用是评分,还是通过代码来讲解。

curuser = request.user
title = request.session.get('title','-1')
#获取上述三个视图函数传递过来的题目顺序
dxt_cid_lst = eval(request.session.get('dxt_cid_lst','-1'))
#获取表单提交的学生答案
data_form  = request.POST.copy()
#每道题目构建一个 Examination 模型对象,放入列表 Exam_lst 中
Exam_lst = [];
#dxt_dct 放置试题,整理顺序
dxt_dct = {};
for item in  Choicetimu.objects.filter( Q ( cid__in = dxt_cid_lst)):dxt_dct[item.cid] = item#累计学生成绩
dxt_stu_grade = 0
dxt_stu_answer = dict()
#根据题目的顺序,给每道题目评分
for chid in dxt_cid_lst:std_item = dxt_dct[chid]stu_item = dxt_stu_answer[cid]  = data_form.get(f'dxt{chid}', 'None')if  stu_item == std_item.canswer :#每题 2 分dxt_stu_grade += 2#准备模型对象exam = Examination(esid = curuser, whidname='chid', whidval = chid, eanswer = stu_answer, egrade = 2 ) Exam_lst.append(exam)else:if stu_answer != 'None':#做错了,不得分,记录也要存入数据库#对没有做的题目,不做 处理exam = Examination(esid = curuser, whidname='chid', whidval = chid, eanswer = stu_answer, egrade = 0 ) Exam_lst.append(exam)if len(Exam_list)>0:#bulk_create 方法,记录批量存入数据库Examination.objects.bulk_create(Exam_lst)return render(request, 'choicetest/ch_judge.html', locals()  )

二、models.py 部分

上述用到了 Choicetimu 模型,对应了数据表 choicetimu,是存取选择题 的中介。Examination 是操作答题记录的模型。
本讲中随机获取记录:Choicetimu.objects.filter(Q( cbigitem = '卓帆')).order_by('?')[:choicecount];也用到了原生 sql 命令来查询订正题的记录的:Choicetimu.objects.raw(sqlstr);对于学生练习的多个选择题的答案,有多个 Examination 对象,准备好入在一个列表 Exam_lst,使用 Examination.objects.bulk_create(Exam_lst) 可批量入库。可见,django 模型提供了很大的便利。
Choicetimu 模型定义,对应的表是 choicetimu。

class Choicetimu(models.Model):cid = models.AutoField(primary_key=True)csub = models.IntegerField(blank=True, null=True)ctitle = models.TextField(blank=True, null=True)cana = models.TextField(blank=True, null=True)canb = models.TextField(blank=True, null=True)canc = models.TextField(blank=True, null=True)cand = models.TextField(blank=True, null=True)canswer = models.TextField(blank=True, null=True)cbigitem = models.TextField(blank=True, null=True)csmallitem = models.TextField(blank=True, null=True)ctag = models.TextField(blank=True, null=True)

在视图 ch_judge 中 item.ctag = stu_answer,把学生答案存入字段 ctag 中一并传入模板中,可靠地做到了答案与试题一一对应。

三、templates 部分

有 3 个模板文件,ch_index.html、ch_test.html、ch_judge.html。先介绍自字义模板标签,再介绍 3 个模板的关键部分。

1. 自定义模板标签和过滤器

在项目的根目录下创建目录 templatetags 中创建文件 mytags.py,文件名自取。在 settings.py 中加一段,指明模板标签文件的位置:

'OPTIONS': {............ 'libraries':{'mytags':'templatetags.mytags'}

看看 mytags.py 的内容,很简单,就是 python 的函数

from atexit import register
from django import template
register = template.Library()#遵循这个定义形式,定义注册名 avg 的过滤器
@register.filter(name='avg')
def myavg(value):return sum(value)/len(value)@register.filter(name='max')
def mymax(value):return max(value)@register.filter(name='ls')
def dtols(value):return list(value)@register.filter(name='ran')
def mylist(value,i=0):'''这个是带参数的过滤器产生从 1 开始的:{% for i in 15|ran 1%}'''return list(range(i,value))@register.filter(name='plus')
def mod(value,i):return value*int(i)@register.filter(name='mod')
def mod(value,i):return  0 if int(value)%int(i)==0 else 10-int(value)%int(i)#根据下标返回元素,可以是列表或字典
@register.filter(name='index')
def index(value,i):return value[i]@register.filter(name='split')
def split(value, key):return value.split(key)#以下是一个 在模板中定义变量的标签
class SetVarNode(template.Node):def __init__(self, var_name, var_value):self.var_name = var_nameself.var_value = var_valuedef render(self, context):try:value = template.Variable(self.var_value).resolve(context)except template.VariableDoesNotExist:value = ""context[self.var_name] = valuereturn u""def set_var(parser, token):"""{% set <var_name>  = <var_value> %}"""parts = token.split_contents()if len(parts) < 4:raise template.TemplateSyntaxError("'set 标签使用形式:  {% set <var_name>  = <var_value> %}")return SetVarNode(parts[1], parts[3])
#注册标签
register.tag('set',set_var)

这里有个效率问题:尽量在视图函数中把所需的简单变量、列表、字典准备好,在模板中少用过滤器处理数据,效率会更高。

2.模板文件内容介绍

在模板文件的最部,{% load mytags %}引入自定义的模板标签及过滤器。

ch_index.html 部分内容,

{% block content%}
<div class='row'><div class="col-md-1"></div><div class="col-md-10" ><div class='row'><h3>选择题完成情况:</h3></div><font size="5">{{curuser.sclass}}  {{curuser.sname}}  {{curuser.sno}} 正确率:{% if r_e_len > 0 %}{{ rightrate | floatformat:"2" }}%{% else %}None{% endif%}进度:{{ progressrate |floatformat:"2" }}%        {% if errorlen > 0 %} <!-- a href="{% rul 'chcorrect' %}" target="_blank"  --><a href="/ch_correct/" target="_blank"> 订正 </a>{% endif %}<br></font>   <br>{% for i in chlist%} {% if i in rights  %}  <div style="color:blue;display: inline-block;" align="center">✓</div>   {% elif i in errors %}   <div style="color:red; display: inline-block;" align="center">✗</div>{% else %}  <div style="color:grey;display: inline-block;" align="center">.</div>  {% endif%}  {% endfor%}  </div>
</div>
{% endblock %}

ch_test.html部分内容,代码注释如下

<br>
<form name="eqt" method="post" action="/ch_judge/"><div class="container py-5" >  {% for rec in dxt %} <div class="row" >   <div class="col-md-1"> </div><div class="col-md-10" ><!--显示题干--><a id="targ{{rec.cid}}" name="{{rec.cid}}"> {{forloop.counter}}、{{rec.ctitle|safe}}</a>  </div>   </div><div class="row" ><div class="col-md-2"> </div><div class="col-md-8" ><!--显示选项-->A. {{rec.cana|safe}} <br>B. {{rec.canb|safe}} <br>C. {{rec.canc|safe}} <br>D. {{rec.cand|safe}} <br> </div></div>  <div class="row" ><div class="col-md-7"> </div><div class="col-md-5" ><div align="center"><!--表单元素,点击后 右侧栏对应题号深色,表示已做--><label> <input type="radio" name="dxt{{rec.cid}}" value="A" onclick="haddo('nvref{{rec.cid}}')">A   </label><label> <input type="radio" name="dxt{{rec.cid}}" value="B" onclick="haddo('nvref{{rec.cid}}')">B   </label><label> <input type="radio" name="dxt{{rec.cid}}" value="C" onclick="haddo('nvref{{rec.cid}}')">C   </label><label> <input type="radio" name="dxt{{rec.cid}}" value="D" onclick="haddo('nvref{{rec.cid}}')">D   </label></div></div></div><br>{% endfor %}<div class="row" ><div class="col-md-3"> <input type="submit" value=" 提 交 "></div><div class="col-md-8" ></div></div>
</form>
<br>
<!-- 右侧提示栏,深色表示已做,白色表示没做。点击可以跳转到相应的题目 -->
<div id='infoti' class="info-div" > 共有{{ choicecount }}小题,{{choicecount|plus:2}}分</div>
<div id='nvtodo' class="nav-div">{% for i in dxt_cid_lst %}   <div class='aido' id='nvref{{i}}'   style="width:35px;height:35px;border:1px solid grey;color:gray;background:#ffffff; margin: 4px 4px 4px 4px; display: inline-block;padding:0px  0px 5px ;cursor:pointer;font-size:22px;" align="center"onclick='location.href="#{{i}}"'>{{forloop.counter}}</div>  {% endfor %} <br>
</div>

ch_judge.html部分内容,

<!--选择题 评分 --><div  class="row" ><div class="col-md-1"></div><div class="col-md-10"><table align="left" ><tr><td> <font align="center" size="5"><br/>一、选择题:(共{{25}}小题),共得分:{{dxt_stu_grade}}</font> </td><td> </td></tr>   {% for id in dxt_cid_lst %}{% with  dxt_dct|index:id as rec %}<tr><td colspan="2"><a id="targ{{forloop.counter}}" name="{{forloop.counter}}">   </a><pre>{{forloop.counter}}、{{rec.ctitle | safe}}</pre></td></tr><tr><td colspan"2">A. {{rec.cana | safe}} <br>B. {{rec.canb | safe}} <br>C. {{rec.canc | safe}} <br>D. {{rec.cand | safe}} <br>{% if rec.canswer == dxt_stu_answer|index:id %}<font color='blue'> 标准答案:{{rec.canswer }}       你的答案:{{dxt_stu_answer|index:i }}</font>{% else %}<font color='red'> 标准答案:{{rec.canswer }}       你的答案:{{dxt_stu_answer|index:id }}</font><!--错题,右侧题号显示为红色--><script> document.getElementById('nvref{{forloop.counter}}').style="width:35px;height:35px;border:1px solid red;color:white;background:#ff0000;margin:4px 4px 4px 4px; display: inline-block;padding:0px 0px 5px;cursor:pointer;font-size:22px;"  </script> {% endif %}</td></tr>{% endwith %}{% endfor %}</table>    </div><div class="col-md-1"></div></div>

过滤器使用的例子,dxt_dct|index:id用管道符`|`加过滤器及参数的形式来调用,之间不要有空格。

总感觉这样写的教程缺乏吸引力,编程特别是网站方面的教程该如何写作才能出彩呢,期望您的建议。

第五讲 Django开发选择题练习的应用相关推荐

  1. Django开发实战

    Django开发流程 参考 https://www.cnblogs.com/fwl8888/p/9345573.html 首先说明的是项目中要包含这几个文件 CHANGELOG.md 用来记录项目的变 ...

  2. Django 开发中的最佳实践之一

    为什么80%的码农都做不了架构师?>>>    Django 开发中的最佳实践之一 本文关注 Django 开发中调试的部分. 出自 Flask 项目旗下的 Werkzeug deb ...

  3. 单选选择才可以提交_第二篇:DJANGO开发产品选择表amp;调查问卷

    锅大虾:第一篇:DJANGO开发产品选择表&调查问卷​zhuanlan.zhihu.com 三.调查问卷部分 前端实现效果:首页 首页效果图 需求: 1.单项.多项选择,并且随意增加" ...

  4. html请求接口_python接口自动化测试 - 2.Django开发接口

    要测试接口,首先我们要学会开发一个简单的接口,只有你知道了如何开发,你才能更好的进行测试,才能知道具体哪里最容易出错,从而大大的提高测试的准确性以及覆盖率.所以,我们以Django为例子,开发一个简单 ...

  5. 搭建 Django 开发环境

    Hello,我是 Alex 007,一个热爱计算机编程和硬件设计的小白,为啥是007呢?因为叫 Alex 的人太多了,再加上每天007的生活,Alex 007就诞生了. Django安装 了解了什么是 ...

  6. Django开发社交类网站必备的10个第三方应用

    本文首发于我的博客 追梦人物的博客,欢迎关注. Django 的好处就是大而全,不仅内置了 ORM.表单.模板引擎.用户系统等,而且第三方应用的生态也是十分完善,开发中大部分常见的功能都能找到对应的第 ...

  7. Django开发准则与最佳实践

    最近在网易云课堂学习一门django高级实战教程,本文是学习课时14.15的一些笔记 Django开发准则与最佳实践 一.优先使用自定义用户模型 继承BaseUserManager和AbstractB ...

  8. django 开发中数据库可以怎样优化

    django 开发中数据库可以怎样优化 (1)设计表时,尽量少使用外键,因为外键约束会影响插入和删除性能: (2)使用缓存,减少对数据库的访问: (3)在 orm 框架下设置表时,能用 varchar ...

  9. Django开发中问题和报错集合

    记录django项目开发过程中的遇到的问题,导致原因和已经奏效的解决方法 常见报错UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbc in ...

最新文章

  1. 2019BATJ面试题汇总详解:MyBatis+MySQL+Spring+Redis+多线程
  2. Weblogic12C 集群实现session同步
  3. python爬虫教程网-Python爬虫全集
  4. 聚合中返回source_Java 8 中的 Streams API 详解—— Streams 的背景以及 Java 8 中的使用详解...
  5. Oracle生成指定表的列名,并前后添加select from
  6. 条款20 :宁以pass-by-reference-to-const 替换pass-by-value
  7. Adaboost方法分类新闻数据
  8. Lombok介绍、附比较好用的几种注释推荐
  9. python web 框架的flash消息_python web开发-flask中消息闪现flash的应用
  10. android虚线边框_Android实现代码画虚线边框背景效果
  11. python中如何调用或修改元组中的元素_python 元组的使用方法
  12. 【渝粤教育】国家开放大学2018年秋季 0109-21T公司财务 参考试题
  13. unity UI事件
  14. js延时函数_js自执行函数分享
  15. VS启动项目时一个奇葩问题
  16. ubuntu 显卡驱动卸载和安装
  17. 已删除的QQ好友聊天记录怎么查看
  18. matlab中的插值函数
  19. 移动办公系统 服务器地址,移动办公怎么设置服务器地址
  20. 计算机网络-应用层笔记

热门文章

  1. 金融帝国实验室(Capitalism Lab)官方正版游戏『最新销售政策』
  2. 【组件】前端js拖拽插件 VUE
  3. 计算机辅助英语教学mti,计算机辅助翻译与翻译硕士(MTI)专业建设
  4. 网页端企业微信扫码登录及其cookie问题
  5. SMC CC-Link总线单元Ex□□0 通讯位数 问题
  6. 程序员都会的五大算法之一(分治算法),恶补恶补恶补!!!
  7. 编译Android源码(2) ---- envsetup.sh文件分析
  8. Install OpenERP in TurnkeyLinux Core
  9. 【立哥】【每日一个小知识】铁扇公主和太上老君到底是什么关系?
  10. java 100以内的整数和_java计算100以内的正整数和的三种方法