)
简介基于Python Django、MySQL与HTML技术栈构建的学生成绩管理系统是一套面向Web开发初学者、课程设计与毕业设计场景的完整项目能够帮助学习者快速了解Django项目从结构搭建到功能落地的过程。压缩包共373个文件大小约2.58MB核心包含Python源码、HTML页面模板、JavaScript交互脚本、CSS/LESS/SCSS样式文件、数据库SQL脚本和安装说明文档前后端分层清晰便于直接部署和二次扩展。系统内置超级管理员、学校管理员和成绩录入测试账号覆盖创建学校、管理年级班级、维护学生名单、在线录入成绩与统计等功能且通过角色权限区分可操作范围。对于学习者而言可结合源码深入理解Django的MTV分层、ORM数据查询、模板渲染和权限设计随包提供的安装教程也能减少环境配置阻力无论是快速部署还是改造升级都具备参考价值。当前已有827人学习/下载适合需要完整可运行项目作为参考的开发者。1. 用浏览器打开的成绩单为什么学生成绩管理系统值得自己搭很多学校还在用 Excel 管理成绩一个班一个文件合班排名靠手工复制改一次分要把文件重新传一轮。用 Python Django MySQL HTML 这套组合搭学生成绩管理系统等于把成绩管理搬进浏览器——录入、修改、查询、统计都在同一个后台完成打开页面就能操作不用给每台电脑装桌面软件。对开发者来说这是入门 Web 开发最典型的练手场景Django 负责模型和业务逻辑MySQL 负责持久化存储HTML 模板负责展示四者各司其职做完之后对整条数据流会有直观认知。标题里特意写了「含安装教程」说明真正的门槛不在写业务代码而在把 Python、Django、MySQL 三个环境弄成能协作的状态——本节就从这里切入先立住理论再带你复现一个能跑的成绩管理项目。2. 环境准备与安装Python、Django、MySQL 先在本机跑通2.1 版本选型先定版本再动手能避开一半报错常见做法是先确认 Python、Django、MySQL 三者的版本兼容关系再开始安装。以目前主流的组合为例Python 3.10 或 3.11 配合 Django 4.2 LTSMySQL 8.0 及以上。Django 4.2 是长期支持版本官方维护周期到 2026 年社区资料最全遇到报错基本都能搜到案例。MySQL 用 8.0 的原因是它默认字符集是 utf8mb4存中文成绩单姓名不会出现乱码早期 5.7 版本则需要手动指定。组件推荐版本说明Python3.10 / 3.11不要用 3.12 以下的老版本与 Django 4.2 组合避免第三方驱动不兼容Django4.2 LTS自带 admin 后台ORM 支持 annotate 聚合查询适合成绩统计MySQL8.0默认 utf8mb4支持窗口函数后续做排名统计更方便连接驱动pymysql 或 mysqlclientWindows 上 pymysql 更省事Linux 上推荐 mysqlclient提示如果你的电脑已经装了 MySQL 5.7暂时不想升级那么建库时必须显式指定CHARACTER SET utf8mb4否则写入中文成绩单会出现Incorrect string value错误。2.2 Python 与 Django 安装一条命令验证是否装好Django 不是独立软件它是以 Python 第三方库的形式安装的。用pip安装即可安装后通过python -m django --version验证版本号。如果同时装了 Python 2 和 Python 3务必使用python3和pip3前缀避免装错解释器。# 安装 Django 4.2 LTS pip install django4.2 # 验证是否安装成功 python -m django --version逻辑说明python -m django是官方推荐的验证方式它明确指定用当前 python 解释器去加载 django 模块比直接敲django-admin --version更能避免多版本冲突。安装后不要急着写代码先执行一次django-admin startproject score_system .创建项目骨架再执行python manage.py runserver浏览器访问 127.0.0.1:8000 能看到 Django 默认欢迎页就说明 Web 框架层已经通了。2.3 MySQL 安装配置与建库字符集和认证方式是关键MySQL 安装教程网上版本很多核心差距在初始化后的配置。Windows 用 MySQL Installer 按默认选项安装即可安装过程中记得选「Server only」root 密码设置成自己好记的字符串。安装完成后需要手动创建一个数据库给 Django 用这一步在命令行或 MySQL Workbench 里操作都行。-- 创建数据库指定字符集 CREATE DATABASE score_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; -- 创建专用账号避免直接用 root 连应用 CREATE USER score_userlocalhost IDENTIFIED BY your_password_123; -- 授权 GRANT ALL PRIVILEGES ON score_db.* TO score_userlocalhost; -- 刷新权限 FLUSH PRIVILEGES;参数说明utf8mb4_unicode_ci是排序规则它对中文和英文字母的排序比较合理score_user是应用专用的低权限账号好处是即使项目源码泄露别人也拿不到 root 权限。这里有个容易忽略的点——MySQL 8.0 默认的认证插件是caching_sha2_password老版本的 pymysql 不支持所以要么把 pymysql 升级到 1.1.0 以上要么在创建用户时指定IDENTIFIED WITH mysql_native_password BY 密码。2.4 配置 settings.py 连接 MySQLDjango 接入数据库的必经步骤Django 默认配置的是 SQLite切换 MySQL 需要改settings.py里的DATABASES配置并在项目__init__.py里声明使用 pymysql 冒充 MySQLdb 驱动。# score_system/__init__.py import pymysql pymysql.install_as_MySQLdb()# settings.py DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: score_db, USER: score_user, PASSWORD: your_password_123, HOST: 127.0.0.1, PORT: 3306, OPTIONS: { charset: utf8mb4, init_command: SET sql_modeSTRICT_TRANS_TABLES, }, } }参数说明ENGINE是驱动引擎入口Django 内置了 mysql 后端init_command里的 sql_mode 建议保持 STRICT_TRANS_TABLES它会让非法数据在写入时报错而不是被静默截断对成绩这种敏感数据尤其重要。改完配置后执行python manage.py migrate看是否能生成内置表不报错就说明 Django 和 MySQL 的连接通道已经完全打通。3. 数据模型与 Django 后台把成绩表设计成三个模型3.1 创建 app 与模型字段学生、课程、成绩各有各的归属先用python manage.py startapp grades创建名为grades的应用然后打开models.py设计数据模型。常见的做法是把成绩单拆成三个模型Student 存学生基本信息Course 存课程信息Score 存成绩并关联学生和课程。拆开的理由很简单——同一个学生有多门课成绩同一门课有多个学生成绩表是典型的关联表。from django.db import models class Student(models.Model): 学生模型 student_no models.CharField(学号, max_length20, uniqueTrue) name models.CharField(姓名, max_length50) gender models.CharField(性别, max_length10, choices[(男, 男), (女, 女)]) class_name models.CharField(班级, max_length50) created_at models.DateTimeField(创建时间, auto_now_addTrue) def __str__(self): return f{self.student_no} {self.name} class Course(models.Model): 课程模型 course_no models.CharField(课程编号, max_length20, uniqueTrue) course_name models.CharField(课程名称, max_length100) credit models.FloatField(学分, default2.0) def __str__(self): return self.course_name class Score(models.Model): 成绩模型学生与课程的关联表 student models.ForeignKey(Student, on_deletemodels.CASCADE, verbose_name学生) course models.ForeignKey(Course, on_deletemodels.CASCADE, verbose_name课程) score models.DecimalField(成绩, max_digits5, decimal_places2) exam_date models.DateField(考试日期, nullTrue, blankTrue) class Meta: # 联合唯一同一学生同一门课只能有一条成绩 unique_together (student, course) def __str__(self): return f{self.student.name} - {self.course.course_name} - {self.score}字段设计说明student_no设置uniqueTrue是硬约束防止学号重复录入Score模型里的ForeignKey是成绩与实体之间的绑定关系on_deletemodels.CASCADE表示学生被删除时其成绩记录一并删除这符合成绩管理的直觉——没有学生的成绩没有存在意义。DecimalField而不是FloatField存成绩避免浮点数精度问题导致 89.99 显示成 89.99000001。3.2 迁移数据库与注册 admin让后台能直接看到表模型定义完毕执行迁移命令让 Django 把模型翻译成 MySQL 的 CREATE TABLE 语句。然后在admin.py注册模型就可以在 Django 自带的 admin 后台直接增删改查数据。python manage.py makemigrations grades python manage.py migrate# grades/admin.py from django.contrib import admin from .models import Student, Course, Score admin.register(Student) class StudentAdmin(admin.ModelAdmin): list_display (student_no, name, gender, class_name) search_fields (student_no, name) admin.register(Course) class CourseAdmin(admin.ModelAdmin): list_display (course_no, course_name, credit) admin.register(Score) class ScoreAdmin(admin.ModelAdmin): list_display (student, course, score, exam_date) list_filter (course, exam_date)list_display控制了后台列表页显示的列search_fields提供搜索框list_filter让管理员可以按课程和考试日期筛选成绩。注册完以后启动服务访问 127.0.0.1:8000/admin 输入超级管理员账号就能看到三张表的入口。注意创建超级管理员是硬需求执行python manage.py createsuperuser按提示输入用户名、邮箱、密码否则 admin 后台无法登录。4. 视图 模板实现成绩录入、查询与统计4.1 URL 路由规划从页面到视图的映射关系成绩管理系统的页面一般包含成绩列表页、成绩录入页、成绩编辑页。URL 的设计遵循资源化思路/scores/是列表和录入/scores/id/edit/是编辑。打开urls.py将路由指向views.py里对应的函数。# grades/urls.py from django.urls import path from . import views app_name grades urlpatterns [ path(scores/, views.score_list, namescore_list), path(scores/add/, views.score_add, namescore_add), path(scores/int:pk/edit/, views.score_edit, namescore_edit), path(scores/statistics/, views.score_statistics, namescore_statistics), ]参数说明int:pk是 Django 2.0 引入的 path converter它限制了 URL 中的 pk 必须是整数如果写abc直接返回 404比老式的(\d)正则匹配更安全。app_name是命名空间模板里用{% url grades:score_add %}引用这个 URL即使以后路径变了模板不用改。4.2 成绩录入与列表查询视图逻辑的分层写法视图层按职能拆成三个函数录入、编辑、列表。成绩添加时可以直接用 Django 内置的CreateView类视图但为了让新手看清流程下面用函数视图写出完整逻辑。# grades/views.py from django.shortcuts import render, get_object_or_404, redirect from django.contrib import messages from .models import Student, Course, Score # 成绩列表 def score_list(request): # 关联查询减少 SQL 查询次数 scores Score.objects.select_related(student, course).all() # 支持按课程筛选 course_id request.GET.get(course_id) if course_id: scores scores.filter(course_idcourse_id) return render(request, grades/score_list.html, {scores: scores}) # 成绩录入 def score_add(request): if request.method POST: student_id request.POST.get(student) course_id request.POST.get(course) score_value request.POST.get(score) # 检查是否已存在同名学生同课程的成绩 if Score.objects.filter(student_idstudent_id, course_idcourse_id).exists(): messages.error(request, 该学生此课程已有成绩请直接编辑) return redirect(grades:score_add) Score.objects.create( student_idstudent_id, course_idcourse_id, scorescore_value ) messages.success(request, 成绩添加成功) return redirect(grades:score_list) students Student.objects.all() courses Course.objects.all() return render(request, grades/score_form.html, { students: students, courses: courses, })逻辑说明select_related(student, course)是 Django 执行查询时的性能优化手段它用一条带 JOIN 的 SQL 把关联对象一并取出避免在模板里访问score.student.name时重复查询数据库。新增成绩前的去重检查属于业务兜底虽然数据库层已经设置了unique_together但提前给出友好提示比让用户看 500 错误体验好得多。4.3 HTML 模板与表单提交页面如何和视图交换数据模板用 Django 模板语法写表单的action留空表示提交到当前 URLname属性必须与视图里request.POST.get()的 key 一一对应。!-- grades/templates/grades/score_form.html -- !DOCTYPE html html langzh-cn head meta charsetutf-8 title录入成绩/title /head body h2录入学生成绩/h2 {% if messages %} {% for msg in messages %} p stylecolor: {{ msg.tags }}{{ msg }}/p {% endfor %} {% endif %} form methodpost {% csrf_token %} label学生/label select namestudent {% for s in students %} option value{{ s.id }}{{ s.student_no }} {{ s.name }}/option {% endfor %} /select br label课程/label select namecourse {% for c in courses %} option value{{ c.id }}{{ c.course_name }}/option {% endfor %} /select br label成绩/label input typenumber namescore step0.01 min0 max100 required br button typesubmit保存/button /form a href{% url grades:score_list %}返回列表/a /body /html两条容易忽略的细节{% csrf_token %}是 Django 的跨站请求伪造防护模板里不写它会提示 403input标签的step0.01 min0 max100让浏览器端先做格式校验减少无效请求打到服务器。列表模板的写法类似用{% for score in scores %}遍历并展示每个字段这里不再重复贴出。4.4 平均分与排名统计用 annotate 聚合查询学生成绩管理系统的核心价值在于统计——平均分、最高分、班级排名。Django 执行查询时最省心的方式是用annotate配合聚合函数把统计交给数据库完成。# 课程平均分与选课人数统计 from django.db.models import Avg, Max, Count def score_statistics(request): stats Score.objects.values(course__course_name).annotate( avg_scoreAvg(score), max_scoreMax(score), student_countCount(student), ).order_by(-avg_score) return render(request, grades/score_statistics.html, {stats: stats})参数说明values(course__course_name)先按课程名分组annotate为每组计算结果列——Avg(score)生成平均分Count(student)统计选课人数。order_by(-avg_score)按平均分降序排页面里用{{ item.avg_score|floatformat:1 }}过滤模板过滤器控制小数点位数即可。这样一个统计接口就能承载课程比较和成绩分析两个功能点。5. 验证项目可复现三个检查步骤与两个收尾技巧5.1 按接口路径逐项验证功能是否完整项目是否真正跑通别只看默认欢迎页建议按下面顺序在浏览器里逐项操作验证访问127.0.0.1:8000/admin用超级管理员账号登录在后台分别添加 3 个学生、2 门课程再录入 5 条成绩。此时 MySQL 的score_db库三张表已经各自落数据。访问127.0.0.1:8000/scores/确认列表页能看到刚才录入的成绩且学生姓名、课程名正确显示——如果显示成Student object (1)说明模板里没有使用.name属性。在列表页点击新增成绩故意录入已存在的「学生 课程」组合确认出现友好错误提示而不是数据库异常报错。打开 MySQL 客户端执行SELECT * FROM grades_score;确认数据与页面一致。这里能验证中文字符集是否正常。5.2 高概率踩坑排查表报错现象根本原因解决方式ModuleNotFoundError: No module named pymysql未安装驱动执行pip install pymysql在__init__.py中引入django.db.utils.OperationalError: (1045, Access denied)数据库账号密码错误或未授权确认settings.py的 USER/PASSWORD并执行 GRANT 授权(1366, Incorrect string value: \\xE5\\xBC\\xA0...)表或库字符集非 utf8mb4建库时指定DEFAULT CHARACTER SET utf8mb4删除重建不可逆TemplateDoesNotExist模板目录结构错误确认 templates 目录下按grades/score_list.html路径放置表单提交显示 CSRF 403模板缺少 csrf_token在 form 标签后第一行加入{% csrf_token %}5.3 admin 界面美化和批量导入数据Django admin 界面美化是高频搜索词但根本目的不是炫技而是让非技术用户愿意使用系统。常规做法是继承 admin 自带的admin/base_site.html模板覆盖标题和样式# grades/admin.py 内追加 admin.site.site_header 学生成绩管理后台 admin.site.site_title 成绩管理 admin.site.index_title 数据管理入口这段代码把后台顶部的 Django administration 替换成中文标题零成本提升可用性。如果想把 Excel 里的成绩批量导入推荐用django-import-export库在 admin 的 ModelAdmin 子类中添加入口。# 需要先安装 pip install django-import-export from import_export import resources from import_export.admin import ImportExportModelAdmin class ScoreResource(resources.ModelResource): class Meta: model Score class ScoreAdmin(ImportExportModelAdmin, admin.ModelAdmin): resource_class ScoreResource配合import_export的导入页面管理员可以上传 Excel 一键录入整班成绩学习成本低且复用性高。做完这一层这个学生成绩管理系统就从一个 demo 变成了真正能交给教务人员日常使用的工具数据的维护、备份、迁移也都有了清晰的路径——后续需要扩展权限、导出报告时这套 Django MySQL 的骨架不用动直接往上加模块即可。本文还有配套的精品资源点击获取