ARTICLE DETAIL

资讯详情

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

会议室预约系统源码:Django后端调度与微信小程序实战

会议室预约系统源码:Django后端调度与微信小程序实战 简介这是一套完整的微信小程序会议室预约系统源码前端为微信小程序后端基于Django框架面向企业、机关单位或需要内部会议室管理的团队帮助快速搭建线上预约、查询、审批等功能。系统包含管理员与普通用户视角适合用作毕业设计、课程项目或企业二次开发基础。压缩包以zip格式提供大小约750KB共含106个文件文件类型涵盖Python后台代码、JavaScript交互逻辑、JSON配置文件、WXML页面结构及WXSS样式表也包含少量图片和说明文档目录组织规范便于按模块阅读。目前已有2154人参与下载学习。通过这份源码读者可以了解小程序与Django服务端对接的完整流程包括接口设计、数据模型搭建、页面渲染等关键环节直接部署后即可运行演示。资源内附环境配置文件和基础页面素材对希望快速上手小程序开发或Django后端开发的初学者同样具有参考价值。1. 一套能直接改的会议室预约源码后端调度逻辑比界面更值钱做企业信息化相关工作的同行大概率都遇到过会议室预约需求看起来只是给前台加个排期表真接需求后才发现难的不是界面而是同一个时间段的会议室不能重复预约临时取消后时间片怎么释放。这套微信小程序会议室预约系统微信小程序Django服务端后台源码把小程序端和 Django 服务端后台源码都放进了一个包里前端负责选会议室、挑日期时间、提交预约后端负责房间维护、预约校验和管理员介入。想找一份能跑的微信小程序项目实例可以直接把它当作可运行骨架来拆开放预约、资产借用、活动室预定都能在同样的调度模型上改。后端自带配置样例和源码本地能起服务直接调试。2. Django 服务端源码骨架配置分层、数据模型与初始化2.1 从 local_settings.py.default 看多环境配置源码包里出现local_settings.py.default说明项目采用“公共配置 本地覆盖”两层写法。settings.py保存所有开发环境一致的配置比如 app 列表、中间件、模板路径local_settings.py放机器相关的差异项比如数据库连接串、SECRET_KEY、DEBUG是否开启。local_settings.py.default则是提交到仓库里的模板记录本地配置需要哪些字段团队新成员加入时复制改名即可。cp local_settings.py.default local_settings.py python manage.py check --deploy复制命令之后紧跟check --deploy是用来在启动业务前做一次静态巡检。它会输出当前配置中不安全的地方例如DEBUGTrue、ALLOWED_HOSTS缺失、SSL 配置不足。注意这只是一个参考检查并不代表检查通过就是生产级安全至少能帮你少踩DEBUGTrue直接暴露堆栈信息的坑。常见配置项的作用如下表表格里的字段在复制模板后基本都要过一遍配置项所在文件作用SECRET_KEYlocal_settings.py签名会话与密码重置令牌不能公开DEBUGlocal_settings.py调试模式生产环境必须为 FalseALLOWED_HOSTSsettings.py允许访问的域名列表DATABASESlocal_settings.py数据库类型、地址与账号TIME_ZONEsettings.py影响日期时间字段的存储与展示这套拆分逻辑在稍大一点的 Django 项目里非常常见换一台机器部署时只需要改local_settings.py公共配置不会因为个人环境差异被污染git 冲突也会少很多。2.2 会议室与预约的 Django 数据模型核心业务涉及两个模型Room 和 Reservation。Room 描述资源本身Reservation 描述人和会议室在某时间段的关系。“关系”这个词是关键预约的本质不是一条简单记录而是一个带时间边界的状态对象。from django.db import models from django.contrib.auth.models import User class Room(models.Model): name models.CharField(max_length64, uniqueTrue) capacity models.IntegerField(default10) location models.CharField(max_length128, blankTrue) is_active models.BooleanField(defaultTrue) class Reservation(models.Model): room models.ForeignKey(Room, on_deletemodels.CASCADE, related_namereservations) user models.ForeignKey(User, on_deletemodels.CASCADE) date models.DateField() start_time models.TimeField() end_time models.TimeField() title models.CharField(max_length128, blankTrue) status models.CharField(max_length16, defaultconfirmed) created_at models.DateTimeField(auto_now_addTrue)room_id外键保持资源与预约的关联删除会议室时on_deletemodels.CASCADE会连带删除预约如果业务要求保留历史建议改成PROTECT让管理员先处理历史记录再删会议室。date用DateField、时间用TimeField模型层直接约束了格式就不会出现“2025/01/18”和“2025-01-18”混存的脏数据。is_active用来下架房间而不是删除比如装修中的会议室可以临时不展示。status字段没有用choices写死虽然灵活但后台录入容易出错建议至少补上CHOICES常量约束。需要扩展业务模块时用python manage.py startapp新建一个独立 app 放周边功能保持这个主流程的模型表结构单一。2.3 setup.cfg 与页面资源工程规范说明setup.cfg在源码包里的作用是统一开发约束常见内容包括flake8的最大行宽、忽略规则以及isort的导入排序方式。多人提交代码时行宽和导入顺序不一致会产生大量无谓 diff有了统一配置代码评审的关注点才能落在业务逻辑上。.gitattributes则控制行尾符Windows 上常见的 CRLF 不会在提交时污染整个文件。源码包里的error.html是自定义错误页模板。Django 默认的 404/500 页面比较简陋而且可能暴露调试信息把error.html通过handler404、handler500绑定后访客看到的是友好说明线上环境也能少泄露堆栈细节。几张 jpg 图片1.jpg、3.jpg、5.jpg是会议室轮播图或演示截图room_demo.jpg更像某个会议室的示例图。Django 惯例是把这类静态资源放在static/目录按static/rooms/路径分目录比全部堆在根目录好维护。2.4 初始化命令把后端跑起来拿到源码后按下面的顺序把服务端启动。先建虚拟环境再装依赖避免把系统 Python 环境弄乱。cd django_server python -m venv venv source venv/bin/activate pip install -r requirements.txt cp local_settings.py.default local_settings.py python manage.py makemigrations python manage.py migrate python manage.py createsuperuser python manage.py runserver 0.0.0.0:8000依赖清单一般是requirements.txt如果包内换成了pyproject.toml用pip install -e .安装即可。makemigrations根据当前模型生成迁移文件migrate把迁移应用到数据库改过模型字段之后这两条命令必须重新执行。createsuperuser创建 Django admin 的管理员账号会议室和预约记录的维护都在 admin 里做。runserver 0.0.0.0:8000是为了让小程序开发者工具或同一局域网真机访问到后端如果只在本机调试直接python manage.py runserver更省事。3. 预约冲突检测时间段重叠判断与 Django ORM 查询写法3.1 重叠区间的判定条件同一个会议室能否被预约唯一需要严格判断的就是时间区间是否重叠。一段时间由start_time和end_time两个端点确定两个区间存在交集的条件是已有预约的开始时间早于新预约的结束时间并且已有预约的结束时间晚于新预约的开始时间。existing.start_time new.end_time existing.end_time new.start_time以 10:00-12:00 的已有预约为例新预约 09:30-11:00 在两个条件上都成立确实冲突新预约 12:00-13:00 不满足第一条12:00 12:00 为假说明只留下背靠背的衔接时段。大多数会议室系统都允许这种排列因为两场会议在物理上并不重叠。真正要警惕的是跨天预约如果模型里只有date字段、没有结束日期跨天场景就需要额外设计比如拆成两段子预约。3.2 用 Django ORM 写重叠查询与状态过滤冲突判断放在前端不可靠前端禁用按钮不代表绕过请求就不能提交必须放在 Django 视图或 service 层里做二次校验。from .models import Reservation def is_conflict(room_id, date, start_time, end_time, exclude_idNone): qs Reservation.objects.filter( room_idroom_id, datedate, status__in[confirmed, pending], start_time__ltend_time, end_time__gtstart_time, ) if exclude_id: qs qs.exclude(idexclude_id) return qs.exists()这段查询里datedate把范围缩到同一天status__in[confirmed, pending]只考虑有效预约cancelled和completed不参与占用start_time__ltend_time与end_time__gtstart_time对应上一节的两个不等式。注意参数顺序新预约的end_time和start_time作为比较值不要写成反方向否则重叠判断会变成包含判断。exclude_id用于修改预约时间用户在已有一条预约的情况下改期校验时要排除自己那条记录否则永远与自身冲突。如果未来要支持多人同时抢同一个时段还需要把查询放进transaction.atomic()并配合select_for_update()锁住已查到记录避免两个请求同时通过校验单机开发阶段可以暂不考虑。3.3 取消、删除与过期处理预约取消和记录删除是两件不同的事。用户取消后后台依然需要看到这条历史了解谁在什么时候约过又取消所以用状态更新而不是删行。# 用户取消保留记录释放时间片 Reservation.objects.filter(idresv_id, userrequest.user).update(statuscancelled) # 管理员清理真正删除 Reservation.objects.filter(idresv_id).delete()update()是 QuerySet 层面的批量更新不走模型实例的save()方法所以如果模型里重写了save()做审计日志这里不会被触发需要审计时改成先get()再修改实例字段后save()。.delete()会触发DELETESQL记录一旦删除后台筛选和统计都会少掉一条非必要不调用。过期预约的常见处理方式是状态流转为completed。要注意过期只适用于“预约日期早于今天”或“预约日期是今天且end_time已过当前时间”的记录不能简单把所有带start_time的记录都清掉因为未来时段的预约仍然有效。这个判断写成管理命令后用定时任务每天跑一次。status含义是否占用时间片confirmed已确认占用pending待审核占用cancelled用户取消不占用completed已结束不占用3.4 admin 后台配置与查询界面默认 admin 列表也能看全部预约但会议室一多就难用。定制list_display、list_filter和search_fields可以很快定位问题数据。比如某天哪几间会议室被谁占了用date_hierarchy的日期层级下钻最快。from django.contrib import admin from .models import Reservation admin.register(Reservation) class ReservationAdmin(admin.ModelAdmin): list_display [room, date, start_time, end_time, user, status] list_filter [date, room, status] search_fields [user__username, title] date_hierarchy datelist_display里的room和user是外键Django 默认显示对象的__str__如果没有定义友好的__str__列表页会显示成Room object (1)非常难读。建议在模型里给Room.__str__返回self.name给User用它的username。list_filter字段越多页面加载越慢date、room、status三个维度已经覆盖大多数排查场景。admin 界面美化优先级不高先把字段和筛选逻辑做对再考虑换主题皮肤。4. 小程序端对接 Django API登录态、请求封装与表单提交4.1 小程序端目录结构与页面职责原生微信小程序的页面按目录组织每个页面目录下包含.wxml、.wxss、.js、.json四个文件。以这套系统为例典型页面是会议室列表、会议室详情和我的预约app.js里做全局登录初始化app.json注册所有页面路由这属于搭建微信小程序的流程中最基础的结构规范。页面间通过wx.navigateTo跳转详情页从列表页接收room_id作为参数。Django 端不使用模板渲染页面只提供 JSON API。小程序端所有数据来自wx.request所以这里天然是前后端分离架构。用 HBuilderX 改造同样适用uni.request的调用方式与wx.request基本一致保留utils/request.js这一层封装原生页面迁到 uni-app 时只需要替换请求单体业务逻辑不用重写。4.2 封装 utils/request.js 并携带会话凭证小程序没有浏览器的 Cookie 概念身份信息一般放在请求头里。登录后后端返回 token前端存到本地缓存之后每个请求都带上。const BASE_URL https://your-domain.example/api; function request(path, method GET, data {}) { return new Promise((resolve, reject) { wx.request({ url: ${BASE_URL}${path}, method, data, header: { Content-Type: application/json, Authorization: Bearer ${wx.getStorageSync(token) || }, }, success: (res) { if (res.statusCode 200) { resolve(res.data); } else if (res.statusCode 401) { wx.removeStorageSync(token); reject(res); } else { reject(res); } }, fail: reject, }); }); } module.exports { request };这段封装的要点在于getStorageSync(token)从本地缓存读取会话凭证没登录时为空字符串后端返回 401 时主动清掉 token避免后续请求反复带一个失效凭证。Promise包装让业务层可以用async/await写调用比层层嵌套success回调好读很多。如果后端把所有业务结果都包在{ code, msg, data }里再把res.statusCode 200的条件改成res.data.code 0通用性更好。BASE_URL在开发期可以指向局域网 IP比如http://192.168.x.x:8000/api联调阶段不用每次改代码。提示wx.login()拿到的code是一次性的有效期很短。应当把它立即传给 Django 后端由后端换取会话身份而不是在小程序端缓存code。4.3 提交预约的表单参数与日期格式化会议室详情页通常会有日期选择和时间段选择。微信原生picker组件返回的值是字符串不要把datetime混在一起传。后端DateField解析YYYY-MM-DDTimeField解析HH:mm这是最省事的配合。const payload { room_id: currentRoom.id, date: e.detail.value.date, // 2025-01-18 start_time: e.detail.value.time, // 14:30 end_time: calcEndTime(14:30, 60), // 15:30 }; request(/reservations, POST, payload) .then(() wx.showToast({ title: 预约成功, icon: success })) .catch(() wx.showToast({ title: 该时段已被约, icon: none }));calcEndTime的时间计算建议统一用分钟数累加把HH:mm转成总分钟数加上时长后再转回字符串。直接用字符串拼接会遇到 14:30 60 分钟等于 15:30 这类进位问题也有 23:30 跨到次日 00:30 的边界。如果业务不允许跨天计算后要判断结果日期是否还是当天否则直接报错提示用户重新选时段。传参后端的room_id必须来自详情页路由参数或接口返回不要信任前端自行构造的数字后端视图里要再用Room.objects.filter(idroom_id, is_activeTrue)校验会议室存在且有效。4.4 与后端 API 对应的接口清单接口路径方法参数说明/api/auth/loginPOSTcode小程序 code 换取 token/api/roomsGET无可用会议室列表/api/reservationsPOSTroom_id, date, start_time, end_time创建预约/api/reservationsGETdate 可选查询我的预约/api/reservations/{id}/cancelPOST无取消预约/api/auth/login的流程是小程序wx.login()拿到 code传给 DjangoDjango 调用微信接口换取openid再用openid找到或创建本地用户最后签发一个业务 token 返回前端。这个 token 可以存成 Django 的Token模型也可以用 JWT 自包含签名。源码包如果已实现其中一种尽量保持原实现如果登录还没实现建议先做最简单的 token 表不要一上来就上 JWT调试成本更低。5. 从源码跑通到上线域名配置、mysqlclient 与数据落库排查5.1 小程序请求 Django 服务端的域名配置本地开发时微信开发者工具可以打开“不校验合法域名”选项让http://127.0.0.1:8000直接可用。真机预览和正式上线时这个开关无效必须到小程序管理后台的开发设置里登记服务器域名。域名需要是https路径按/api/这样配置。真机预览首次报request:fail时优先检查这一步而不是改代码。这个排查顺序能省下大量时间。5.2 mysqlclient 在 Linux 上的安装本地用 SQLite 跑通后线上部署大多换 MySQL。Django 连 MySQL 时最常卡在mysqlclient编译失败错误信息一般指向mysql_config找不到。apt install default-libmysqlclient-dev build-essential pkg-config pip install mysqlclientdefault-libmysqlclient-dev提供 MySQL 客户端头文件build-essential提供编译工具链pkg-config让mysql_config能被正确找到。缺少这三个pip install mysqlclient就会在编译阶段报错。装完依赖后再安装再把DATABASES里的ENGINE从sqlite3改到django.db.backends.mysql并填写生产数据库地址、账号和端口。5.3 判断预约是否真的写进数据库小程序端提示“预约成功”但后台列表看不到记录时先确认是写库失败还是查看位置不对。用终端直接查库最直接sqlite3 db.sqlite3 select id, room_id, date, start_time, end_time, status from appname_reservation; python manage.py shell -c from app.models import Reservation; print(Reservation.objects.count())表名由 app 名加模型名拼接比如 app 叫meeting表就是meeting_reservation不确定时先执行python manage.py showmigrations确认模型对应的表。线上 MySQL 换成SELECT id, room_id, date, start_time, end_time, status FROM meeting_reservation;在客户端里执行。计数条数比预期少再翻 Django 日志看有没有IntegrityError多半是外键或唯一约束被命中。本文还有配套的精品资源点击获取
返回列表