第五讲 Django开发选择题练习的应用

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

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

来看一个 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*100
    progressrate = r_e_len/choiceset_count*100
    del 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=25
    youch = str(yourchoice["zhfan"])
    #选择卓帆 15 套中的某一套选择题练习
    dxt = Choicetimu.objects.filter(Q( cbigitem='卓帆' ) & Q(  csmallitem = youch) )
    title = "卓帆选择题测试第"+ youch  +"套"

#视图函数 ch_correct,订正题目的选择
curuser = request.user
 choicecount=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_name
        self.var_value = var_value

    def render(self, context):
        try:
            value = template.Variable(self.var_value).resolve(context)
        except template.VariableDoesNotExist:
            value = ""
        context[self.var_name] = value
        return 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 部分内容,

选择题index界面

{% 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用管道符`|`加过滤器及参数的形式来调用,之间不要有空格。

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 选择题的题目可能很多,我将从我的理解角度回答一个可能的django运维开发笔试选择题。 题目:在Django项目中,数据库操作的正常流程是什么? 答案: 在Django项目中,数据库操作的正常流程如下: 1.定义模型(Model):首先,在Django中,我们需要定义模型类来描述数据库中的表结构。模型类定义在`models.py`中,使用Django提供的字段类型来定义表中的字段,并且可以设置字段的属性和约束等。 2.生成迁移脚本(Migration):在模型类定义完成后,我们需要通过运行`python manage.py makemigrations`命令来生成迁移脚本,用于记录数据库结构的变化。迁移脚本位于`migrations`目录下。 3.执行迁移(Migration):我们需要运行`python manage.py migrate`命令来执行迁移脚本,将模型类的定义映射到数据库中对应的表结构。这样,数据库就会创建或更新相应的表结构。 4.使用模型进行数据库操作:在数据库迁移完成后,我们可以在视图函数中使用模型类进行数据库的增删改查操作。Django提供了ORM(对象关系映射)工具,通过操作模型类的对象来实现对数据库的操作。可以使用模型类的对象新增、查询、修改或删除数据库中的记录。 5.数据操作完成后,我们可以根据需要在视图函数中进行相应的响应处理,最后返回给用户。 总结: 通过以上流程,我们可以在Django项目中进行数据库的正常操作。首先定义模型类来描述数据库表结构,然后通过迁移脚本生成和执行将模型映射到数据库的操作,最后在视图函数中使用模型类的对象进行数据库操作。这样就能够完成对数据库的增删改查操作,并返回响应结果给用户。 ### 回答2: 作为django运维开发,我可以回答这个选择题目。以下是我的回答: 1. django的settings.py文件是用来做什么的? settings.py文件是用于配置Django项目的核心设置的。它包含了数据库连接、静态文件路径、中间件、应用、国际化等项目必要的设置项。 2. 在django模板中,如何使用静态文件? 在django模板中,可以通过使用“{% static '文件路径' %}”的语法来使用静态文件。需要确保在settings.py文件中设置了STATIC_URL和STATICFILES_DIRS来指定静态文件的路径。 3. 如何在Django中实现用户认证功能? Django已经提供了内置的用户认证功能。可以使用“django.contrib.auth”模块来实现用户的注册、登录、注销等功能。同时,可以使用装饰器来限制只有认证过的用户才能访问某些视图函数或页面。 4. 如何创建一个Django项目? 可以通过在命令行中执行“django-admin startproject 项目名”命令来创建一个Django项目。然后通过执行“python manage.py runserver”命令来运行项目。 5. 如何在Django中使用数据库查询? Django中使用ORM(Object-relational mapper)来实现数据库查询。可以通过定义模型类,并使用该模型类的对象来进行数据库的增删改查操作。ORM提供了灵活的查询API,例如filter、get、save等方法来执行各种数据库操作。 以上是对这些选择题的简要回答。作为django运维开发,我们需要熟悉django的配置、模板、认证、项目创建以及数据库查询等方面的知识,以便有效地管理和开发Django项目。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值