简介:面向高校课程设计与期末大作业场景,这份Python Django学生宿舍管理系统提供了可直接运行的完整工程,包含后端业务逻辑、前端页面与数据库脚本,适合正在学习Web框架开发或需要快速交付项目的同学参考。项目已通过导师指导并获97分评价,下载后无需额外修改即可部署体验,覆盖学生信息、宿舍分配、报修管理等典型模块,能够直观理解Django的MTV分层与ORM操作。压缩包共862个文件,以py、js、vue、html、css等类型为主,兼有sql数据库文件与静态资源,整体约30.65MB,目录结构清晰,便于按源码、模板、静态文件分类查阅。目前已有247人浏览学习,对想要借助真实项目巩固Django开发能力、完成课程设计任务的学习者而言,是一份值得参照的实践范本。
1. 为什么宿舍管理系统是Django课程的黄金练手项目
每到期末,宿舍管理员还在用Excel登记入住、手工核算水电费,而学生找宿管查一次住宿信息要跑三趟。这种场景在高校里极为普遍,也正因如此,学生宿舍管理系统成了Python课程设计中出镜率最高的题目之一。拿到这份97分的高分项目源码时,我先扫了一遍目录,典型的Django MTV结构:models定义数据表、views处理业务、templates渲染页面,外加一个完整的MySQL数据库脚本。它不是那种只搭了个架子、逻辑全写在前端的演示货,而是真能跑起来做增删改查的完整项目。
这个项目适合两类人:一是正在做课程设计、需要快速交差的学生,下载后改改数据库连接就能演示;二是想搞懂Django Web开发全流程的初学者,可以借这套代码研究ORM查询、表单验证、会话管理等核心机制。源码里包含了管理员端和学生端的双角色设计,宿舍分配、入住登记、调宿申请、水电费统计这些宿舍管理的核心功能都有覆盖。本篇文章会把这套系统的数据模型、业务逻辑、部署步骤和二次开发思路拆开来讲,保证读完你不仅能复现,还能在答辩时讲清楚每个表为什么这么设计。
2. Django ORM模型设计:一张表就是一个业务实体
2.1 宿舍管理领域的数据表结构拆解
打开项目里的models.py,最先看到的是这个系统最核心的数据模型设计。宿舍管理系统的业务实体并不复杂,但表之间的关系处理得好不好,直接决定了后期代码好不好写。这套项目把实体划分为五大类:学生信息、宿舍楼栋、宿舍房间、入住记录、水电费账单。
from django.db import models from django.contrib.auth.models import User class Building(models.Model): name = models.CharField(max_length=50, verbose_name='楼栋名称') address = models.CharField(max_length=100, verbose_name='楼栋地址') floors = models.IntegerField(default=6, verbose_name='楼层数') manager = models.CharField(max_length=30, blank=True, verbose_name='楼管员') def __str__(self): return self.name class Room(models.Model): building = models.ForeignKey(Building, on_delete=models.CASCADE, verbose_name='所属楼栋') room_number = models.CharField(max_length=20, verbose_name='房间号') capacity = models.IntegerField(default=4, verbose_name='可住人数') current_people = models.IntegerField(default=0, verbose_name='已住人数') class Meta: unique_together = ('building', 'room_number') def __str__(self): return f'{self.building.name}-{self.room_number}'这段代码里有几个设计亮点。Building和Room通过外键ForeignKey建立一对多关系,一栋楼有多个房间,这在宿舍场景中是天然成立的。Room表里同时保存capacity和current_people两个字段,前者是房间最大容量,后者是当前入住人数,每次分配宿舍时通过比较这两个值来判断房间是否已满,不用实时去关联查询入住记录再COUNT,这是一种用冗余字段换查询性能的做法。
unique_together元选项保证了同一栋楼内不会出现重复房间号,这是数据库层面的完整性约束,比在视图函数里手工判断要可靠得多。on_delete=models.CASCADE指定了楼栋被删除时其下所有房间级联删除,符合业务预期——楼都没了,房间记录自然没有保留意义。这里每个字段的verbose_name参数值得学习,Django admin后台会自动用它作为表单标签,省去了单独写页面的麻烦。
2.2 Student模型相关设计
学生表是宿舍管理系统的中心表,几乎所有业务逻辑都要关联它。这套项目里Student模型的设计有一些值得注意的细节。先看核心代码:
class Student(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name='关联用户') student_no = models.CharField(max_length=20, unique=True, verbose_name='学号') name = models.CharField(max_length=30, verbose_name='姓名') gender = models.CharField(max_length=10, choices=(('male', '男'), ('female', '女')), verbose_name='性别') room = models.ForeignKey(Room, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='所在宿舍') phone = models.CharField(max_length=11, blank=True, verbose_name='手机号') checkin_date = models.DateField(null=True, blank=True, verbose_name='入住日期') def __str__(self): return f'{self.student_no}-{self.name}'这里使用OneToOneField与Django内置的User表做一对一关联,把系统登录认证和业务数据分离。很多初学者图省事直接在Student表里加username和password字段,这种做法虽然简单,但无法利用Django内置的认证、会话、权限体系,后面做登录功能时会非常痛苦。使用默认的User表意味着可以直接调用request.user获取当前登录用户,配合@login_required装饰器就能完成页面访问控制。
room字段用SET_NULL并允许为空,对应学生可能还未分配宿舍的状态。这比直接删除学生记录更符合实际——学生退宿时,我们只需要把room置空,保留基本档案。gender字段用choices限定可选值,这个设计在宿舍分配场景中很关键,管理员操作时不会出现非法数据。
2.3 数据库初始化与迁移策略
拿到源码后第一步要处理数据库问题。项目自带的my.cnf配置文件说明它用的是MySQL。在MySQL中创建一个专用数据库,然后在settings.py里修改数据库连接信息:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'dormitory_db', 'USER': 'root', 'PASSWORD': 'your_password', 'HOST': '127.0.0.1', 'PORT': '3306', 'OPTIONS': { 'charset': 'utf8mb4', }, } }这里的OPTIONS中设置utf8mb4而不是utf8,是因为MySQL的utf8字符集最多只支持3字节,而utf8mb4可以完整支持中文和生僻字,同时避免emoji存入时报错。项目里附带了SQL文件,有两种导入方式:一是直接用Navicat或命令行source命令导入,二是删掉SQL文件、改用python manage.py makemigrations和python manage.py migrate重新建表。第二种方式更干净,能确保表结构与模型代码完全同步,但前提是你对模型字段有足够信心;第一种方式适合赶时间交作业的场景。
如果使用migrate方式,还需要先创建超级管理员账号,因为系统依赖Django的User表做登录认证。执行python manage.py createsuperuser按提示输入即可。
3. 核心业务逻辑:从入住分配到退宿全流程实现
3.1 入住登记的视图与表单设计
宿舍管理系统的核心操作之一是入住登记。这套项目用基于类的视图完成这一功能,整体结构比函数视图更清晰。看看views.py中入住登记的实现方式:
class CheckInView(LoginRequiredMixin, View): def get(self, request): form = CheckInForm() return render(request, 'dorm/checkin.html', {'form': form}) def post(self, request): form = CheckInForm(request.POST) if form.is_valid(): student = form.cleaned_data['student'] room = form.cleaned_data['room'] if room.current_people >= room.capacity: messages.error(request, '该房间已满,请选择其他房间') return render(request, 'dorm/checkin.html', {'form': form}) student.room = room student.checkin_date = timezone.now().date() student.save() room.current_people += 1 room.save() messages.success(request, f'{student.name} 入住 {room.building.name}-{room.room_number} 成功') return redirect('dorm:room_list') return render(request, 'dorm/checkin.html', {'form': form})这段代码体现了一个重要原则:业务逻辑中的条件判断不能只依赖前端校验。虽然前端表单会用JavaScript限制用户选择,但恶意请求可以直接POST绕过页面,所以必须在服务端再次检查房间容量。messages框架用来在页面上显示操作结果,这是Django内置的轻量通知机制。
判断和写入操作要放在同一个视图里完成,但这里有一个并发安全的小隐患:两个管理员同时为不同学生分配同一个最后空位时,可能出现超卖。生产环境应该用事务加select_for_update()锁行,教学项目阶段知道这个坑即可。视图中LoginRequiredMixin确保了只有登录用户才能访问该功能,这是类视图和装饰器@login_required的等价写法。
3.2 调宿申请的状态流转设计
调宿是宿舍管理中最繁琐的流程,这套项目的设计思路是把调宿申请做成一张独立表,每次调宿都生成一条申请记录,由管理员审核后才执行真正的宿舍变更。这比直接修改学生宿舍字段要安全,出了差错也有迹可查。
class TransferApplication(models.Model): student = models.ForeignKey(Student, on_delete=models.CASCADE, verbose_name='申请人') old_room = models.ForeignKey(Room, related_name='old_room', on_delete=models.CASCADE, verbose_name='原宿舍') new_room = models.ForeignKey(Room, related_name='new_room', on_delete=models.CASCADE, verbose_name='目标宿舍') reason = models.TextField(verbose_name='调宿原因') status = models.CharField(max_length=10, choices=(('pending', '待审核'), ('approved', '已通过'), ('rejected', '已驳回')), default='pending', verbose_name='审核状态') created_at = models.DateTimeField(auto_now_add=True) processed_at = models.DateTimeField(null=True, blank=True)状态字段status定义了三种取值,这是典型的审批流设计。related_name参数给外键起别名,否则同一个模型有两个指向Room的外键时,Django会因反向查询名称冲突而报错。业务上管理员通过后执行的操作是:新房间的current_people加一、原房间减一、学生表的room字段改到新房间,这三个修改必须放在同一个事务中执行。
在views.py中处理审核动作时需要注意,执行数据变更之前要重新校验新房间的剩余容量,因为申请提交和审核通过之间有时间差,期间新房间可能已经住满。这也解释了为什么不能在学生提交申请时就锁定房间——如果审核不通过,房间资源就白白浪费了。
3.3 水电费统计的数据聚合查询
水电费模块是这套系统里最有含金量的部分,因为它涉及Django ORM的分组聚合查询。每间宿舍按月录入水电表读数,系统自动计算用量和费用。
def bill_summary(request): month = request.GET.get('month', timezone.now().strftime('%Y-%m')) bills = (Bill.objects.filter(month=month) .values('room__building__name', 'room__room_number') .annotate( electricity_usage=F('current_electricity') - F('previous_electricity'), water_usage=F('current_water') - F('previous_water'), total_cost=F('electricity_cost') + F('water_cost') ) .order_by('room__building__name', 'room__room_number')) return render(request, 'dorm/bill_list.html', {'bills': bills, 'month': month})这里的关键在于annotate配合F表达式的用法。F('current_electricity') - F('previous_electricity')在数据库层面完成计算,而不是先把所有记录加载到Python内存里再算,这样数据量大时性能也不会急剧下降。F表达式还能避免并发更新时的竞态条件,因为整个计算过程在SQL语句内部完成。
values('room__building__name')的用法体现了ORM跨表查询的能力,双下划线不是偶然的语法,而是Django约定俗成的跨关系查询语法。这种写法生成的SQL是LEFT JOIN连接了Bill、Room、Building三张表,然后按楼栋和房间分组。如果你在MySQL客户端里开启general_log,可以看到Django ORM自动生成了完整的SQL语句,这也是调试复杂查询的有效手段。
3.4 权限控制与角色管理机制
一个完整的宿舍管理系统必须区分管理员和学生两类角色。这套项目并没有采用复杂的三方权限框架,而是直接在Django的Group权限上做扩展。核心逻辑在decorators.py中:
def admin_required(view_func): @wraps(view_func) def wrapper(request, *args, **kwargs): if not request.user.is_staff: messages.error(request, '需要管理员权限才能访问此页面') return redirect('dorm:index') return view_func(request, *args, **kwargs) return wrapperis_staff是Django User模型自带的字段,标识用户是否有后台管理权限。这里使用函数装饰器实现权限控制,在需要管理员才能访问的视图函数上添加@admin_required即可,代码复用性比在每个视图里写重复判断要好。学生登录后看到的是自己的入住信息和水电账单,管理员的导航菜单则多出宿舍管理、学生管理、账单录入等入口,这种模板上的差异用{% if request.user.is_staff %}标签就能实现,不必维护两套模板。
4. 部署实操:从本地运行到服务端上线的全过程
4.1 本地开发环境搭建与初始启动
拿到这份源码压缩包后,按照以下步骤能让项目快速跑起来。前提是你已经装好了Python 3.8以上版本和MySQL数据库。
# 解压源码包后进入项目目录 cd dormitory_system # 创建虚拟环境(Windows用python -m venv venv) virtualenv venv source venv/bin/activate # 安装项目依赖 pip install -r requirements.txt # 注意requirements.txt里应包含以下核心包: # Django>=3.2, mysqlclient, pillow, django-crispy-forms # 如果mysqlclient安装失败的解决方案见下方说明 # 修改settings.py中的数据库连接 # 创建数据库(MySQL终端执行) CREATE DATABASE dormitory_db CHARACTER SET utf8mb4; # 执行数据库迁移 python manage.py makemigrations python manage.py migrate # 创建超级管理员 python manage.py createsuperuser # 启动开发服务器 python manage.py runserver 0.0.0.0:8000mysqlclient在Windows上安装经常失败,因为它依赖MySQL的C语言客户端库。常见解决方式是到https://www.lfd.uci.edu/~gohlke/pythonlibs/下载对应的whl文件,然后pip install mysqlclient-xxx.whl安装。在Linux服务器上,需要先apt install python3-dev default-libmysqlclient-dev再pip install,这是纯编译依赖问题。
启动项目后访问http://127.0.0.1:8000,用刚才创建的超级管理员登录即可看到后台管理界面。如果页面样式CSS丢失,检查settings.py里的STATIC_URL和STATICFILES_DIRS配置是否正确,以及静态文件目录路径是否与模板中引用的路径一致,这是Django新手最容易踩的坑。
4.2 针对课程设计答辩的关键配置
既然项目定位是课程设计,那你的演示环节最好避开开发服务器各种不稳定的表现。有几个配置值得调整:
| 配置项 | 开发默认值 | 答辩建议 | 说明 |
|---|---|---|---|
DEBUG | True | False | 开启False后错误页面不会暴露代码细节,演示观感更专业 |
ALLOWED_HOSTS | [] | ['*'] | 允许所有主机访问,防止演示时真机访问被拦截 |
TIME_ZONE | UTC | 'Asia/Shanghai' | 时区不正确会导致创建时间与实际不符 |
LANGUAGE_CODE | en-us | 'zh-hans' | 切换Django admin为中文界面 |
把DEBUG设为False之后,静态文件服务方式会发生变化。如果不想配置nginx,可以在urls.py里临时添加静态文件路由,这是开发模式下的简化做法。答辩现场如果用的是自己的笔记本电脑配合手机演示,ALLOWED_HOSTS必须填写*,否则非本机访问会被拒绝。
4.3 生产环境部署:Nginx + uWSGI + MySQL
Gunicorn和uWSGI是Django生产部署的两大主流选择。uWSGI的配置灵活、性能稳定,在技术博客圈子里长期是首选方案。nginx处理静态文件请求,动态请求通过socket转发给uWSGI进程。出一个精简的部署配置:
# uwsgi.ini [uwsgi] chdir = /var/www/dormitory_system module = dormitory_system.wsgi:application master = true processes = 4 threads = 2 socket = 127.0.0.1:8001 vacuum = true daemonize = /var/log/uwsgi/dormitory.log# /etc/nginx/sites-available/dormitory server { listen 80; server_name your_domain.com; location /static/ { alias /var/www/dormitory_system/static/; } location /media/ { alias /var/www/dormitory_system/media/; } location / { include uwsgi_params; uwsgi_pass 127.0.0.1:8001; } }uwsgi_pass通过socket地址与uwsgi进程通信,比使用HTTP端口更高效。启动前先执行python manage.py collectstatic把所有应用内的静态文件集中收集到settings.py指定的STATIC_ROOT目录,否则nginx找不到CSS样式。部署完成后建议测试全面的核心流程——登录、分配宿舍、录入账单,因为生产环境与开发环境的时间处理、静态文件路径都有细微差异。
4.4 常见报错与排查思路
这套项目运行中最常见的故障集中在数据库连接和依赖包版本兼容上。整理了一份高频报错速查表:
| 报错信息 | 原因 | 处理方案 |
|---|---|---|
ModuleNotFoundError: No module named 'MySQLdb' | 未安装mysqlclient | pip安装或安装对应whl文件 |
django.db.utils.OperationalError: (1045, Access denied) | 数据库账号密码错误 | 检查settings.py中的PASSWORD配置 |
NameError: name 'LoginRequiredMixin' is not defined | 未导入django.contrib.auth.mixins | 检查文件头部导入语句 |
TemplateDoesNotExist at /admin/ | 模板目录配置错误 | 确认DIRS或APP_DIRS设置 |
TypeError: __init__() got an unexpected keyword argument 'max_length' | Django版本与代码不匹配 | 确认requirements.txt中的Django版本 |
RuntimeError: Model class apps doesn't declare an explicit app_label | 模型文件结构出错 | 检查apps.py中的配置与INSTALLED_APPS对应关系 |
排查顺序建议是:先确认报错信息对应的模块是否导入成功,再查数据库服务是否正常运行,最后看Django版本与代码的兼容性。版本不匹配是最隐蔽的问题——Django 5.x移除了一些旧版API,如果源码基于Django 4.0以下开发,直接pip install django拉新版本会引发连锁报错,保险的做法是按requirements.txt锁定版本安装。
5. 二次开发与性能优化:让答辩更出彩的三个技巧
5.1 用django-tables2快速生成高颜值数据表格
源码自带的宿舍列表页面如果显得简陋,可以在二次开发阶段用django-tables2库优雅地完成优化。安装库并注册到INSTALLED_APPS,然后在视图里定义一个表格类:
import django_tables2 as tables from .models import Room class RoomTable(tables.Table): building = tables.Column(verbose_name='楼栋') room_number = tables.Column(verbose_name='房间号') capacity = tables.Column(verbose_name='可住人数') current_people = tables.Column(verbose_name='已住人数') class Meta: model = Room template_name = 'django_tables2/bootstrap5.html' def room_list(request): table = RoomTable(Room.objects.select_related('building').all()) table.paginate(page=request.GET.get('page', 1), per_page=10) return render(request, 'dorm/table.html', {'table': table})select_related('building')是ORM性能优化的关键手段,它在生成SQL时直接做LEFT JOIN,把楼栋信息一并查出,避免了模板中每显示一行房间就查询一次Building表的N+1查询问题。N+1查询是Django新手最容易犯的性能错误——表面看不出问题,数据量上来后页面响应会指数级变慢。
生成的表格自带排序、分页功能,模板中只需要写一行{% render_table table %}就能输出完整表格页面。答辩时展示这种带排序分页的列表页,比静态表格更有说服力。
5.2 导出功能:Excel报表的三种实现路径
宿舍管理员经常需要把账单或学生名单导出为Excel文件。实现方式有三种,复杂度递增但功能也越来越丰富。最轻量的是用Django的StreamingHttpResponse直接输出CSV,实现简单但格式受限;中等方案是用openpyxl库生成真正xlsx文件,可以指定单元格样式和合并单元格,适合制作正规报表。项目里已有pandas的话,还能把查询集转换为DataFrame后调用df.to_excel()导出,代码量最少。
以openpyxl方案为例,核心逻辑是创建Workbook对象、写入表头、遍历数据行插入值、设置列宽等。
5.3 答辩演示时的自检清单与加分素材
答辩前按这份清单逐项验证系统功能,能有效避免临场翻车:
# 1. 核心业务闭环手动测试 # 管理员登录 -> 新建楼栋 -> 新建房间 -> 学生入住 -> 录入水电费 -> 生成账单 # 学生登录 -> 查看个人信息 -> 提交调宿申请 -> 管理员审核 -> 确认房间变更 # 2. 数据一致性验证 # 查看房间列表,确认入住人数与房间容量一致 # 在MySQL中执行 SELECT room_id, count(*) FROM dorm_student WHERE room_id IS NOT NULL GROUP BY room_id # 与实际住宿表单据进行对比 # 3. 异常场景模拟 # 为已满房间分配学生,应提示房间已满 # 删除已被引用的楼栋,应阻止操作或级联删除 # 未登录用户直接访问管理页面,应跳转登录页可以在项目里预置一批演示数据,学号带demo_前缀,覆盖已入住、空闲、已满不同状态的房间。答辩时先展示基础数据列表,再做一次完整的入住操作流程,最后调出一张水电费汇总表,整个链路干净利落。这套管理系统的每个设计点都可以作为评分的加分项——外键关系是否明确、查询有没有用select_related、校验逻辑是否完整,这些都是答辩老师最常追问的技术细节。
最后一个值得留意的技巧是写好README说明文档。这份系统的部署步骤、账号信息、核心功能说明都写清楚,放到GitHub上给项目做存档。答辩时老师一般会直接翻阅项目说明文档评估工作量,条理清晰的文档是这套源码除代码之外的第二张加分牌。
本文还有配套的精品资源,点击获取