ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python+Django校园宿舍管理系统开发全解析:从数据库设计到核心功能落地

Python+Django校园宿舍管理系统开发全解析:从数据库设计到核心功能落地 前几天有个学弟在群里吐槽他们宿舍楼还靠纸质表登记换寝辅导员月底要数据统计到半夜。他说想做个“校园学生宿舍管理系统”当课设又不知道该用啥技术栈、数据库怎么设计、从哪下手。这场景我太熟了每年都有一批人被这种管理系统类项目卡住业务看着简单真做起来表格一多、状态一多就乱套。这篇文章就把我用 Python Django 做的一套校园学生宿舍管理系统完整拆开讲一遍包括系统选型、数据库表结构、核心功能实现、常见坑位排查。项目自带源码、数据库脚本和配套文档适合正在准备课程设计、毕业设计或者想在公司内部搞一套宿舍/公寓管理小工具的同学参考。文章尽量从“拿到需求之后怎么思考”开始讲而不是直接甩代码这样你做完之后不只能交差还能跟答辩老师把逻辑讲清楚。1. 项目选型与整体设计思路拆解1.1 为什么用 Django 而不是 Flask 或 Spring做一个宿舍管理系统本质上是典型的 MIS管理信息系统项目增删改查、登录认证、权限控制、数据报表几乎没有复杂算法和高并发场景。这种场景下 Django 是最合适的选项原因有三个。第一Django 自带 ORM不用写一行 SQL 就能完成大部分建表和查询工作。第二Django 内置 Admin 后台基础数据录入阶段几乎零开发量。第三Django 自带用户认证体系登录、会话、权限校验都有现成方案。对比一下Flask 灵活但需要自己拼装太多东西Spring Boot 当然也能做但学习成本高对课设和毕业设计来说时间成本不划算。打个生活化的比方Django 像精装修交付的样板间Flask 像毛坯房Spring Boot 像从头设计别墅。做宿舍管理这种功能边界清晰的系统直接选样板间是效率最高的路径。1.2 数据库表结构设计先把业务关系捋清楚动手写代码之前建议先画一张业务关系图。宿舍管理系统的核心离不开这几件事学生住哪个楼哪个房间哪个床位、报修工单怎么流转、访客进出怎么登记、晚归考勤怎么统计。围绕这些业务我把表拆成了六张核心表。楼栋表Building和房间表Room是一对多关系房间表和床位表Bed是一对多关系。学生表Student和用户表User是一对一关系当前床位作为外键关联到床位表。这里要特别强调学生和床位之间必须留一个入住记录表CheckinRecord用来保存历史入住和迁出记录不能只存一个“当前床位”字段就完事。否则换寝之后历史数据全部丢失查不到“这个学生大一住过哪栋楼”这种审计信息。报修工单表RepairOrder至少要有这几个字段报修人、房间、报修内容、状态、提交时间、处理人、完成时间。状态字段建议用整数或短字符串保存配合字典映射展示中文比如0表示待受理1表示处理中2表示已完成3表示已关闭。访客登记表VisitorRecord重点记录访客姓名、证件号、被访学生、进入时间和离开时间。晚归考勤表AttendanceRecord记录学生、日期、状态状态常见取值是正常、晚归、未归。设计原则只有一条能拆的表尽量拆别把几十个字段堆在一张表里。我见过有人把所有信息全部塞进一个 model光字段就四十多个结果查询、维护全是灾难。1.3 项目目录与 App 模块划分Django 项目天然支持多 App 结构宿舍管理系统按业务边界拆 App 是最清晰的方式。我的建议是拆成这几个模块accounts用户登录、角色管理、个人资料。building楼栋、房间、床位的基础数据管理。students学生档案、入住分配、换寝退寝。repair报修工单的提交、派单、处理和统计。attendance晚归考勤记录与统计报表。visitor访客登记与查询。notice公告通知的发布和展示。整个项目的目录结构大概长这样dormitory_manager/ ├── manage.py ├── config/ # 项目配置目录 │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── accounts/ ├── building/ ├── students/ ├── repair/ ├── attendance/ ├── visitor/ ├── notice/ ├── static/ # 静态文件目录 ├── media/ # 上传文件目录 └── templates/ # 全局模板目录很多新手习惯把所有页面逻辑堆在同一个 App 的views.py里写着写着文件就几千行了。按业务拆 App 表面上看是多写几个文件实际上每个模块的代码都在隔离地演进改报修模块不会误伤考勤模块团队协作时也基本不会冲突。1.4 用户角色与权限控制方案宿舍管理系统的用户角色大体分三类系统管理员、宿管员、学生。不同角色能看到的菜单和能执行的操作完全不同。Django 自带的 User 模型提供了is_staff、is_superuser和is_active字段但这只能解决“能不能进后台”的问题解决不了“宿管员能不能给学生分宿舍、学生能不能给自己换床位”这种细分权限问题。实际项目中我给 User 增加了一个一对一关联的Profile扩展表在里面加一个role字段取值分别是admin、manager、student。视图层用装饰器判断角色例如from django.contrib.auth.decorators import user_passes_test def is_manager_or_admin(user): return user.is_authenticated and user.profile.role in [admin, manager] user_passes_test(is_manager_or_admin) def assign_room(request): # 仅管理员和宿管员可执行 pass模板层配合判断显示或隐藏入口{% if request.user.profile.role manager %} a href{% url assign_room %}分配宿舍/a {% endif %}如果后续想做得更规范化可以用 Django 自带的Group和Permission做完整的 RBAC。但对课设和内部小工具来说Profile 加角色字段的方案已经够用代码简单、逻辑直白答辩时反而更好解释。2. 核心功能模块解析与实操要点2.1 学生入住与宿舍分配的业务逻辑学生入住是整个系统的业务起点。新生入学时管理员需要批量导入学生信息并分配宿舍老生调宿时则需要先退宿再重新分配。这块业务的关键在于床位状态的判断一个床位只有“空闲”状态才能被分配分配成功后要立即置为“已占用”。分配逻辑看起来简单但有个并发场景必须考虑最后一张空闲床位同时被两个学生抢。解决方法是查询空闲床位时使用数据库行锁Django 里可以用select_for_update()实现from django.db import transaction with transaction.atomic(): bed Bed.objects.select_for_update().filter(statusfree, room__building__gendermale).first() if not bed: raise ValueError(当前没有符合条件的空床位) bed.status occupied bed.save() # 创建入住记录和更新学生档案这个细节在课程设计答辩时讲出来老师会明显感觉到你不是直接抄代码而是真的考虑过实际问题。对应到生活场景就是“抢最后一张下铺”的并发问题数据量不大但逻辑必须严谨。批量导入学生信息时我一般提供一个 CSV 模板下载功能管理员按模板填好后再上传服务端解析并逐条校验数据。比手工一条条录入效率高很多。2.2 报修工单的状态流转设计报修模块是宿舍系统里被使用频率最高的功能之一因为它是典型的“用户提交—管理员处理—用户确认”闭环。状态流转我建议设计成四个状态待受理、处理中、已完成、已关闭。提交报修时学生选择房间号和故障类型填写描述系统自动记录提交时间。宿管员看到待受理工单后把状态置为“处理中”同时指派维修师傅。维修完成后把状态置为“已完成”学生可以查看处理结果。如果工单因特殊原因无法处理则置为“已关闭”但要记录关闭原因。在代码实现上状态变化最好写成一个统一的方法避免在多个视图里散落赋值逻辑class RepairOrder(models.Model): STATUS ( (pending, 待受理), (processing, 处理中), (completed, 已完成), (closed, 已关闭), ) ... def transition_to(self, new_status, operator): allowed { pending: [processing, closed], processing: [completed, closed], completed: [closed], } if new_status not in allowed.get(self.status, []): raise ValidationError(f状态不能从 {self.status} 变更为 {new_status}) self.status new_status self.processor operator save()这个方法的优势是状态变更规则集中管理不会出现“从已完成改回待受理”这种非法流转。实际做的时候可以在管理员端加一个“最近一周报修工单处理时长统计”用created_at和completed_at的差值计算作为宿管效率考核的参考。2.3 晚归考勤与统计报表实现晚归考勤数据有两个来源一是门禁系统对接二是宿管员人工录入。手动录入场景下宿管员按楼栋选择日期批量标记每个学生的就寝状态系统自动生成统计报表。数据模型建议用“日期 学生 状态”这样一行一条记录而不是把整个宿舍楼的学生状态拼在一行里否则后续按日期查询、按学生汇总都很难受。class AttendanceRecord(models.Model): student models.ForeignKey(Student, on_deletemodels.CASCADE) record_date models.DateField() status models.CharField(max_length10, choicesSTATUS_CHOICES) # normal/late/absent class Meta: unique_together (student, record_date)统计报表这部分值得多说一句。宿舍管理员最关心的是“这个月哪个楼层晚归次数最多”学生辅导员最关心的是“某个学生最近有没有连续晚归”。这需要按不同维度聚合查询Django 的 ORM 聚合方法可以解决from django.db.models import Count # 按日期维度统计全楼晚归人数 AttendanceRecord.objects.filter( record_date__month11, statuslate, student__room__building_id1 ).values(record_date).annotate(totalCount(id))报表展示用图表会比表格直观很多前端接一个轻量的 ECharts 或 Chart.js只需要返回 JSON 数据就行。这一步工作量不大但对整个项目的观感提升非常明显。2.4 访客登记与安保联动考虑访客登记以前都是纸质登记本字迹潦草、信息不全、事后难查。线上访客登记模块应该支持宿管员录入访客信息和被访学生记录进入时间离开时再登记离开时间。字段至少包括访客姓名、证件号码、联系电话、被访学生、事由、进入时间、离开时间。这个模块看起来简单但要注意提醒学生和宿管员“离开登记”是必要步骤。如果只记录进入不记录离开访客是否还在楼内完全无法掌握。可以加一个状态字段进入时是in离开时改成out。首页或安保端可以展示“当前楼内未离开访客列表”这才是宿舍管理系统安全价值的体现。2.5 公告发布与学生端首页宿舍管理系统不只是管人的工具也是信息发布的渠道。停电通知、查寝通知、维修公告这些都应该通过系统推给学生。公告的核心字段是标题、内容、发布人、发布时间、是否置顶。学生登录后首页显示最近的五条公告列表页展示全部公告。这块功能工作量不大但我建议放在项目里因为它的作用是让系统看起来是“完整闭环”的学生有事情可看、管理员有地方发消息互动感一下就出来了。3. 从零实操环境搭建到核心功能落地3.1 Python 环境准备与 Django 项目创建先说结论Python 版本建议用 3.10 或 3.11Django 版本建议用 4.2 LTS。新版 Django 对 Python 3.12 的支持在个别第三方库上可能还有兼容问题用 4.2 LTS 最省心。环境准备阶段继续用虚拟环境隔离依赖python -m venv venv # Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate pip install django4.2然后创建项目和 Appdjango-admin startproject config . python manage.py startapp accounts python manage.py startapp building python manage.py startapp students python manage.py startapp repair创建完 App 后先别急着写代码打开config/settings.py把新 App 注册进INSTALLED_APPS再配置数据库连接。开发阶段我推荐直接用 SQLite零配置、文件型数据库跑起来没有障碍。演示和答辩也完全够用。如果要部署到生产环境再切换到 MySQL只需要改settings.py里的数据库配置并跑一次迁移即可。项目文档里有现成的 MySQL 建库脚本和连接配置说明。3.2 核心数据模型的代码实现直接展示几个核心模型。这里用简化的代码实际字段可以根据自己的业务再扩充。# building/models.py class Building(models.Model): name models.CharField(楼栋名称, max_length50) gender models.CharField(楼栋性别属性, max_length10, choices((male,男生),(female,女生))) class Room(models.Model): building models.ForeignKey(Building, on_deletemodels.CASCADE, related_namerooms) room_number models.CharField(房间号, max_length20) class Bed(models.Model): room models.ForeignKey(Room, on_deletemodels.CASCADE, related_namebeds) bed_number models.CharField(床位号, max_length10) status models.CharField(状态, max_length10, choices((free,空闲),(occupied,已占用)), defaultfree)# students/models.py class Student(models.Model): user models.OneToOneField(User, on_deletemodels.CASCADE) student_no models.CharField(学号, max_length20, uniqueTrue) real_name models.CharField(姓名, max_length30) gender models.CharField(性别, max_length10) major models.CharField(专业, max_length50) current_bed models.OneToOneField(Bed, on_deletemodels.SET_NULL, nullTrue, blankTrue, related_namecurrent_student) class CheckinRecord(models.Model): student models.ForeignKey(Student, on_deletemodels.CASCADE) bed models.ForeignKey(Bed, on_deletemodels.CASCADE) checkin_date models.DateField(auto_now_addTrue) checkout_date models.DateField(nullTrue, blankTrue)写完模型后执行迁移python manage.py makemigrations python manage.py migrate这里有个心得related_name一定要自定义至少别用默认的student_set这种名字。自定义名字如rooms、beds之后查询代码可读性会好很多。项目附带的数据库脚本里已经把这些关系都建好了你也可以直接导入现成的 SQLite 库文件省去手动建表的过程。3.3 Admin 后台快速录入基础数据很多新手一上来就写页面其实浪费了大量时间。Django Admin 的价值在项目初期就能体现出来把 Admin 配好录入基础数据根本不用做前端页面。# building/admin.py from django.contrib import admin from .models import Building, Room, Bed admin.register(Building) class BuildingAdmin(admin.ModelAdmin): list_display (name, gender) admin.register(Room) class RoomAdmin(admin.ModelAdmin): list_display (building, room_number) admin.register(Bed) class BedAdmin(admin.ModelAdmin): list_display (room, bed_number, status) list_filter (status, room__building)录入数据最烦的是“一栋楼有六层每层二十个房间每间四个床位”手工点几百次谁受得了。建议写一个 Django management command 批量生成床位在项目文档里我也附带了这段脚本执行python manage.py generate_beds --building男生1号楼 --floors6 --rooms_per_floor20 --beds_per_room4一次跑完直接生成 480 个床位记录。这种自动化思路放到答辩里也能加分说明你意识到真实数据录入的痛点。3.4 Django 模板页面与分页搜索基础数据进系统之后就可以开始写学生端和管理端的页面了。页面我直接用 Bootstrap 5 加 Django 模板语言搞定不引前端框架简单直接。以学生列表页为例需要支持按学号、姓名、楼栋条件搜索并且分页展示# students/views.py from django.core.paginator import Paginator from django.db.models import Q def student_list(request): kw request.GET.get(kw, ) building_id request.GET.get(building, ) students Student.objects.select_related(current_bed__room__building).all() if kw: students students.filter(Q(student_no__icontainskw) | Q(real_name__icontainskw)) if building_id: students students.filter(current_bed__room__building_idbuilding_id) paginator Paginator(students, 20) page paginator.get_page(request.GET.get(page)) return render(request, students/list.html, {page_obj: page})模板里就按照 Django 模板语言来渲染循环和分页控件。这里提醒一个新手经常踩的坑select_related用来优化外键查询只要列表页会展示关联表字段就应该加。不加的话每渲染一行数据都会额外触发几条 SQL页面一慢就成了恶性循环。3.5 学生名单导出 Excel 的实现管理员最喜欢的功能是“一键导出”。我把导出功能放在每个列表页右上角按当前搜索条件导出 Excel。用openpyxl实现生成xlsx文件。from openpyxl import Workbook from django.http import HttpResponse def export_students_xlsx(request): wb Workbook() ws wb.active ws.title 学生名单 ws.append([学号, 姓名, 性别, 专业, 楼栋, 房间, 床位]) for stu in students: ws.append([...]) response HttpResponse(content_typeapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet) response[Content-Disposition] attachment; filenamestudents.xlsx wb.save(response) return response需要注意的坑如果用 CSV 模块导出并且包含中文一定要指定编码为utf-8-sig否则 Excel 打开是乱码。这个问题项目文档的常见问题章节里也单独写了。用 Excel 文件格式则可以绕开编码问题。4. 常见问题与排查技巧实录4.1 数据库相关的高频问题宿舍管理系统虽然简单但数据库相关的坑一点不少。我整理了实际开发中最高频的几类。时区警告是新手最常见也最容易忽略的报错。启动服务时出现RuntimeWarning: DateTimeField received a naive datetime原因就是settings.py里USE_TZ默认是True而写入的时间没有时区信息。简单方案是把USE_TZ设为False同时设置TIME_ZONE Asia/Shanghai。如果坚持要用时区那就所有时间都调用django.utils.timezone.now()别混用。迁移文件报错也很常见。有些同学手动删过migrations目录或者误改过模型字段导致makemigrations提示“检测到模型改变但没有迁移文件”。处理方法比较稳妥的是保留migrations目录如果开发阶段数据不重要直接删数据库重新migrate。项目文档里附带的数据库脚本就是为了这种场景准备的。另外从 SQLite 切到 MySQL 时有些字段类型会有隐含差异比如BooleanField在 SQLite 里存 0/1MySQL 里也是 tinyint问题不大。真正容易出问题的是中文排序和连接字符集。MySQL 连接参数务必加OPTIONS: {charset: utf8mb4}否则中文容易乱码。4.2 静态文件与模板加载问题开发环境里页面样式加载不出来十有八九是STATIC_URL或STATICFILES_DIRS配置问题。模板里写link relstylesheet href{% static css/app.css %}前提是templates或静态文件目录路径正确。有个很容易被忽略的细节DEBUGTrue时 Django 能自动服务静态文件DEBUGFalse时静态文件必须交给 Nginx 或其他 Web 服务器处理。很多同学本地跑得好好的一放到服务器上样式全丢就是这个原因。解决方案是在项目文档里写了 nginx 静态文件目录映射的配置示例照着配就行。模板路径报错则通常是settings.py里TEMPLATES的DIRS没有配置BASE_DIR / templates。Django 的模板发现机制是先查 App 下的templates目录再查DIRS配置的目录两层都可能被使用理解了这个顺序排查起来就快了。4.3 登录与权限常见问题很多宿舍系统里学生账号是管理员手动创建的初始密码统一设置比如身份证后六位或者固定密码123456。这里要注意创建用户时密码必须用set_password不能直接存明文。正确写法user User.objects.create_user(usernamestudent_no, password123456, first_namereal_name)另一个经典问题login_required装饰器会自动跳转到登录页但登录后跳回原页面的逻辑依赖next参数。如果登录表单里没有带上next用户每次登录后都会固定跳到首页。实现登录视图时要把request.POST.get(next)一起带回响应。权限判断的坑更多体现在模板上。模板里用request.user.is_authenticated判断登录状态没问题但不要用request.user.is_staff判断业务角色因为is_staff只代表“能不能进Admin后台”不是业务含义。业务角色始终以profile.role为准前后端判断要保持一致。4.4 快速排查速查表下面这张表是我做这套系统时整理的常见问题速查项目文档里有完整版本这里列最关键的几条。现象可能原因解决办法页面报 404 且样式全丢静态文件配置错误检查 STATIC_URL / STATICFILES_DIRSAdmin 登录后无操作权限用户权限未配置给用户添加 is_staff 或分配菜单权限时间字段保存报 naive datetime 警告USE_TZ 与本地时间混用统一 USE_TZFalse 用系统时间中文导出乱码CSV 编码错误使用 utf-8-sig 或导出 xlsx列表页查询慢外键查询未优化补 select_related / prefetch_related登录后跳转不对未处理 next 参数登录视图里原样返回 next图片/头像上传失败media 目录不可写配置 MEDIA_ROOT 和 url换寝室后历史查不到未写入住记录表换寝时必须写 CheckinRecord这张表的含金量在于每一条都是真实跑过的坑。很多问题搜搜索引擎也能找到答案但往往分散在零散的帖子里集中在文档里就能大幅缩短排查时间。做这套系统前后改了三版最深的体会是宿舍管理这种项目技术难点真的不多难的从来都是把业务规则想清楚、把状态流转设计好、把数据抄底的思路做对。只要前期把表结构设计好后期写代码会顺很多。最后分享一个我个人的实操习惯先把 Admin 后台配好把楼栋、房间、床位这些基础数据录进去再从学生端视角开始写页面。这个顺序和教科书里“从前往后做”不太一样但实际效率高很多因为你要是连基础数据都看不到页面长什么样凭空写出来的列表、筛选、详情多半都要返工。
返回列表