Python入门自学进阶-Web框架——32、上课、作业流程开发

news2025/4/8 3:16:09

对学员上课、作业进行管理。首先对几个表,即model用途进行阐述:

课程表存放要开什么课,有了课程表,就要有班级,如开了Python入门课程,再根据学员人数,组成班级,如Python入门课程一班、二班等,有了班级就可以开课了,上课老师需要在上课记录表中记录给哪个班级上了第几天课,老师上课需要点名,在学习记录表中对学生点名。

这里主要是学习记录的操作,老师点名时,不能一个学生一个学生的添加,最好就是批量生成所有学生的记录,默认都是已签到,老师点名时不需要在添加学生,只需修改签到状态,及课后成绩修改等。

学习记录:

使用Action来批量生成。

在Django的admin.py中,做如下配置(基本框架的形成):

class CourseRecordAdmin(admin.ModelAdmin):
    list_display = ['from_class','day_num','teacher','has_homework','homework_title']
    def initialize_studyrecords(self,req,queryset):
        print('init studyrecords')
    initialize_studyrecords.short_description = "批量初始化"   # 在action中显示的名字
    actions = ['initialize_studyrecords',]

admin.site.register(models.CourseRecord,CourseRecordAdmin)

配置后的结果:

此时,选中一条上课记录,在Action中选择批量初始化,就可以在学习记录表中生成这节课的所有学员的学习记录。框架出来后,就要对具体的函数,即initialize_studyrecords实现功能。

首先要查询出有哪些学员关联了这节课。查询这个班的学员就可以了。同时,批量生成时,只能选择一节课,因为一个讲师不能同时上多节课,在函数中要先判断是否只选择了一条记录。

Action函数initialize_studyrecords的具体实现:

    def initialize_studyrecords(self,req,queryset):
        if len(queryset)>1:
            return HttpResponse("只能选择一节课 ")
        print(queryset[0].from_class.enrollment_set.all())  # 先打印一下学员明细
        # for enroll_obj in queryset[0].from_class.enrollment_set.all():  # 下面是一个普通实现,一条记录一条记录的插入,效率低
            # # models.StudyRecord.objects.create(  # 使用create时,如果在批量生成前,做了一条学习记录,再批量创建时会报"Duplicate entry“错误,不唯一了
            # models.StudyRecord.objects.get_or_create( # 使用get_or_create,可以避免唯一错误
            #     student= enroll_obj,
            #     course_record= queryset[0],
            #     attendance= 0,
            #     score= 0,
            # )
            # ====上面一条一条插入效率不高,使用下面的事务批量插入,即使用bulk_create
        studyrecord_obj_list = []
        for enroll_obj in queryset[0].from_class.enrollment_set.all():
            studyrecord_obj_list.append(models.StudyRecord(
                student=enroll_obj,
                course_record=queryset[0],
                attendance=0,
                score=0,
            ))
        try:
            models.StudyRecord.objects.bulk_create(studyrecord_obj_list)
        except Exception as e:
            return HttpResponse("批量创建失败,请检查是否有手动创建学习记录或已经批量生成")
        return redirect("/admin/plcrm/studyrecord/?course_record__id__exact=%s" % queryset[0].id) # 带参数,可以显示批量创建的这节课的相关学习记录,否则显示所有的学习记录
    

上面是在Django的admin中实现的批量处理,现在将此功能添加到我们自己的admin中,即mytestapp_admin中

class CourseRecordAdmin(BaseAdmin):
    list_display = ['from_class','day_num','teacher','has_homework','homework_title']
    def initialize_studyrecords(self,req,queryset):
        if len(queryset)>1:
            print("leng >1")
            return HttpResponse("只能选择一节课 ")
        # for enroll_obj in queryset[0].from_class.enrollment_set.all():
            # # models.StudyRecord.objects.create(  # 使用create时,如果在批量生成前,做了一条学习记录,再批量创建时会报"Duplicate entry“错误,不唯一了
            # models.StudyRecord.objects.get_or_create( # 使用get_or_create,可以避免唯一错误
            #     student= enroll_obj,
            #     course_record= queryset[0],
            #     attendance= 0,
            #     score= 0,
            # )
            # ====上面一条一条插入效率不高,使用下面的事务批量插入,即使用bulk_create
        studyrecord_obj_list = []
        for enroll_obj in queryset[0].from_class.enrollment_set.all():
            studyrecord_obj_list.append(models.StudyRecord(
                student=enroll_obj,
                course_record=queryset[0],
                attendance=0,
                score=0,
            ))
        try:
            models.StudyRecord.objects.bulk_create(studyrecord_obj_list)
        except Exception as e:
            return HttpResponse("批量创建失败,请检查是否有手动创建学习记录或已经批量生成")
        return redirect("/mytestapp/plcrm/studyrecord/?course_record=%s" % queryset[0].id) # 带参数,可以显示批量创建的这节课的相关学习记录,否则显示所有的学习记录
    initialize_studyrecords.display_name = "批量初始化"
    actions = ['initialize_studyrecords',]

