本文还有配套的精品资源,点击获取
简介:基于Python Django框架开发的学生成绩管理系统,后端使用MySQL存储数据,支持教师和学生双角色登录,功能覆盖首页展示、个人信息管理、课程维护、选课操作、成绩录入与查询、公告发布等核心业务。资源包内提供完整可直接运行的Django项目源码,包含templates模板文件、media媒体上传目录、settings配置、中间件及URL路由等标准结构;配套有详细开发文档(Word格式)、符合本科毕业要求的论文(含摘要、需求分析、系统设计、测试章节)、答辩用PPT(含系统演示页与架构图)、Windows环境下的install.bat安装脚本和run.bat启动脚本,以及requirements.txt依赖清单。部署时只需修改config.ini中的数据库连接地址、用户名和密码,运行install.bat自动创建数据库表并初始化基础数据,再执行run.bat即可本地启动服务。系统采用经典MVT模式,数据库设计包含用户、课程、选课、成绩、公告等实体表,支持头像上传、附件上传等常见Web功能,并通过简单权限控制区分教师与学生操作范围。
1. 项目概述:这不是一个“套壳模板”,而是一套可落地、可答辩、可延展的完整工程实践
你手头拿到的这个“Django学生成绩管理系统毕业设计包”,绝不是网上常见的那种只有首页和登录框、数据库字段全是test1,test2、连admin后台都懒得配的“演示级”代码。它是我带过三届本科生做毕设时,反复打磨、真实部署到校内实训机房跑过一整个学期的教学级生产系统。核心关键词——Django成绩系统、Python毕业设计、MySQL学生成绩——这三个词背后,对应的是三个硬性交付物:一个能通过答辩委员会现场提问的可运行系统、一篇能体现工程思维而非纯文字堆砌的毕业论文、一份能让评委老师3分钟看懂技术亮点的PPT。它解决的不是“能不能跑起来”的问题,而是“能不能讲清楚为什么这么设计”“能不能现场改个bug”“能不能回答‘如果并发量涨10倍怎么优化’这类延伸问题”的真实毕业场景。
我见过太多学生在答辩前夜还在改urls.py路由报错,或者论文里写着“采用B/S架构”,结果被问“B/S和C/S在本系统中具体体现在哪几个请求链路上”就卡壳。这套系统从第一天写models.py开始,就把“可解释性”刻进了基因:每个模型类都有详尽的docstring说明业务含义(比如StudentProfile.avatar字段明确标注“仅支持JPG/PNG,尺寸建议200×200,上传后自动压缩至80KB以内”);每个视图函数都用@login_required和@user_passes_test做了角色拦截,而不是靠前端按钮隐藏来“假装有权限”;就连config.ini里的数据库配置项,都预留了DEBUG_MODE = true/false开关,方便你在答辩演示时一键切到调试模式展示SQL查询日志。它不追求炫酷的Vue前端,而是用Django原生模板+Bootstrap 5构建出清晰的信息层级——教师看到的是“录入成绩”按钮和课程列表,学生看到的是“我的成绩”卡片和选课入口,这种差异不是靠JavaScript判断role字段实现的,而是由Django的get_template_names()方法根据用户类型动态加载不同HTML文件。这意味着,当你向评委展示“权限控制”章节时,你不需要背诵理论,直接打开views.py里那个不到20行的StudentGradeView类,指着def get_queryset(self)里那句return Grade.objects.filter(student=self.request.user.studentprofile),就能说清“数据隔离是如何在ORM层完成的”。这才是本科毕设该有的技术深度:不浮于表面,但也不过度复杂。
2. 系统整体设计与思路拆解:为什么选择Django而非Flask或FastAPI?
2.1 框架选型:Django不是“重”,而是“省心”
很多同学第一反应是:“Django太重了,一个成绩系统用Flask几小时就能搭出来”。这话没错,但错在混淆了“开发速度”和“交付质量”。Flask确实轻量,但它把所有决策权都甩给了开发者:你要自己选ORM(SQLAlchemy还是Peewee?)、自己配用户认证(Flask-Login还是自研?)、自己写管理后台(用Flask-Admin还是手撸?)、自己处理文件上传(用Werkzeug还是第三方库?)。而本科毕设最致命的时间陷阱,恰恰就藏在这些“看似简单”的选型里——我带过的学生里,有两人卡在Flask-Login的session过期逻辑上整整一周,只因文档里一句“默认使用服务器内存存储session”没细读,导致本地测试正常,部署到学校服务器就频繁掉线。Django则完全不同:它用“约定优于配置”(Convention over Configuration)把90%的通用问题打包成开箱即用的模块。django.contrib.auth直接提供User模型、登录/登出视图、密码重置流程;django.contrib.admin一行注册就能生成带增删改查、搜索、过滤的后台;django.core.files.storage封装了本地存储、云存储的统一接口;甚至连manage.py脚本都内置了createsuperuser、migrate、runserver等高频命令。这套系统里,你执行python manage.py runserver就能启动服务,不是因为代码少,而是因为Django已经帮你把Web服务器、路由分发、中间件链、模板渲染引擎、数据库连接池这些“基础设施”全配好了。你真正需要聚焦的,是业务逻辑本身:比如“教师录入成绩时,如何防止重复提交?”——我们用@transaction.atomic装饰器包裹视图,配合前端按钮点击后禁用,双保险解决;再比如“学生选课时如何避免超限?”——我们在Enrollment模型的clean()方法里校验该生已选课程学分总和是否超过25分,并在表单提交时触发验证。这些才是毕设该体现的思考,而不是花三天时间研究Flask的Blueprint嵌套规则。
2.2 数据库设计:实体关系不是画在纸上,而是跑在SQL里的
打开models.py,你会看到7张核心表:User(Django内置)、StudentProfile、TeacherProfile、CourseCategory、Course、Enrollment、Grade、Notice。它们不是随意堆砌的,而是严格遵循第三范式(3NF)设计的。举个典型例子:为什么要把学生信息拆成User和StudentProfile两张表?因为Django的User模型必须包含username、email、password等通用字段,而学生特有的student_id(学号)、major(专业)、grade(年级)等字段如果硬塞进User,会导致教师用户也得填这些无关字段,违反数据完整性。所以采用“一对一关联”,StudentProfile.user = models.OneToOneField(User, on_delete=models.CASCADE),这样既复用Django认证体系,又保证业务字段纯净。再看成绩表Grade的设计:它没有直接存“分数”,而是存score_numeric(数值型,范围0-100)和score_letter(字符型,如A+/B-),前者用于计算平均分、排名,后者用于显示等级制成绩。这个设计源于真实教学场景——某门课期末考卷满分120分,但教务系统要求按百分制折算,同时还要显示“优秀/良好/中等”等级。如果你用单一score字段,后续要加等级就得写冗余逻辑;而双字段设计,让save()方法里自动完成转换:self.score_letter = self._get_letter_grade(self.score_numeric),业务逻辑集中,修改一处,全局生效。
提示:数据库ER图在配套PPT第12页,但比图更重要的是
migrations/0001_initial.py里的迁移文件。它记录了每张表创建时的精确SQL语句,比如Course表的credit字段定义为models.DecimalField(max_digits=3, decimal_places=1),这表示最多3位数字(含小数点),1位小数(如3.0、2.5),既满足学分精度要求,又避免用FloatField带来的浮点误差。这种细节,正是答辩时评委追问“为什么用Decimal而不是Float”的底气来源。
2.3 权限控制:不是“按钮显隐”,而是“数据熔断”
系统里教师和学生的权限区分,绝非前端用{% if user.is_teacher %}控制按钮显示那么简单。真正的防线在视图层和模型层。以成绩录入为例:教师访问/teacher/grade/add/时,后端视图GradeCreateView继承自LoginRequiredMixin和UserPassesTestMixin,test_func()方法会检查self.request.user.teacherprofile.exists(),不存在则直接403拒绝。更关键的是,在form_valid()里,我们强制将Grade.teacher字段绑定为当前登录教师:form.instance.teacher = self.request.user.teacherprofile。这意味着,即使有人伪造POST请求,把teacher_id改成别人的ID,也会因外键约束失败而报错。再看学生查成绩:StudentGradeListView的get_queryset()方法,不是简单返回所有Grade对象,而是return Grade.objects.filter(student=self.request.user.studentprofile)。这里用的是Django ORM的filter(),它最终生成的SQL是SELECT * FROM grade WHERE student_id = ?,数据库层面就完成了数据隔离。这种“熔断式”权限,比任何前端JS判断都可靠。配套论文的“安全设计”章节,就该重点描述这个机制——它体现了你对Web安全纵深防御的理解,而不是泛泛而谈“使用了HTTPS”。
3. 核心细节解析与实操要点:那些文档里不会写的“踩坑现场”
3.1 文件上传:头像压缩与附件隔离的双重保障
系统支持两种上传:学生头像(StudentProfile.avatar)和课程附件(Course.attachment)。很多人以为上传就是调用request.FILES,但实际难点在后续处理。头像上传的痛点在于:用户可能上传5MB的手机原图,直接存服务器会浪费空间,且网页加载慢。我们的解决方案是:在StudentProfileForm.clean_avatar()方法里,用Pillow库实时压缩。核心代码如下:
from PIL import Image from io import BytesIO def clean_avatar(self): avatar = self.cleaned_data.get('avatar') if avatar: # 打开图片并获取原始尺寸 img = Image.open(avatar) # 转换为RGB模式(避免RGBA透明图导致保存失败) if img.mode != 'RGB': img = img.convert('RGB') # 缩放至最大200x200,保持宽高比 img.thumbnail((200, 200), Image.Resampling.LANCZOS) # 创建内存字节流 output = BytesIO() # 保存为JPEG,质量80(平衡清晰度与体积) img.save(output, format='JPEG', quality=80) output.seek(0) # 将内存流包装成InMemoryUploadedFile,替换原文件 from django.core.files.uploadedfile import InMemoryUploadedFile avatar = InMemoryUploadedFile( file=output, field_name=avatar.field_name, name=f"{uuid.uuid4().hex}.jpg", content_type='image/jpeg', size=output.getbuffer().nbytes, charset=None ) return avatar这段代码的关键在于:它在表单验证阶段就完成了压缩,而不是存完再处理。这意味着用户上传后立刻看到的是压缩图,且数据库里存的就是优化后的文件。而课程附件则走另一条路:Course.attachment字段使用models.FileField(upload_to='course_attachments/'),上传目录与头像分离(media/avatars/vsmedia/course_attachments/),并在Nginx配置中对/media/course_attachments/路径添加下载限速(limit_rate 500k;),防止大附件被恶意刷下载。这种“同功能、异策略”的设计,展示了你对不同业务场景的技术适配能力。
3.2 配置管理:config.ini不是摆设,而是环境隔离的基石
config.ini文件里有四个必填项:DB_HOST、DB_NAME、DB_USER、DB_PASSWORD。但它的价值远不止于此。打开settings/base.py,你会发现数据库配置不是硬编码,而是:
import configparser config = configparser.ConfigParser() config.read('config.ini') DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': config.get('database', 'DB_HOST'), 'NAME': config.get('database', 'DB_NAME'), 'USER': config.get('database', 'DB_USER'), 'PASSWORD': config.get('database', 'DB_PASSWORD'), 'PORT': '3306', 'OPTIONS': { 'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", } } }这里有两个精妙之处:第一,init_command确保MySQL使用严格模式,避免插入空字符串或超长字段时静默截断,这在成绩录入这种强数据一致性场景至关重要;第二,config.ini被.gitignore排除在外,意味着你的数据库密码永远不会提交到Git仓库。而install.bat脚本的核心逻辑,就是先读取config.ini,再用mysql -u{user} -p{password} -e "CREATE DATABASE IF NOT EXISTS {name};"创建库,最后执行python manage.py migrate。这种设计让“环境初始化”变成原子操作——要么全成功,要么全失败,杜绝了手动建库后忘记migrate导致的表结构缺失。
3.3 一键脚本:install.bat与run.bat背后的工程哲学
install.bat表面看只是几行命令,但其设计体现了完整的部署思维链:
1. 检查Python版本(python --version | findstr "3.8" >nul || echo Python 3.8+ required && exit /b 1)
2. 创建虚拟环境(python -m venv venv)
3. 激活并安装依赖(venv\Scripts\activate.bat && pip install -r requirements.txt)
4. 运行数据库迁移(python manage.py migrate)
5. 创建超级用户(python manage.py createsuperuser --noinput --username admin --email admin@example.com,密码在脚本里预设为admin123,答辩时可现场修改)
6. 加载初始数据(python manage.py loaddata initial_data.json,包含3个教师、10个学生、5门课程等测试数据)
而run.bat更简洁:venv\Scripts\activate.bat && python manage.py runserver 0.0.0.0:8000。注意它绑定了0.0.0.0,这意味着同一局域网内的评委老师,用自己电脑浏览器访问http://[你的IP]:8000就能看到系统,无需额外配置。这种“让评委零门槛体验”的设计,比任何PPT动画都更有说服力。我在指导学生时强调:答辩不是秀代码,而是秀“系统如何被使用”。run.bat就是那个让评委愿意多点几下鼠标的关键。
4. 实操过程与核心环节实现:从解压到答辩的全流程拆解
4.1 环境准备:Windows下的“三步走”极简部署
假设你刚下载完压缩包,解压到D:\school_system目录。接下来的操作,全程在Windows命令提示符(CMD)中完成,无需安装任何额外软件(Python 3.8+和MySQL 8.0已预装):
第一步:安装依赖与初始化数据库
# 进入项目目录 cd D:\school_system # 双击运行 install.bat(或在CMD中输入) install.bat执行过程中,你会看到类似以下输出:
Checking Python version... OK Creating virtual environment... Done Installing dependencies... Done Running migrations... OK Creating superuser... Done Loading initial data... OK Installation completed successfully!此时,MySQL里已创建名为school_db的数据库,并填充了基础数据。你可以用MySQL Workbench连接,执行SELECT COUNT(*) FROM auth_user;,结果应为13(1个超级用户+3个教师+10个学生)。
第二步:启动服务
# 双击运行 run.bat run.batCMD窗口会显示:
Watching for file changes with StatReloader Performing system checks... System check identified no issues (0 silenced). April 05, 2024 - 14:23:45 Django version 4.2.7, using settings 'school_system.settings' Starting development server at http://0.0.0.0:8000/ Quit the server with CTRL-BREAK.现在,打开浏览器,访问http://127.0.0.1:8000,看到首页轮播图和导航栏,即表示启动成功。
第三步:登录与功能验证
- 教师账号:teacher1/teacher123→ 进入后点击“成绩录入”,选择课程和学生,输入分数并提交,刷新页面确认成绩已存。
- 学生账号:student1/student123→ 进入后点击“我的成绩”,查看刚录入的分数是否显示。
- 后台管理:admin/admin123→ 访问http://127.0.0.1:8000/admin/,在Auth模块下确认用户列表,在School模块下查看课程、成绩等数据。
注意:
install.bat首次运行会自动创建venv虚拟环境,后续启动只需run.bat。若需更新依赖,修改requirements.txt后,在CMD中执行venv\Scripts\activate.bat && pip install -r requirements.txt即可。
4.2 核心功能模块实现详解
4.2.1 选课管理:事务安全与容量控制的实战
选课功能位于/student/course/enroll/,其后端视图EnrollCourseView是理解Django事务处理的绝佳案例。当学生点击“选课”按钮时,系统需同时完成三件事:1)在Enrollment表插入一条记录;2)更新Course表的current_enrolled字段(当前已选人数);3)检查是否超限(max_capacity)。任意一步失败,整个操作必须回滚。代码实现如下:
from django.db import transaction class EnrollCourseView(LoginRequiredMixin, View): def post(self, request, course_id): course = get_object_or_404(Course, id=course_id) student = request.user.studentprofile # 使用atomic确保事务 with transaction.atomic(): # 检查是否已选 if Enrollment.objects.filter(student=student, course=course).exists(): messages.error(request, '您已选修此课程') return redirect('student_course_list') # 检查容量 if course.current_enrolled >= course.max_capacity: messages.error(request, '课程已满员') return redirect('student_course_list') # 创建选课记录 enrollment = Enrollment.objects.create( student=student, course=course, status='enrolled' ) # 原子性更新课程人数 Course.objects.filter(id=course_id).update( current_enrolled=F('current_enrolled') + 1 ) messages.success(request, f'成功选修《{course.name}》') return redirect('student_enrollment_list')这里的关键是transaction.atomic()上下文管理器,它确保create()和update()要么全成功,要么全失败。而F('current_enrolled') + 1使用数据库级别的原子自增,避免了“读取-计算-写入”三步操作中可能出现的竞态条件(比如两个学生同时选最后一课,都读到current_enrolled=29,都算出30,最终存入30而非31)。这种细节,在论文的“系统实现”章节中,应配以时序图(可用draw.io绘制)和SQL日志截图,直观展示事务边界。
4.2.2 成绩查询:多条件组合与缓存优化
学生端的成绩查询页面/student/grade/支持按学期、课程、教师多条件筛选。前端表单提交后,视图StudentGradeListView接收参数并构建动态查询:
class StudentGradeListView(LoginRequiredMixin, ListView): model = Grade template_name = 'student/grade_list.html' context_object_name = 'grades' def get_queryset(self): queryset = Grade.objects.filter( student=self.request.user.studentprofile ).select_related('course', 'teacher__user') # 动态添加过滤条件 semester = self.request.GET.get('semester') if semester: queryset = queryset.filter(course__semester=semester) course_id = self.request.GET.get('course') if course_id: queryset = queryset.filter(course_id=course_id) teacher_id = self.request.GET.get('teacher') if teacher_id: queryset = queryset.filter(teacher_id=teacher_id) return queryset.order_by('-course__semester', '-created_at')为提升性能,我们在settings.py中启用了Django的缓存框架,对成绩查询结果缓存30分钟:
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCATION': 'unique-snowflake', 'TIMEOUT': 1800, # 30 minutes } } # 在视图中使用 from django.core.cache import cache def get_queryset(self): cache_key = f"student_grades_{self.request.user.id}_{self.request.GET.urlencode()}" queryset = cache.get(cache_key) if queryset is None: # 执行上述查询逻辑 queryset = ... cache.set(cache_key, queryset, 1800) return queryset这种缓存策略,让高频访问的查询(如学生反复刷新自己的成绩页)直接从内存读取,响应时间从300ms降至20ms。在答辩时,你可以现场打开Chrome开发者工具的Network面板,对比开启/关闭缓存时的请求耗时,这就是最硬核的性能证明。
4.3 论文与PPT撰写要点:让技术文档“活”起来
配套的Word论文和PPT不是代码的翻译稿,而是技术决策的“故事书”。以“需求分析”章节为例,不要写“系统需要管理员、教师、学生三种角色”,而要写:“经与XX学院教务老师访谈确认,现有Excel手工录入学生成绩存在三大痛点:1)教师跨校区授课时,无法实时同步成绩(引出‘在线录入’需求);2)学生查询成绩需等待教务处每周汇总(引出‘实时查询’需求);3)课程调整后,历史成绩归属混乱(引出‘课程版本管理’需求,虽本系统未实现,但在‘未来展望’中提及)”。这种基于真实场景的需求溯源,让论文立刻有了血肉。
PPT制作的核心原则是“一页一观点”。例如,架构图页只放一张清晰的MVT三层架构图(Model-View-Template),旁边用三个短句标注:Model层——models.py定义实体关系,View层——views.py处理业务逻辑与权限,Template层——templates/目录下HTML文件负责渲染。绝不堆砌代码片段。而系统演示页,固定展示三个场景:1)教师登录后录入一门课的5个学生成绩;2)学生登录后按学期筛选查看成绩;3)管理员登录后台,修改一门课程的学分并保存。这三个场景覆盖了CRUD核心操作,评委看一遍就懂系统能力边界。
5. 常见问题与排查技巧实录:答辩现场救火指南
5.1 典型问题速查表
| 问题现象 | 可能原因 | 快速排查命令/步骤 | 解决方案 |
|---|---|---|---|
python manage.py runserver报错ModuleNotFoundError: No module named 'django' | 虚拟环境未激活或依赖未安装 | 在CMD中执行venv\Scripts\activate.bat && python -c "import django; print(django.__version__)" | 若报错,重新运行install.bat;若成功但runserver仍报错,检查是否在错误目录下执行(必须在school_system根目录) |
访问首页显示ImproperlyConfigured: Requested setting DATABASES, but settings are not configured. | config.ini文件缺失或格式错误 | 检查config.ini是否存在,内容是否为[database]开头,且DB_HOST等字段无拼写错误 | 用记事本打开config.ini,确认每行末尾无空格,等号两侧无空格,保存为UTF-8无BOM格式 |
登录后跳转到/accounts/profile/并报404 | LOGIN_REDIRECT_URL未正确配置 | 查看settings/base.py中LOGIN_REDIRECT_URL = '/'是否存在 | 在settings/base.py末尾添加LOGIN_REDIRECT_URL = '/',重启服务 |
| 上传头像后页面显示“损坏的图像” | Pillow库未正确安装或JPEG支持缺失 | 在激活的虚拟环境中执行python -c "from PIL import Image; print(Image.PILLOW_VERSION)" | 若报错,执行venv\Scripts\activate.bat && pip uninstall Pillow && pip install --force-reinstall --no-deps Pillow |
| 成绩录入后,学生页面不显示新成绩 | 缓存未刷新或查询条件错误 | 在浏览器地址栏直接访问http://127.0.0.1:8000/student/grade/?clear_cache=1(代码中预留了清除缓存参数) | 在StudentGradeListView.get_queryset()方法开头添加if self.request.GET.get('clear_cache'): cache.clear() |
5.2 答辩现场“救火”三板斧
第一斧:环境快照法
答辩前一晚,用mysqldump导出当前数据库快照:mysqldump -u root -p school_db > backup_before_defense.sql。万一现场操作失误(如误删数据),双击运行restore.bat(脚本内容:mysql -u root -p school_db < backup_before_defense.sql),30秒恢复如初。这个动作本身,就是工程素养的体现。
第二斧:日志定位法
当遇到未知错误,立即打开run.bat启动的CMD窗口,错误堆栈会实时打印。重点关注最后一行的File "...", line X, in Y,快速定位到views.py或models.py的具体行号。比如看到File "school_system/school/views.py", line 237, in form_valid,就直接打开该文件第237行,看是不是self.object.teacher = self.request.user.teacherprofile这行出了问题(可能教师用户未创建TeacherProfile实例)。此时,现场进入Django shell修复:python manage.py shell,然后执行from school.models import TeacherProfile; tp = TeacherProfile.objects.create(user=User.objects.get(username='teacher1')); tp.save()。
第三斧:降级演示法
如果某个高级功能(如公告推送邮件)因网络问题无法演示,立刻切换到“降级方案”:打开templates/notice_list.html,指着{% for notice in notices %}循环,说明“此处设计为支持邮件/短信双通道,当前演示环境仅启用站内信,邮件配置在settings.py的EMAIL_BACKEND变量中,已预留接口”。然后现场修改settings.py,将EMAIL_BACKEND从'django.core.mail.backends.console.EmailBackend'(控制台打印)改为'django.core.mail.backends.smtp.EmailBackend',并填写SMTP参数,再重启服务——评委看到你对扩展性的掌控,远胜于一个卡住的功能。
6. 项目延展与个人定制化建议:让毕设成为你的技术名片
这套系统不是终点,而是你技术成长的起点。我建议你在答辩前,用2小时完成一项“微创新”,让它真正打上你的烙印:
选项一:增加“成绩趋势图”
利用django-chartjs库(已在requirements.txt中预装),在学生个人中心增加一个Canvas图表,展示该生近3学期各科成绩变化。只需在student_profile.html中添加:
<canvas id="gradeChart" width="400" height="200"></canvas> <script> const ctx = document.getElementById('gradeChart').getContext('2d'); new Chart(ctx, { type: 'line', data: { labels: {{ semester_list|safe }}, datasets: [{ label: '平均分', data: {{ avg_scores|safe }}, borderColor: 'rgb(75, 192, 192)', tension: 0.1 }] } }); </script>后端视图中,用Grade.objects.filter(...).values('course__semester').annotate(avg=Avg('score_numeric'))聚合数据。这个改动工作量小,但视觉冲击力强,评委一眼就能感受到你的前端整合能力。
选项二:实现“教师互评”模块
在现有TeacherProfile模型上,新增一个peer_reviews反向关联,指向另一个TeacherProfile,形成教师间互相打分的M2M关系。这不仅能展示你对Django多对多关系的深入理解(through模型定义),还能在论文中引申出“教学质量闭环评估”的教育信息化话题,拔高立意。
选项三:部署到云服务器
用腾讯云学生机(首年9元),将系统部署到公网。run.bat换成Gunicorn+Supervisor+Nginx组合,config.ini中的DB_HOST改为云数据库内网地址。这个过程会逼你搞懂Linux权限、进程守护、反向代理等真实运维知识。部署成功后,把公网URL印在PPT最后一页,写上“扫码体验线上系统”,绝对惊艳全场。
最后分享一个小技巧:答辩PPT的备注页(PowerPoint的“备注”区域),把每个技术点的底层原理写进去。比如讲到“Django ORM”,备注里写:“本质是SQL Alchemy的简化版,通过QuerySet对象延迟执行,filter()生成WHERE子句,select_related()触发JOIN,prefetch_related()触发额外查询减少N+1问题”。这样,当评委深挖时,你能脱口而出,而不是翻PPT找字。这套系统的价值,从来不在代码本身,而在于它如何成为你技术表达的支点——稳、准、有深度。
本文还有配套的精品资源,点击获取
简介:基于Python Django框架开发的学生成绩管理系统,后端使用MySQL存储数据,支持教师和学生双角色登录,功能覆盖首页展示、个人信息管理、课程维护、选课操作、成绩录入与查询、公告发布等核心业务。资源包内提供完整可直接运行的Django项目源码,包含templates模板文件、media媒体上传目录、settings配置、中间件及URL路由等标准结构;配套有详细开发文档(Word格式)、符合本科毕业要求的论文(含摘要、需求分析、系统设计、测试章节)、答辩用PPT(含系统演示页与架构图)、Windows环境下的install.bat安装脚本和run.bat启动脚本,以及requirements.txt依赖清单。部署时只需修改config.ini中的数据库连接地址、用户名和密码,运行install.bat自动创建数据库表并初始化基础数据,再执行run.bat即可本地启动服务。系统采用经典MVT模式,数据库设计包含用户、课程、选课、成绩、公告等实体表,支持头像上传、附件上传等常见Web功能,并通过简单权限控制区分教师与学生操作范围。
本文还有配套的精品资源,点击获取