资讯动态

Python酒店管理系统实战:Django+Flask实现房态订单与报表

发布时间:2026/10/17 2:29:53 来源:尧图企业网站定制
最近用Python做了一套面向中小型酒店的练手项目目标场景是一家30多间客房的商务酒店。动手之前我也以为这种规模的系统很简单几个房间、几份订单能复杂到哪去真正开始梳理才发现小酒店的“小”只是房间数量少业务上的弯弯绕绕一点都不少——钟点房、续住、换房、押金、夜审、维修房态任何一个环节没理顺前台第二天就得掏出纸质登记簿来兜底。这篇文章我把整个项目从需求梳理、框架选型、数据建模到预订入住退房流程、权限报表和部署上线的过程完整过一遍。文章里的思路和代码都直接可复用正在用Python做酒店管理系统、或者想给本地中小型酒店做一套轻量系统的人可以少走几段弯路。1. 需求梳理中小型酒店要的不是大而全是把这几件事理顺每次聊到管理系统最容易犯的错就是一上来列一堆功能清单。我在动手之前先站在酒店前台的角度把一整天的经营活动在心里过了一遍客人打电话问房、现场订房、入住登记、交押金、退房结账、保洁打扫、维修上报……把这些场景吃透之后才敢划需求边界。1.1 先承认小酒店的“小”只是房间数少这里有个反直觉的结论房间越少的酒店业务交叉越密。30多间房的酒店前台通常只有三四个人轮班店长偶尔顶班保洁阿姨还要顺手登记维修事项。这意味着系统不能设计成“每个岗位各干各的”任何一个操作员离开工位另一个人必须能在几十秒内看懂当前房态和待办事项。我梳理下来的核心业务线其实只有四条房态管理、订单管理预订和入住、账务管理押金、房费、消费、统计报表。围绕这四条线做前台的日常工作基本就能闭环。至于那些花哨功能在这个规模下几乎都是累赘。1.2 需求分三层别被“大系统”带跑把需求按优先级分成三层是我在这个项目里觉得最值的决策P0 基础闭环房间与房型管理、房态查询与变更、预订登记、入住登记、退房结账、每日房态总览。这层做不好系统根本没法用。P1 高频但容易漏钟点房计费、续住、换房、押金管理、散客与协议单位区分、简单日报表。这层是前台天天用、但新手开发时最容易忽略的。P2 低优先级复杂会员积分、OTA渠道自动同步、微信提醒、智能门锁对接。这层属于“店长嘴上说说、真上线了也没精力维护”的需求。为什么要砍掉P2因为中小型酒店真正高频使用的是P0和P1复杂会员体系和渠道同步背后往往是另一套商业逻辑硬塞进一个轻量系统里只会拖慢核心功能的开发节奏。做系统最忌讳用“未来可能有需求”来绑架当前的开发周期。1.3 角色权限先定好我一开始就把角色划成三类后面建模和写视图全都照着这个来前台查看房态、开单入住、退房结账、登记押金。不允许改房价、不允许看营收报表。店长/老板看全部报表、调房价、处理房态异常、管理员工账号。保洁/维修只看脏房和维修房清单做完“已清洁”后房态由系统联动回可售。权限这件事最好在建模之前想清楚因为它直接影响数据表的字段设计和接口的返回范围。Django自带的Group和权限系统在后面帮了大忙这部分放到第5章细说。2. 框架选型复盘为什么是Django打底、Flask补位项目标题里同时出现了“python flask django”说明很多人会在这两个框架之间纠结。我做完这个项目后的结论非常明确这两个不是非此即彼的关系至少在这类管理系统里完全可以按边界各管一摊。2.1 Django负责主系统省掉半条开发周期Django对管理类项目最大的价值不是Web框架本身而是那套全家桶ORM自带数据库迁移、自带后台管理界面Admin、自带用户认证和权限分组、自带表单数据处理。这些东西恰好是酒店管理系统最需要的基建不需要拼装。举个实际例子光是房间、房型、订单、账单这几张表的模型定义、迁移脚本、增删改查接口如果全手写两三个星期是跑不掉的。而用Django模型写完后执行makemigrations和migrate直接建表再在admin.py里注册一下就能获得一套能用的管理后台。前台日常的房态维护、订单查询几乎零成本搞定。中小型项目拼的就是交付效率这一点Django优势太明显了。2.2 Flask以极轻的方式切进报价与统计我并没有把整个系统做成纯Django而是把房价计算和统计报表两个模块用Flask单独拆成了两个轻量服务。这样做的原因有两条房价计算规则全天房、钟点房、续住、协议价是改动最频繁的业务拆成独立服务后调整逻辑不用重新部署整个主系统。后面如果要给小程序或者OTA订单接入报价直接调用这个接口就行。统计报表的聚合逻辑比较复杂用Flask写成一个只读接口隔离在业务主流程之外Django那边按需调用职责清晰不会把主系统的代码越堆越乱。这种架构说起来高大上实现起来其实不重Flask服务只有一个app.py、几段路由和几个函数单独起一个进程监听5001端口Django这边用requests库调它。对中小型项目来说这种“轻服务主系统”的组合比一开始就上微服务那套要实在得多。2.3 Flask与Django的选型对照维度DjangoFlask自带Admin后台有开箱即用无ORM与迁移内置且完整需自行选SQLAlchemy并装配权限与认证内置需自行集成学习成本偏高但用料足低但要自己拼组件适合角色业务主系统、后台管理独立小服务、灵活接口、工具脚本本项目角色房态/订单/账单主流程报价计算、统计报表接口做个简单的选型参考如果你的系统要管一堆数据、一堆表单优先考虑Django如果只是某个单一功能对外提供接口或者团队风格偏极简Flask更顺手。两个一起用也不冲突按业务边界拆开就行。3. 数据模型与房间状态机把前台日常翻译成字段数据库设计是这个项目里最需要“先想后写”的部分。前台很多操作换个角度看其实就是改状态、插记录。我把模型迭代了两版才最终定下来这一版我认为最贴近中小型酒店的实际经营模型。3.1 核心模型清单最终我用了六张核心表关系都是简单的外键没有到处建中间表表关键字段用途RoomTypename, base_price, area, capacity房型定义与门市价Roomroom_number, room_type, floor, status房间基础信息与房态Guestname, phone, id_card住客档案方便回头客查询Bookingroom, guest, check_in, check_out, price_type, status预订和入住订单统一放这张表RoomStaybooking, room, start_time, end_time换房/续住产生的实际占房记录Bill / BillItembooking, amount, pay_type, created_at结账主表和明细这里有个刻意为之的设计我没有单独做“入住单”和“订单”两张表而是让Booking兼任。因为中小型酒店的预订和入住基本可以看成一件事的两个阶段——预订是未来日期的占位入住是当下生效。加一个status字段区分reserved / checked_in / checked_out / cancelled就够用了少一张表就少一堆联表查询。3.2 房间状态必须由动作驱动不能让人乱改房间状态是这个项目里最容易被低估的坑。我说的状态不是“空闲/占用”两个布尔字段而是完整的经营状态流转可售房 → 已预订下单后锁定→ 入住中客人办好入住→ 脏房客人退房后待打扫→ 可售房保洁完成“已清洁”除此之外还有维修房。整条流转是一个闭合链必须由系统动作触发下单锁房、入住变占用、退房变脏房、保洁确认变可售。我最担心的就是有人在页面上手动改房态这个口子一开数据三天就乱了。所以手动修改状态的操作权限严格锁给了店长角色。3.3 代码示例Django模型与状态流转from django.db import models class RoomType(models.Model): name models.CharField(max_length50, verbose_name房型) base_price models.DecimalField(max_digits8, decimal_places2, verbose_name门市价) capacity models.IntegerField(default2, verbose_name可住人数) def __str__(self): return self.name class Room(models.Model): STATUS [ (available, 可售), (booked, 已预订), (occupied, 入住中), (dirty, 脏房), (maintenance, 维修房), ] room_number models.CharField(max_length10, uniqueTrue, verbose_name房号) room_type models.ForeignKey(RoomType, on_deletemodels.PROTECT) floor models.IntegerField(verbose_name楼层) status models.CharField(max_length20, choicesSTATUS, defaultavailable, verbose_name房态)第一版建模时我把住客信息全塞进订单里后来发现同一个单位经常同时订多间房、回头客也不少才把Guest拆成独立表。想对读者说的是建模时宁可多写注释也不要在表名上搞太花的设计前台同事不会懂什么叫“订单快照表”。4. 预订、入住、退房全流程实现与踩坑框架和表结构定了真正花时间的反而是几条业务链路。下面按我的实现顺序说这几段也是整个项目里踩坑最密集的地方。4.1 并发防重同一间房为什么会被订两次做第一版时我其实没考虑并发觉得30多间房的酒店前台就几个人怎么也不可能抢同一间房。直到某次测试时两个浏览器同时提交了同一个房号的订单一间房被订出去两次我才意识到“看起来一样”的前台页面背后完全可能有两个请求几乎同时到达服务器。解法是事务加行锁。下订单前先把对应房间记录用select_for_update()锁住让第二个请求等待锁拿到后再判断房态只有available才继续创建订单。这一步很重要所有“判断占位”型操作必须放在同一个数据库事务里锁住行之后第二个请求只能读到第一个请求提交后的最新房态。from django.db import transaction transaction.atomic def create_booking(room_id, guest_name, phone, check_in, check_out): room Room.objects.select_for_update().get(idroom_id) if room.status ! available: raise BookingConflict(该房间当前不可售) booking Booking.objects.create( roomroom, guest_nameguest_name, phonephone, check_incheck_in, check_outcheck_out, statusreserved, ) room.status booked room.save(update_fields[status]) return booking如果没有这把行锁两个请求同时通过if room.status ! available的检查就会各自创建一张订单、把同一间房同时标成booked。这个坑用文字很难复现但一旦出现就是前台和店长都解释不了的脏数据。4.2 房价计算全天、钟点、续住的分段逻辑房价是这个项目里最容易被改需求的模块。我梳理下来中小型酒店常见的计价方式大概四种全天房按“夜”算一般14点后入住、次日12点前退房计入一晚跨多天按每晚价格叠加。钟点房按小时套餐计费比如4小时结算一次超出的部分按钟点加收或转为全天。续住客人不退房继续住通常按当天门市价续费而不是沿用第一晚的协议价。协议价/折扣价长包房、单位协议走固定协议价有时还区分平日和周末。这些规则全写进主系统里会很绕所以用Flask单独做了一个报价接口输入房间类型、基础价格、入住日期、离店日期、是否钟点房返回应收金额和明细分段。from flask import Flask, request, jsonify from datetime import datetime app Flask(__name__) def calc_quote(base_price, check_in, check_out, hourlyFalse): if hourly: hours (check_out - check_in).total_seconds() / 3600 return {type: hourly, hours: hours, amount: base_price * max(1, (hours 3) // 4)} nights (check_out - check_in).days if nights 0: return {error: 离店日期必须晚于入住日期} return {type: daily, nights: nights, amount: base_price * nights, detail: [base_price] * nights} app.route(/api/quote, methods[POST]) def quote(): data request.get_json() check_in datetime.strptime(data[check_in], %Y-%m-%d) check_out datetime.strptime(data[check_out], %Y-%m-%d) return jsonify(calc_quote(float(data[base_price]), check_in, check_out, data.get(hourly, False)))这段代码看着简单实际我写了快三小时主要时间耗在“钟点房跨天”“续住跨天”“4小时套餐超过怎么加收”这些边角规则上。建议写代码前先把计价规则用表格列出来找店长逐条确认开发到一半被改需求才是最痛苦的。4.3 退房结账与换房续住的处理细节退房结账表面上是“客人退房收钱”背后其实要做三件事根据入住期间的房价和消费生成账单、把房间状态改为脏房、把订单状态更新为已退房。收款不能强求一次性结清因为有客人是入住时交押金、退房时才多退少补。我的做法是Bill表里记录应收、实收、押金抵扣三个字段押金单独立账。财务对账时一眼能看出每个订单的押金状态不会出现“客人退了房、押金还在账上挂着”的情况。换房是最容易写乱的功能。我的方案是把换房等价成“旧房间先退房、新房间重新入住”两个动作同时保留RoomStay记录里真实的起止时间段这样入住的统计才准确。续住则刚好反过来先检查目标日期对应房间是否可用再做订单check_out延期同时重新按门市价计算差额。这里一定要给“调整房价”留操作日志店长半夜接到续住电话第二天要对账时最需要的就是这条记录。5. 权限控制、报表统计与部署上线5.1 用Django自带的Group做权限隔离前面第1章说好的权限问题在这里收口。Django的认证和权限分组是现成的我创建了三个组前台组、店长组、保洁组。前台组只能访问订单、房态、客人的列表和新增修改接口店长组可以访问全部包括价格调整、报表、账号管理保洁组只有房态更新那几条接口。Django严格说是“组权限位”的模式我给每个视图加上permission_required装饰器或者用LoginRequiredMixin约束就能保证登录但没有权限的用户访问不了关键页面。有一点提醒不要图省事给所有同事开超级管理员账号。这个项目里前台流动率高账号权限越开放越难控制误操作的影响范围。Django后台里把Admin地址改成非默认路径再配合组权限能挡住绝大多数低级失误。5.2 入住率、ADR和营收报表的计算口径报表统计是我踩坑最多的模块。最典型的坑是入住率的口径有人直接把“当前有多少房间是occupied”当成入住率这在房间少的时候勉强能看但只要有维修房、脏房数字就明显不对。我最终用的是“间夜入住率”口径统计区间内已售间夜数 ÷ 可售间夜数。可售间夜要排除维修房已售间夜按每个订单在区间内实际覆盖的天数累加。配合ADR平均房价和RevPAR每间可售房收入两个指标店长看一眼报表就能判断当天要不要做促销、今天的经营状况到底如何。def room_revenue(start, end): bookings Booking.objects.filter( check_in__ltend, check_out__gtstart, status__in[checked_in, checked_out] ) sold_nights 0 revenue 0 for b in bookings: overlap_start max(b.check_in, start) overlap_end min(b.check_out, end) nights (overlap_end - overlap_start).days if nights 0: sold_nights nights revenue b.room.room_type.base_price * nights return sold_nights, revenue这段只是示意真实项目里我会把房价、折扣、钟点房金额统一汇总到Bill表再用Bill表做统计避免重复计算。报表页面我用Django模板渲染一个简单的后台页面支持按日、按月切换并导出CSV给店长做账完全够用。5.3 部署心得Gunicorn Nginx 备份部署环境我用了一个很小的云主机主系统用Gunicorn起Django报价接口单独起一个Gunicorn监听另一个端口Nginx做反向代理。整个过程按下面几步走两小时内能在新服务器上跑起来# Django 主服务 pip install gunicorn gunicorn hotel_manage.wsgi:application -w 4 -b 127.0.0.1:8000 # Flask 报价服务 gunicorn quote_service:app -w 2 -b 127.0.0.1:5001server { listen 80; server_name your-domain; location /api/quote { proxy_pass http://127.0.0.1:5001; } location / { proxy_pass http://127.0.0.1:8000; } }静态文件用collectstatic收集后交给Nginx直接serve。备份这块我是吃过亏的某个测试环境的数据被我手滑清空当天的订单记录全没了。现在的方案很简单每天凌晨用cron跑一次数据库备份SQLite就直接复制文件PostgreSQL就用pg_dump保留最近7天同时系统日志滚动保留30天。中小型酒店数据量不大备份策略越简单越容易长期执行。6. 复盘与建议再做一次我会怎么改项目做完我给自己列了一份心得与其说是系统亮点不如说是一份避坑清单先花时间看业务流程再动手写代码。站在开发者角度想功能和站在前台角度想功能得出的系统完全是两个样子。房态这种强状态字段必须用动作触发流转宁可多写几个函数也不要开放手工修改入口。价格和报表逻辑尽量独立成小服务或独立模块它们是改动最频繁、也最容易影响主流程的地方。备份、日志、权限三件事从第一天就要做不要等到上线前再补。如果再让我做一次我会在一开始就把“协议单位”和“散客”的计费差异建模进数据库而不是后面靠补丁方式处理。也会考虑给店长做一个简单的移动端入口毕竟很多小酒店店长不在店里的时间更多手机上能看房态和报表的需求是真实存在的。最后分享一个实操体会中小型酒店管理系统最难的不是技术而是把模糊的业务规则翻译成确定的流程。每一个看似简单的功能比如“换房”“续住”背后都藏着前台少跑路、账目对得上的深层需求。代码写不快没关系业务逻辑理不顺后面一定会返工。要是让我用一个词总结这个项目我会说先理顺前台的日常再谈系统的架构。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