在具体调用action函数的程序中(views函数),调用的片段:

    if req.method == "POST":
        if not admin_class.readonly_table:
            select_ids = req.POST.get('selected_ids')
            select_ids = select_ids.split(',')
            actions = req.POST.get('myaction')
            action_obj = getattr(admin_class,actions)
            models_objs = admin_class.model.objects.filter(id__in=select_ids)

            # action_obj(admin_class,req,models_objs)  # 执行action函数,原来程序到这里就结束了

            return_httpresponse_obj = action_obj(admin_class, req, models_objs)
            print("======>>>",return_httpresponse_obj)
            return return_httpresponse_obj
            # 在编写action实现批量生成学习记录时,修改为上面两句,因为
        else:
            error = 'readonlyerror:Table is readonly, cannot be deleted!'

这里有一个很重要的知识点:就是作为views函数,即在路由项中定义的对应函数,必须返回一个HttpResponse,否则就会出错;在views函数中调用其他的函数,其他函数含有return HttpResponse(),只是返回一个HttpResponse对象,不会真正的返回给前端,只有views函数的return才能返回前端。我的视图函数中在处理action时,一开始只是调用了action函数,即只执行了action_obj(admin_class,req,models_objs)这一句,我以为action函数,这里指initialize_studyrecords中最后执行的是return HttpResponse(“失败”),views函数也就返回了响应,实际上不会,action_obj(admin_class,req,models_objs)这一句只是获得了一个HttpResponse对象,并且没有用变量保存,也就是直接丢弃了,然后views函数会接着往下运行,然后在前端返回的是views函数最后返回的return页。所以要捕获action函数返回的值,即HttpResponse或HttpResponseRedirect对象,在return

这样,我们的自定义app就包含了批量初始化学习记录的功能。

学员课程流程开发:主要是学生账号设置和学生课程管理,主要是作业管理,提交作业。

在客户报名成功成为学员后,给学员创建一个账号,并关联上客户信息,在学员登录后,根据相应的客户信息,找到学员所报课程相关信息,并给出课程进度、课程成绩等信息,然后再给出一个链接,对所报课程进行作业管理。

修改账户表,增加一个客户信息的关联字段,然后创建账号:

学员角色以及角色对应的菜单项:

学员登录后的主页:

点击学生课程菜单,进入课程管理页:

在项目的urls中增加学员登录的路由项以及学员管理应用的urls

path('',views.index,name="stu_index"),

path('student/',include("student.urls")),

学员课程菜单对应的实现:

student.urls中的路由项:path('student_class/',views.student_class,name="student_class"),

视图函数student_class:

def student_class(req):

    return  render(req,'student/student_class.html')

前端页面student_class.html:

{% extends "base.html" %}
{% load stu_tags %}
{% block mybody %}
<body>
    
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
..页头部分,略
</nav>

<div class="container-fluid">
  <div class="row">
    <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
      <div class="sidebar-sticky pt-3">
      <div style="height: 40px;background-color: black"></div>
        <ul class="nav flex-column">
          {% for role in request.user.roles.select_related %}
            <!--   {{ role }}    测试role的值,这里应该是roles类的__str__()方法的值 -->
            {% for menu in role.menus.all %}
                <li class="nav-item">
                <a class="nav-link active" href="{%  url menu.url_name %}">
              <span data-feather="home"></span>
                    {{ menu.name }} <span class="sr-only">(current)</span>
            </a>
          </li>
            {% endfor %}
          {% endfor %}
        </ul>
      </div>
    </nav>

    <main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
      <div class="card">
          <div class="card-header h4">
            学生{{ request.user.name }}课程信息
          </div>
          <div class="card-body">
            <table class="table table-striped table-responsive">
                <thead>
                    <tr>
                        <th>课程名称</th>
                        <th>班级</th>
                        <th>开课日期</th>
                        <th>结业日期</th>
                        <th>课程进度</th>
                        <th>我的成绩</th>
                        <th>作业管理</th>
                    </tr>
                </thead>
                <tbody>
                    {% for enroll_obj in request.user.stu_account.enrollment_set.all %}
                    <tr>
                        <td>{{ enroll_obj.enrolled_class.course }}</td>
                        <td>s{{ enroll_obj.enrolled_class.semester }}</td>
                        <td>{{ enroll_obj.enrolled_class.start_date }}</td>
                        <td>{{ enroll_obj.enrolled_class.end_date }}</td>
                        <td>已上{{ enroll_obj.enrolled_class.courserecord_set.all.count }}节</td>
                        <td>{% get_score enroll_obj request.user.stu_account as score_date %}{{ score_date.score__sum }}</td>
                        <td><a href="#">作业管理</a></td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
          </div>
        </div>
    </main>
  </div>
