基于Python和Django的高考志愿填报系统设计与实现
简介这套基于PythonDjango的高考志愿填报系统是面向计算机相关专业学生的高分毕业设计资料包适用于毕业设计、课程设计或项目初期立项演示。资源包含完整的系统源码、数据库脚本及详细设计文档覆盖考生信息管理、志愿智能推荐、院校专业查询等核心业务模块适合希望快速搭建完整项目并理解Django框架实际开发流程的读者。压缩包大小约214MB目前已有125人学习下载。资料按功能模块组织包含项目代码、数据库文件、设计说明文档等代码已在Windows与Mac环境下测试通过可直接运行或二次开发同时附带答辩所需的系统架构说明、流程设计等内容能帮助使用者节省从零搭建的时间高效完成课设或毕设任务。该资源特别适合软件工程、人工智能、电子信息等专业学生进阶学习或作为项目参考也方便入门者通过完整案例掌握前后端交互与数据库设计的要点。1. 从志愿草表到 Web 应用Python Django 高考志愿填报系统要解决的核心问题高考出分后那几天考生和家长面对的不是一张表而是几百页招生计划、多批次选科限制、各校历年录取分数与位次的组合判断。基于 Python 与 Django 的高考志愿填报系统把这些数据拆解成院校库、专业库、招生计划、历年录取线和考生自己的志愿草表让筛选、排序、保存、修改都在浏览器里完成。前台考生可以按选科组合和位次区间检索可报院校后台维护招生计划与分数线数据也支持用 Excel 批量导入每年更新的计划。压缩包里还带了数据库文件、详细设计文档和管理端配置适合软件工程、计科、人工智能等专业学生做课程设计或毕业设计二次开发。拿到项目后第一步不是跑代码而是先看数据库设计。2. 数据表设计是整套系统的主干院校、专业、招生计划与历年录取线接手一个 Django 毕设项目时我习惯先翻 models.py 而不是先跑页面。数据表的设计直接决定了后台管理页能提供哪些筛选条件、推荐逻辑好不好写、Excel 导入脚本要处理哪些字段。这套系统里的表关系不复杂但把每一张表的定位说清楚后续调推荐算法时就不用反复改表结构。2.1 从一张 ER 图说起六张核心表如何关联围绕志愿填报业务核心实体可以归纳成六类用户、学生档案、院校、专业、招生计划、历年录取线另外再用一张志愿表保存用户的推荐结果和手动调整。用户与学生档案可以拆成两张表常见做法是用 Django 内置的 User 认证体系再通过 OneToOneField 挂一个学生资料表这样登录注册直接复用 Django 自带能力又能扩展选科、成绩、位次这些字段。院校和专业属于基础数据它们本身不产生志愿记录。真正被志愿记录引用的是“招生计划”某一年、某一个批次、某所学校的某个专业计划招多少人、选科要求是什么。招生计划是推荐逻辑检索的主体而历年录取线因为需要按年份重复存储单独建一张外键关联表结构更干净。2.2 物理表与 Django ORM 的对应关系及模型代码把压缩包里的 models.py 核心部分压缩后表关系大概长这样class School(models.Model): code models.CharField(院校代码, max_length20, db_indexTrue) name models.CharField(院校名称, max_length100, uniqueTrue) province models.CharField(所在省份, max_length30) level models.CharField(办学层次, max_length20, choices[(985, 985), (211, 211), (双一流, 双一流), (普通本科, 普通本科)]) nature models.CharField(办学性质, max_length10, choices[(公办, 公办), (民办, 民办)]) class RecruitPlan(models.Model): school models.ForeignKey(School, on_deletemodels.CASCADE, related_nameplans) major models.ForeignKey(Major, on_deletemodels.CASCADE, related_nameplans) year models.IntegerField(招生年份, db_indexTrue) batch models.CharField(批次, max_length20, choices[(本科批, 本科批), (专科批, 专科批), (提前批, 提前批)]) plan_num models.IntegerField(计划人数) subject_req models.CharField(选科要求, max_length50) class ScoreLine(models.Model): plan models.ForeignKey(RecruitPlan, on_deletemodels.CASCADE, related_namescorelines) year models.IntegerField(录取年份) min_score models.IntegerField(最低分, nullTrue, blankTrue) min_rank models.IntegerField(最低位次, nullTrue, blankTrue) avg_score models.IntegerField(平均分, nullTrue, blankTrue)代码里有两个关键设计。第一School.code 加了 db_indexTrue 并且作为逻辑查询主键Excel 导入时靠院校代码去重比直接用 name 查询更可靠也能抗住院校改名的干扰。第二RecruitPlan 和 ScoreLine 拆成两张表是因为同一个专业的招生计划每年都在变化而历年分数线要跨年份做聚合查询单独存放后 ORM 里的 annotate、filter 都能直接作用于 year 字段。2.3 历年分数线单独建表的取舍常见误区是把近三年最低分直接拼成一个字符串存进招生计划表比如存成“2023:580|2024:575”。这种方案在页面展示上确实直观但一旦要做“近三年最低位次都在当前位次之前”这样的跨年份比较就得在应用层切字符串又慢又容易错。拆分成 ScoreLine 表后一次外键反向查询就能拿到所有历史记录后台管理里也能对每一年的数据单独编辑。另一个取舍是同时保留分数和位次。分数受当年试题难度影响参考价值有限位次直接反映考生在全省考生中的排位。原始表里如果只有分数建议在导入历史数据时按当年一分一段表补上 bit次 字段后续推荐算法能直接用位次做比较。2.4 字段设计里容易踩的坑设计表的时候就应该把可能出现的脏数据挡在门外下面这几个位置我在实际运行中经常看到问题位置常见问题建议选科要求存成“物理或化学”自由文本统一成“物理化学”“物理或化学”或 JSON 数组写入前清洗年份用字符串存导致排序异常用 IntegerField查询时带 year 条件计划人数用 CharField 存储IntegerFieldExcel 导入时把 NaN 处理成 0历年分数空值填 0用 nullTrue不要填 0否则筛选 min_score 会误伤选科要求的清洗要特别说。各省新高考规则不一样有的要求“物理必选”有的要求“物理和化学均选”有的是“政治或地理任选一门”。如果原始表里是自由文本最好在导入阶段做一个映射把中文描述替换成带操作符的代码推荐逻辑里写一个解析函数去匹配而不是靠字符串 contains 碰运气。2.5 建库迁移与初始数据导入命令数据库文件通常放在压缩包的 database 目录下可能是 .sql 文件也可能是 Django fixture。先用命令把表结构建出来再决定导入哪种初始数据python manage.py makemigrations python manage.py migrate python manage.py createsuperuser python manage.py loaddata initial_data.jsonmakemigrations 负责根据 models.py 生成迁移脚本migrate 把表结构写入实际数据库createsuperuser 创建的后台账号会进到 Django 默认的 User 表。如果提供的是 .sql 文件可以在数据库管理工具里直接执行如果提供的是 fixtureloaddata 一次还原完整数据。导入完成后建议用下面的命令验证数据条数python manage.py shell -c from 业务app.models import RecruitPlan; print(RecruitPlan.objects.count())3. 选科匹配、位次换算与冲稳保推荐核心业务逻辑的 Django 实现数据表就绪后系统的核心价值集中在推荐逻辑上。志愿填报推荐和电商推荐不同它不需要猜用户偏好而是必须严格服从约束选科组合不满足的专业不能显示考生位次与院校历年录取位次差距过大的专业不能乱推荐。3.1 先按选科和批次把招生计划筛掉一半选科匹配是第一道门槛。假设考生选科组合是“物理化学生物”表单提交后把科目按约定传到后端Django 视图里可以这样过滤def filter_by_subject(queryset, subjects, batch, year): q Q(yearyear) Q(batchbatch) for subject in subjects: q Q(subject_req__icontainssubject) return queryset.filter(q)这段代码用 icontains 做包含匹配适合科目要求还是自由文本的原始数据但边界很清楚如果一条计划要求“物理或历史”用 AND 逻辑会把符合条件的计划排除掉。所以我通常先把 subject_req 清洗成统一格式必选用物理化学任选用[物理,化学]再写一个解析函数处理两种操作符避免无脑 contains。3.2 位次换算的原理为什么比单纯看分数更接近真实分数线的价值在于映射到省排名。同样是 580 分2022 年可能排在全省 2 万名2024 年可能已经是 2.8 万名直接用分数对比招生计划里的最低分结论会偏差很大。位次换算的做法是取目标专业近三年的最低位次比如得到 21000、19500、22000再和考生今年的位次做相对比较。没有完整一分一段表时可以用简化版把考生位次和历年最低位次的相对差值作为排序指标差值越小代表该专业往年门槛越高。这个相对差值就是下一节冲稳保分档的核心参数。3.3 冲稳保三档划分与参数表冲稳保是考生真正关心的输出结果。常见做法是把“考生位次”和“院校专业近年最低位次”做差值比例按区间分类档位ratio 区间使用场景冲ratio -0.15院校历年录取位次明显好于考生位次风险高稳-0.15 到 0.15位次接近录取概率中等保ratio 0.15院校历年录取位次明显差于考生位次托底用ratio 的计算方式是(院校近年最低位次 - 考生位次) / 考生位次。考生位次数值越小排名越靠前所以 ratio 为负数说明院校门槛比考生位次高属于冲刺。这个阈值不是固定的不同批次可以调提前批可以收紧到 0.1本科批保持 0.15 能多留出候选。3.4 View 层推荐逻辑的代码骨架下面这段代码是推荐引擎的核心骨架放在 views.py 里就能工作def build_recommendations(student_rank, subjects, batch, year): from django.db.models import Max base_qs RecruitPlan.objects.filter(yearyear, batchbatch) base_qs filter_by_subject(base_qs, subjects, batch, year) recommendations [] for plan in base_qs: lines plan.scorelines.filter(year__gteyear - 3) if not lines.exists(): continue ref_rank lines.aggregate(Max(min_rank))[min_rank__max] if not ref_rank: continue ratio (ref_rank - student_rank) / student_rank if ratio -0.15: tag 冲 elif ratio 0.15: tag 稳 else: tag 保 recommendations.append((tag, ratio, plan)) recommendations.sort(keylambda item: item[1]) return recommendations这里用 aggregate(Max(min_rank)) 取近三年最低位次中数值最大的那个代表这三年里门槛相对最低的一届让考生知道自己最低可能落到什么位置。ratio 用于排序值越小代表往年门槛越高排在最前面的就是冲刺项越往后越是保底。代码的优点是逻辑直观、适合答辩展示缺点是几万条计划时逐条循环会偏慢。毕业设计场景下可以把结果按recommend:{student_id}:{batch}做缓存数据更新时再主动清掉。3.5 数据不足时降级处理新开专业、中外合作办学项目经常只有一年数据直接用三年的逻辑会漏掉。降级规则可以分两档近三年只有一年的直接用这一年的 min_rank标签改为“新设专业”近三年完全没有数据的不出现在推荐列表但可以单独展示在“最新计划”模块。实现时在循环里统计 lines.count()小于 2 时给 plan 加一个提示字段前端显示成灰色标记避免用户误判。4. 从压缩包到浏览器环境配置、数据库连接与 Django 后台使用项目能不能跑起来八成问题出在环境而不是代码本身。这套代码在 macOS 和 Windows 10/11 上都验证过但每台机器的 Python 环境差异还是会遇到各种各样的报错。这一章按顺序操作基本能打开前台和管理端。4.1 解压后的项目里都有什么解压后通常包含工程配置目录、业务 app、manage.py、requirements.txt、数据库备份目录和文档。大致布局如下project/ manage.py requirements.txt zhiyuan/ # 工程配置目录 settings.py urls.py wsgi.py core/ # 业务 app实际名称以压缩包为准 models.py views.py admin.py templates/ # 页面模板 static/ # css/js/图片 database/ # 数据库备份或初始数据 docs/ # 设计文档、说明先打开 requirements.txt 看依赖清单再创建虚拟环境安装。不要直接往系统 Python 里塞依赖容易和机器上别的项目相互干扰。4.2 本地环境准备与依赖安装python -m venv venv source venv/bin/activate venv\Scripts\activate # Windows 下执行这条 pip install -r requirements.txt第一条命令创建虚拟环境后两条分别是 macOS/Linux 和 Windows 下的激活方式。requirements.txt 里通常会包含 Django、MySQL 驱动、pandas 这些依赖。安装完成后用python -c import django; print(django.get_version())确认 Django 能正常导入。4.3 settings 里连接数据库项目可能默认使用 SQLite也可能要求连 MySQL具体看压缩包附带的说明文档。Django 的数据库配置集中在 settings.py 里改动点如下DATABASES { default: { ENGINE: django.db.backends.mysql, NAME: volunteer_db, USER: root, PASSWORD: 你的数据库密码, HOST: 127.0.0.1, PORT: 3306, OPTIONS: {charset: utf8mb4}, } }ENGINE 指定数据库后端NAME 是库名需要先在 MySQL 里建好库。OPTIONS 里的 utf8mb4 很重要高校专业名称里各种特殊字符都能存。如果只是想本地先把项目跑起来把 ENGINE 换成django.db.backends.sqlite3NAME 改成db.sqlite3就行不用装 MySQL。4.4 迁移、初始数据和管理员账号数据库连接改好后按顺序执行python manage.py makemigrations python manage.py migrate python manage.py createsuperuser python manage.py runserver迁移会把 models.py 定义的表结构写进数据库。createsuperuser 按提示输入用户名、邮箱、密码这个账号用来登录 /admin/。runserver 默认监听 8000 端口浏览器访问 http://127.0.0.1:8000/ 打开前台访问 /admin/ 打开管理后台。如果 8000 被占用指定新端口python manage.py runserver 8080。4.5 把核心模型注册进 admin压缩包里的后台通常已经注册好了模型如果要自己把新表加进去admin.py 可以这样写from django.contrib import admin from .models import School, RecruitPlan, ScoreLine admin.register(School) class SchoolAdmin(admin.ModelAdmin): list_display [code, name, province, level] search_fields [code, name] admin.register(RecruitPlan) class PlanAdmin(admin.ModelAdmin): list_filter [year, batch] search_fields [school__name, major__name]list_display 决定列表页显示哪些列search_fields 生成搜索框list_filter 在页面右侧生成过滤器。外键字段在 search_fields 里用双下划线写法比如 school__name这样就能按学校名称直接搜索招生计划。4.6 运行阶段常见错误与排查报错信息可能原因处理方式No module named MySQLdb缺少 MySQL 驱动pip install mysqlclient或确认 requirements 已包含Unknown column ... in field list数据库旧表与 models 不一致备份数据后重新 migrate 对应 appDisallowedHost 报错ALLOWED_HOSTS 限制开发期在 settings.py 里加入 127.0.0.1静态文件 404DEBUGTrue 配置或静态目录未识别检查 STATICFILES_DIRS 指向的路径以上四条是接手 Django 毕设项目最常见的启动问题。出现 DisallowedHost 时把 ALLOWED_HOSTS 临时设置成[*]可以快速定位是不是域名配置问题但别长期留在生产环境。静态文件问题绝大多数是路径没对齐检查 static 目录是否在项目根路径下。5. 把 Excel 招生计划批量灌进系统一个能直接改的导入脚本与三个坑招生计划每年更新一次数量大、格式每年都略有变化。后台逐条录几百所院校的计划录入慢还容易错批量导入脚本是实际使用中最该先做的一步。5.1 为什么需要独立导入脚本Django admin 适合维护单条数据不适合大批量初始化。Excel 里的列基本能对应上 RecruitPlan但学校名和代码要关联到 School 表专业名要关联到 Major 表先查再插或先插再查的逻辑需要脚本统一处理并且要允许重复执行不产生重复数据。5.2 用 pandas 读取并逐行写入数据库import pandas as pd from your_app.models import School, Major, RecruitPlan df pd.read_excel(plan_2024.xlsx, dtype{院校代码: str, 专业代码: str}) errors [] for idx, row in df.iterrows(): school, _ School.objects.get_or_create( coderow[院校代码], defaults{name: row[院校名称]}) major, _ Major.objects.get_or_create( coderow[专业代码], defaults{name: row[专业名称]}) try: RecruitPlan.objects.update_or_create( schoolschool, majormajor, yearint(row[年份]), batchrow[批次], defaults{plan_num: int(row[计划人数]), subject_req: str(row[选科要求])}) except Exception as exc: errors.append((idx, str(exc))) print(完成失败行数:, len(errors))get_or_create 先按院校代码查查不到再新增返回的 created 标志可以判断是插入还是复用。update_or_create 按学校、专业、年份、批次四个字段做唯一性判断同一个计划不会重复插入只会更新计划数和选科要求。每行的异常收集到 errors 列表而不是直接中断跑完一眼就能看到哪些行需要人工修正。5.3 在 Django shell 里执行导入脚本不能直接python import_plan.py因为模型依赖 Django 的 settings 信息。常见做法有两种python manage.py shell -c exec(open(import_plan.py, encodingutf-8).read())也可以进入 shell 后手动粘贴代码。第一次跑之前先执行df.head()确认列名不要拿着真实数据直接跑导入工具一旦匹配错列后续清理要花更多时间。5.4 Excel 表格里的三个典型坑第一年份列在 pandas 里可能被读成浮点数变成 2024.0写入 IntegerField 前要显式转 int。第二专业代码前有零容易被吃掉读 Excel 时必须指定 dtype 为 str否则字符串“081201”会变成数字 81201。第三选科要求列可能有很多空值直接 str(row[选科要求]) 会把 NaN 变成字符串“nan”写入前用if pd.isna(row[选科要求]): subject_req 处理。5.5 导入后的复核查询导入完成后用聚合查询验证总数和学校数量python manage.py shell -c from your_app.models import RecruitPlan from django.db.models import Count print(RecruitPlan.objects.filter(year2024).count()) print(RecruitPlan.objects.values(school__name).annotate(numCount(id)).count())第一条输出 2024 年招生计划总数第二条输出涉及学校数量。如果数量和 Excel 行数对不上优先检查批次名称里是否有多余空格。shell -c 外面用双引号内部代码避免再使用和 bash 冲突的引号这是在 macOS 和 Windows 下都能跑的写法。本文还有配套的精品资源点击获取