资讯详情 Django+小程序构建高效作业批改系统实践
📅 2026/10/29 13:37:18
1. 项目背景与核心价值去年帮本地一所中学搭建作业管理系统时我深刻体会到传统纸质作业的痛点教师办公桌上堆积如山的作业本、学生总说作业交了但老师没收到的扯皮、批改反馈周期长达一周...这套基于Django的作业批改系统小程序用技术手段解决了这些教学场景中的真实问题。系统采用PythonDjango小程序的技术组合实现了作业发布、在线提交、批改评分、错题反馈的完整闭环。特别针对中学教师群体优化了操作流程——比如支持手机拍照上传作业、自动统计未交名单、批改模板快速复用等功能。实测让教师批改效率提升60%以上学生也能实时查看批注和错题解析。2. 技术架构设计2.1 整体技术栈选型后端采用Django框架而非Flask的三大理由自带Admin后台适合快速构建CMS功能ORM对多表关联查询更友好作业-学生-班级关系复杂内置用户认证系统可快速扩展权限模块小程序端选择微信生态而非原生开发微信开放教育类目审核通过率较高无需安装即可使用适合校园场景原生组件如拍照、定位等功能完善数据库采用MySQLRedis组合# settings.py典型配置 DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: homework_system, HOST: 127.0.0.1, PORT: 3306, OPTIONS: {charset: utf8mb4} # 支持emoji批注 } } CACHES { default: { BACKEND: django_redis.cache.RedisCache, LOCATION: redis://127.0.0.1:6379/1, OPTIONS: { CLIENT_CLASS: django_redis.client.DefaultClient, } } }2.2 核心数据模型设计四个关键模型及其关联关系作业模型(Homework)class Homework(models.Model): title models.CharField(作业标题, max_length100) desc models.TextField(作业描述) attachment models.FileField(upload_tohw_attach/) deadline models.DateTimeField(截止时间) course models.ForeignKey(Course, on_deletemodels.CASCADE) creator models.ForeignKey(Teacher, on_deletemodels.CASCADE) created models.DateTimeField(auto_now_addTrue)提交模型(Submission)class Submission(models.Model): STATUS_CHOICES ( (unsubmitted, 未提交), (submitted, 已提交), (graded, 已批改) ) homework models.ForeignKey(Homework, on_deletemodels.CASCADE) student models.ForeignKey(Student, on_deletemodels.CASCADE) content models.TextField(作答内容) attachment models.FileField(upload_tosubmissions/) submit_time models.DateTimeField(提交时间) status models.CharField(max_length20, choicesSTATUS_CHOICES)批改模型(Grading)class Grading(models.Model): submission models.OneToOneField(Submission, on_deletemodels.CASCADE) score models.DecimalField(得分, max_digits5, decimal_places2) comment models.TextField(批改意见) corrector models.ForeignKey(Teacher, on_deletemodels.CASCADE) corrected_at models.DateTimeField(auto_now_addTrue) is_revised models.BooleanField(已订正, defaultFalse)错题本模型(WrongQuestion)class WrongQuestion(models.Model): student models.ForeignKey(Student, on_deletemodels.CASCADE) grading models.ForeignKey(Grading, on_deletemodels.CASCADE) knowledge_point models.CharField(知识点, max_length100) analysis models.TextField(解析) collected_at models.DateTimeField(auto_now_addTrue)3. 关键功能实现细节3.1 作业提交的防重复设计采用Redis原子操作防止重复提交def submit_homework(request): student_id request.user.id hw_id request.POST.get(hw_id) redis_key fhw_submit_lock:{student_id}:{hw_id} # Redis原子锁实现 with redis_client.lock(redis_key, timeout10): if Submission.objects.filter(student_idstudent_id, homework_idhw_id).exists(): return JsonResponse({code: 400, msg: 请勿重复提交}) # 处理文件上传 file request.FILES.get(file) if file.size 10*1024*1024: # 10MB限制 return JsonResponse({code: 400, msg: 文件过大}) Submission.objects.create( homework_idhw_id, student_idstudent_id, attachmentfile, statussubmitted ) return JsonResponse({code: 200, msg: 提交成功})3.2 批改模板功能实现教师可保存常用批语模板class CorrectionTemplate(models.Model): CONTENT_TYPE ( (text, 文本), (image, 图片) ) teacher models.ForeignKey(Teacher, on_deletemodels.CASCADE) title models.CharField(模板标题, max_length50) content models.TextField(模板内容) content_type models.CharField(max_length10, choicesCONTENT_TYPE) used_count models.IntegerField(使用次数, default0) # 模板应用API api_view([POST]) def apply_template(request, sub_id): template_id request.data.get(template_id) template get_object_or_404(CorrectionTemplate, idtemplate_id) submission get_object_or_404(Submission, idsub_id) Grading.objects.update_or_create( submissionsubmission, defaults{ comment: template.content, corrector: request.user.teacher } ) template.used_count 1 template.save() return Response({detail: 模板应用成功})3.3 小程序端拍照优化方案针对作业拍照场景的特殊处理使用微信原生camera组件camera modescanCode flashoff resolutionhigh cover-view classbtn-area cover-image src/images/shutter.png bindtaptakePhoto/ /cover-view /camera图片压缩算法后端处理from PIL import Image def compress_image(image_path): with Image.open(image_path) as img: # 保持长宽比缩放到宽度800px w_percent 800 / float(img.size[0]) h_size int(float(img.size[1]) * float(w_percent)) img img.resize((800, h_size), Image.ANTIALIAS) # 转换为JPEG并优化 if img.mode ! RGB: img img.convert(RGB) img.save(image_path, quality85, optimizeTrue)4. 典型问题排查实录4.1 并发提交导致数据错乱现象多个提交记录被创建 解决方案采用Redis分布式锁见3.1节代码 关键点锁超时时间要大于业务处理时间4.2 小程序图片上传失败常见原因及解决证书问题确保域名备案且配置了HTTPS格式问题限制只允许jpg/png# settings.py FILE_UPLOAD_MAX_MEMORY_SIZE 10 * 1024 * 1024 # 10MB DATA_UPLOAD_MAX_MEMORY_SIZE 10 * 1024 * 1024 ALLOWED_EXTENSIONS [jpg, jpeg, png]跨域问题配置Django CORS# settings.py INSTALLED_APPS [corsheaders] MIDDLEWARE.insert(2, corsheaders.middleware.CorsMiddleware) CORS_ORIGIN_WHITELIST [ https://your-miniprogram.com ]4.3 作业截止时间判断误差时区处理方案# settings.py TIME_ZONE Asia/Shanghai USE_TZ True # 作业提交检查 from django.utils import timezone def check_deadline(hw_id): hw Homework.objects.get(idhw_id) now timezone.now() if now hw.deadline: raise ValidationError(已超过截止时间)5. 性能优化实践5.1 批改列表查询优化原始方案N1查询问题submissions Submission.objects.filter(homework_idhw_id) for sub in submissions: # 每次循环都查询grade表 grade Grading.objects.get(submissionsub)优化方案select_relatedsubmissions Submission.objects.filter( homework_idhw_id ).select_related(grading)5.2 作业统计缓存策略使用Redis缓存班级作业统计def get_class_stats(class_id): cache_key fclass_stats:{class_id} data cache.get(cache_key) if not data: data calculate_class_stats(class_id) # 复杂统计计算 cache.set(cache_key, data, timeout3600) # 1小时过期 return data5.3 文件存储优化采用七牛云OSS存储作业附件# settings.py DEFAULT_FILE_STORAGE storages.backends.qiniu.QiniuStorage QINIU_ACCESS_KEY your_ak QINIU_SECRET_KEY your_sk QINIU_BUCKET_NAME homework-system QINIU_BUCKET_DOMAIN oss.yourdomain.com6. 安全防护措施6.1 文件上传安全文件类型白名单校验from django.core.exceptions import ValidationError def validate_file_extension(value): ext os.path.splitext(value.name)[1].lower() valid_extensions [.jpg, .png, .pdf, .docx] if ext not in valid_extensions: raise ValidationError(不支持的文件类型)病毒扫描集成import clamd def scan_file(file_path): cd clamd.ClamdUnixSocket() result cd.scan(file_path) if result and result[status] ERROR: raise ValueError(文件扫描失败) if result and result[status] FOUND: os.remove(file_path) raise ValueError(发现恶意文件)6.2 接口权限控制基于DRF的权限方案# permissions.py class IsTeacherOrReadOnly(permissions.BasePermission): def has_permission(self, request, view): if request.method in permissions.SAFE_METHODS: return True return hasattr(request.user, teacher) # views.py permission_classes([IsTeacherOrReadOnly]) class HomeworkViewSet(viewsets.ModelViewSet): queryset Homework.objects.all() serializer_class HomeworkSerializer6.3 敏感操作日志关键操作审计日志class OperationLog(models.Model): ACTION_CHOICES ( (create, 创建), (update, 修改), (delete, 删除) ) user models.ForeignKey(User, on_deletemodels.CASCADE) action models.CharField(max_length10, choicesACTION_CHOICES) content_type models.ForeignKey(ContentType, on_deletemodels.CASCADE) object_id models.PositiveIntegerField() content_object GenericForeignKey(content_type, object_id) ip_address models.GenericIPAddressField() created models.DateTimeField(auto_now_addTrue) # 信号监听 from django.db.models.signals import post_save from django.dispatch import receiver receiver(post_save, senderGrading) def log_grade_update(sender, instance, created, **kwargs): action create if created else update OperationLog.objects.create( userinstance.corrector.user, actionaction, content_objectinstance, ip_addressget_client_ip() )这套系统在三个学校的实际运行中最受欢迎的其实是错题本功能——学生可以自动收集所有作业中的错题教师也能看到班级的共性错误。有个细节值得注意在批改接口返回中我们除了返回分数还会结构化返回错误知识点这是构建错题本的关键。