</div>
。。。
  </body>
{% endblock %}

学员的信息,通过账号关联的客户信息,在通过关联的报名信息、班级信息、上课信息等,可以正查或反查出各种信息,再通过聚合函数统计等得出各种信息。

学员成绩查询时使用了自定义标签get_score enroll_obj:

@register.simple_tag
def get_score(enroll_obj,customer_obj):
    study_records = enroll_obj.studyrecord_set.\
        filter(course_record__from_class_id=enroll_obj.enrolled_class.id)
    for record  in study_records:
        print(record)
    return study_records.aggregate(Sum("score"))

作业管理,点击作业管理后,进入显示某一班级的所有上课记录的页面:

显示此学员此班级的上课记录信息,在这里也有个作业管理,用于学员上传作业,此页面:

这里作业提交管理使用dropzone插件,完成作业文件上传,文件要使用zip格式。

某一班级学习管理:path('studyrecords/<int:enroll_obj_id>/',views.studyrecords,name='studyrecords'),

视图函数studyrecords:

def studyrecords(req,enroll_obj_id):
    enroll_obj =models.Enrollment.objects.get(id=enroll_obj_id)

    return render(req,'student/studyrecords.html',{'enroll_obj':enroll_obj,})

前端页面/studyrecords.html:

<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
      <div class="card">
          <div class="card-header h4">
            学生:{{ request.user.name }} --> {{ enroll_obj.enrolled_class.course }} 学习信息
          </div>
          <div class="card-body">
            <table class="table table-striped table-responsive">
                <thead>
                    <tr>
                        <th>课程节次</th>
                        <th>上课日期</th>
                        <th>是否有作业</th>
                        <th>作业标题</th>
                        <th>签到状态</th>
                        <th>成绩</th>
                        <th>作业管理</th>
                    </tr>
                </thead>
                <tbody>
                    {% for sturecord in enroll_obj.studyrecord_set.all %}
                    <tr>
                        <td>{{ sturecord.course_record.day_num }}</td>
                        <td>{{ sturecord.course_record.date }}</td>
                        <td>{{ sturecord.course_record.has_homework }}</td>
                        <td>{{ sturecord.course_record.homework_title }}</td>
                        <td>{{ sturecord.get_attendance_display }}</td>
                        <td>{{ sturecord.get_score_display }}</td>
                        <td><a href="{% url 'homework_detail' sturecord.id %}">作业管理</a></td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
          </div>
        </div>
    </main>

具体谋一节课的作业管理:

path('homework_detail/<int:sturecord_id>/',views.homework_detail,name='homework_detail'),

视图函数homework_detail:

def homework_detail(req,sturecord_id):
    sturecord_obj = models.StudyRecord.objects.get(id=sturecord_id)
    if req.method == "POST":
    # class_id/course_record_id/studyrecord_id
        homework_path = "{base_dir}/{class_id}/{course_record_id}/{studyrecord_id}/".format(
            base_dir = settings.HOMEWORK_DATA,
            class_id = sturecord_obj.student.enrolled_class_id,
            course_record_id = sturecord_obj.course_record_id,
            studyrecord_id = sturecord_obj.id,
        )
        if not os.path.isdir(homework_path):
            os.makedirs(homework_path,exist_ok=True)

        for k,file_obj in req.FILES.items():
            with open("%s/%s" %(homework_path,file_obj.name),"wb") as f:
                for chunk in file_obj.chunks():
                    f.write(chunk)
        return HttpResponse(json.dumps({"status":0,"msg":"file upload success"}))
    return render(req,"student/homework_detail.html",{'sturecord_obj':sturecord_obj,})

前端页面homework_detail.html:

<main role="main" class="col-md-9 ml-sm-auto col-lg-10 px-md-4">
      <div class="card">
          <div class="card-header h4">
            {{ sturecord_obj.course_record.from_class.course }} 第{{ sturecord_obj.course_record.day_num }}节课
          </div>
          <div class="card-body">
            <h5>作业标题:{{ sturecord_obj.course_record.homework_title }}</h5>
            <h5>作业详情:</h5><pre><P class="bg-light col-lg-10 border pt-2 pb-2">{{ sturecord_obj.course_record.homework_content }}</P></pre>
            <h5>老师评语:</h5><P class="bg-light col-lg-10 border pt-2 pb-2">{{ sturecord_obj.memo }}</P>
            <h5>本节成绩:{{ sturecord_obj.score }}</h5>
            <hr/>
            <h5>作业提交管理:</h5>
            <div class="col-lg-10">
              <form id="mydropz" action={{ request.path }} class="dropzone">
              <div class="fallback">
                <input name="file" type="file" multiple />
              </div>
            </form>
            </div>
          </div>
        </div>
    </main>

  </div>
</div>

    <script>
        if ($("form#mydropz").length !=0)  {

        Dropzone.options.mydropz = false;
        var myDropzone = new Dropzone("form#mydropz",{
            headers:{'X-CSRFToken':'{{csrf_token}}'},
            dictDefaultMessage:"将打包的作业拖至此框",
            maxFiles: 1,
            accept:function (file,done) {
                if( !file.name.endsWith(".zip")){
                    alert("只能传zip文件");
                    done("文件未上传");
                    myDropzone.reset();

                }  else {done();}
            }
    });
    }
    </script>

这里使用了dropzone插件,下面的js脚本用于dropzone的初始化和处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/363345.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

报考浙大MBA项目的基本常识信息

一、项目简介 以培养具有国际视野、创新创业精神、卓越领导能力和高度社会责任感的中高级管理人才和创业型人才为己任。通过对引领时代发展的经典管理思想和前沿管理理念的传授&#xff0c;以及对推动行业健康发展的企业管理实践的研讨&#xff0c;来培养和提升学员的职业意…

一个测试工程师的7年感悟 ---- 致在一路独行的你(别放弃)

前言 不知不觉在软件测试行业&#xff0c;摸爬滚打了7年之久。这一路上也留下了许许多多令我难以忘记的故事。有刚入行时的迷茫&#xff0c;有学习技术路上踩过的坑&#xff0c;有做项目连夜敲代码的悲情也有迎来项目成功上线的欢愉&#xff0c;有太多太多值得铭记的瞬间&…

JUC-day02

JUC-day02 集合的线程安全callable和futureJUC三个工具类(练习)读写锁: 共享锁 独占锁(练习)AQS: 实现原理(核心方法)CAS: 原理–>可见性关键字 1 集合的线程安全(重点) 1.1 集合操作Demo NotSafeDemo public static void main(String[] args) {List list new ArrayLis…

Java集合(二)---Map

1.什么是Hash算法哈希算法是指把任意长度的二进制映射为固定长度的较小的二进制值&#xff0c;这个较小的二进制值叫做哈希值static final int hash(Object key) {int h;return (key null) ? 0 : (h key.hashCode()) ^ (h >>> 16);}以上是HashMap中的hash算法代码2…

三天吃透Spring面试八股文(最新整理)

本文已经收录到Github仓库&#xff0c;该仓库包含计算机基础、Java基础、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等核心知识点&#xff0c;欢迎star~ Github地址&#xff1a;https://github.com/…

【音视频处理】为什么MP3不是无损音乐?音频参数详解,码率、采样率、音频帧、位深度、声道、编码格式的关系

大家好&#xff0c;欢迎来到停止重构的频道。上期我们讨论了视频的相关概念&#xff0c;本期我们讨论音频的相关概念。包括采样率、码率、单双声道、音频帧、编码格式等概念。这里先抛出一个关于无损音频的问题。为什么48KHz采样率的.mp3不是无损音乐 &#xff0c;而48KHz采样率…

95后刚毕业2、3年就年薪50W,才发现,打败我们的不是年龄····

一刷朋友圈&#xff0c;一读公众号&#xff0c;一打开微博&#xff0c;甚至是一和朋友聊天&#xff0c;这些让人焦虑的话题总会铺天盖地的袭来&#xff1a; Ta刚毕业半年&#xff0c;就升职加薪当上了测试主管 &#xff08;同样是一天24小时&#xff0c;为什么同龄人正在抛弃…

【Linux】编辑器——vim(最小集+指令集+自动化配置)

目录 1.vim最小集 1.1 vim的三种模式 1.2 vim的基本操作 2.vim指令集 2.1 命令模式指令集 移动光标 删除文字 复制 替换 撤销上一次操作 更改 跳至指定的行 2.2 底行模式指令集 列出行号 跳到文件中的某一行 查找字符 保存文件 多文件操作 3.如何配置vim 配…

网络编程之TCP 的介绍

TCP 的介绍学习目标能够说出TCP 的特点1. 网络应用程序之间的通信流程之前我们学习了 IP 地址和端口号&#xff0c;通过 IP 地址能够找到对应的设备&#xff0c;然后再通过端口号找到对应的端口&#xff0c;再通过端口把数据传输给应用程序&#xff0c;这里要注意&#xff0c;数…

科技 “新贵”ChatGPT 缘何 “昙花一现” ,仅低代码风靡至今

恍惚之间&#xff0c;ChatGPT红遍全网&#xff0c;元宇宙沉入深海…… 在科技圈&#xff0c;见证了太多“昙花一现”&#xff0c;“新贵” ChatGPT 的爆火几乎复制了元宇宙的路径&#xff0c;它会步元宇宙的后尘&#xff0c;成为下一个沉入深海的工具吗&#xff1f; 不可否认的…

小程序开发注意点

1.组件样式隔离注意点 2.methods方法 3.自定义组件的properties参数 4.自定义组件的事件监听 5.纯数据字段 6.插槽 单个插槽 启用多插槽 使用多个插槽 7.属性绑定实现父传子功能 例如在这里有一个组件为<one></one>&#xff0c;那么可以在组件当中传入参数 &l…

iOS上架及证书最新创建流程

目前使用uniapp框架开发app&#xff0c;大大节省了我们兼容多端应用的工作量和人手&#xff0c;所以目前非常缺乏ios上架和证书创建流程流程的文档假如你没有任何的打包或上架经验&#xff0c;参考本文有很大的收益。通常申请ios证书和上架ipa应用&#xff0c;是需要MAC电脑的&…

干货复试详细教程——从联系导师→自我介绍的复试教程

文章目录联系导师联系之前的准备联系导师注意自我介绍教育技术领域通用的复试准备其他补充联系导师 确定出分和自己能进复试以后联系。 分两类 科研技能型 低调&#xff0c;如实介绍&#xff0c;不吹不水。就算你很牛啥都会手握核心期刊论文也不太狂 学霸高分型 不要自卑&…

审计syslog设备活动

从交换机到路由器&#xff0c;几乎所有网络设备都会生成syslog。因为您的网络中有大量生成syslog的设备&#xff0c;所以审计过程&#xff08;包括跟踪、监控和分析所有syslog&#xff09;需要花费大量时间和精力。但是&#xff0c;无论这些任务需要多少精力去完成&#xff0c;…

Java:Java与Python — 编码大战

Java和Python是目前市场上最热门的两种编程语言&#xff0c;因为它们具有通用性、高效性和自动化能力。两种语言都有各自的优点和缺点&#xff0c;但主要区别在于Java 是静态类型的&#xff0c;Python是动态类型的。它们有相似之处&#xff0c;因为它们都采用了“一切都是对象”…

3、Maven安装

前言&#xff1a;工具下载地址阿里云盘&#xff1a;Maven&#xff1a;https://www.aliyundrive.com/s/SgHKjQ5doSp提取码: ml40一、什么是maven?Apache Maven是个项目管理和自动构建工具&#xff0c;基于项目对象模型&#xff08;POM&#xff09;的概念。作用&#xff1a;完成…

小白都能看懂的C语言入门教程

文章目录C语言入门教程1. 第一个C语言程序HelloWorld2. C语言的数据类型3. 常量变量的使用4. 自定义标识符#define5. 枚举的使用6. 字符串和转义字符7. 判断和循环8. 函数9. 数组的使用10. 操作符的使用11. 结构体12. 指针的简单使用C语言入门教程 1. 第一个C语言程序HelloWor…

Could not find resource jdbc.properties问题的解决

以如下开头的内容&#xff1a; Exception in thread "main" org.apache.ibatis.exceptions.PersistenceException: ### Error building SqlSession. ### The error may exist in SQL Mapper Configuration 出现以上问题是没有在src/main/resources下创建jdbc.prop…

IDEA怎么自动生成serialVersionUID

序列化和反序列化Java是面向对象的语言&#xff0c;与其他语言进行交互&#xff08;比如与前端js进行http通信&#xff09;&#xff0c;需要把对象转化成一种通用的格式比如json&#xff08;前端显然不认识Java对象&#xff09;&#xff0c;从对象到json字符串的转换&#xff0…

CF707C Pythagorean Triples 题解

CF707C Pythagorean Triples 题解题目链接字面描述题面翻译题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1样例 #2样例输入 #2样例输出 #2样例 #3样例输入 #3样例输出 #3样例 #4样例输入 #4样例输出 #4样例 #5样例输入 #5样例输出 #5提示思路代码实现题目 链接 http…