ARTICLE DETAIL

资讯详情

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

房屋租赁管理系统实战:Flask、Django与微信小程序解析

房屋租赁管理系统实战:Flask、Django与微信小程序解析 手上几套房子的房东最头疼的往往不是买不起房而是“租出去之后那一堆破事”。空调坏了、水管漏了租客一个电话甩过来你人在公司开会还得临时翻通讯录找维修师傅月底算房租、水电、押金、保洁费Excel表翻得眼花记错一笔就是几百块的窟窿。这套基于Python Flask、Django和微信小程序的房屋租赁管理系统就是冲着这两个痛点去的租客用小程序的报修入口提交故障房东在后台收到工单、指派维修、跟踪闭环另一侧系统把租金、水电、押金、维修人工费这些应收应付账目扎进账本模型里月底自动出账单、定时催缴哪套房赚了哪个租客逾期了一行SQL就能查清楚。这套系统适合谁参考一种是刚入行的Python开发想找一个能放上简历的完整项目练手把Flask和Django两个框架前后端串起来另一种是确实在运营几套房的二房东或公寓管家想用最低成本把报修流程和财务台账管起来。下文我会按真实项目的开发顺序拆解先讲设计和选型再讲报修工单与应收应付两个核心模块的建模逻辑然后落到微信小程序端的踩坑记录最后给出一套能直接在服务器上跑的部署方案和问题排查表。全程手写代码级别的实操细节不含糊。1. 项目整体设计与技术选型思路模块化是这套系统能跑通的第一步。整个系统拆成三端租客端微信小程序、运营端Web管理后台、以及中间的业务API层。租客只关心“报修是否被受理”“账单该交多少钱”运营者关心“工单在执行流程的哪一步”“本月应收多少、实收多少”。前端和后端之间的所有数据交互都走JSON接口小程序端不做业务逻辑只做界面和交互这样后续如果要把租客端改成App或公众号H5后端代码一行都不用动。1.1 核心模块与业务闭环先框定范围这套系统最初的业务闭环是三条线第一报修闭环。租客在小程序提交报修填问题类型、文字描述、图片后台生成一张报修单状态为“待指派”管理员把它指派给维修师傅或自己接单状态变为“维修中”师傅上门修完回传处理结果和费用状态变为“待验收”租客确认没问题工单完结。整个流程里每一次状态变化都要留时间戳和操作人方便以后扯皮时翻记录。第二应收闭环。以房屋为单位建账每月根据合同约定的租金和抄表读数的水电费自动生成该套房当月的应收账单租客账单缴清后账单状态变为“已结清”。所有实收流水按日期记入收款台账支持部分付款和押金抵扣。第三应付闭环。维修产生的费用不是房东自己掏腰包就完事系统要把每一笔维修费挂到对应的报修单和维修师傅名下月底汇总出“本月应付给师傅多少钱”供应商采购比如批量购买门锁、灯泡也走同样的应付台账。应收应付分开记月底对账才不会乱。1.2 为什么用Flask Django双框架而不是只选一个很多新手会问标题里又是Flask又是Django是不是重复造轮子实际上这两个框架在这个项目里各司其职没有重叠。Django在这个系统里承担“重活”因为它自带ORM、Admin后台、迁移机制和完整的用户认证体系。像房屋、租客、合同、报修单、账单这些实体之间有大量外键关联Django的ORM写起来又快又稳Admin后台也省了自己写基础增删改查页面的大量功夫。Flask这边承担的全是“小工具型”服务而且都是可以独立运行的轻量模块支付回调的接收与验签服务、定时扫描租约并生成账单的任务服务、Excel对账导出的文件生成服务。这些功能如果全塞进Django项目的manage.py里会让主项目变得臃肿不说支付回调和定时任务一旦崩溃还会拖累主业务。把Flask单独跑在另一个端口通过HTTP内部接口和Django通信用挂了重启独立的进程就行不影响主业务接口。这也是实际SaaS项目里常见的BFF模式Backend For Frontend的简化版Flask作为聚合层负责和微信服务器、第三方支付打交道Django专注核心业务模型。选型时还有一点考量是团队能力。如果是单人开发Flask和Django的语法并不冲突模型定义和视图函数的学习成本在两个框架之间大概有70%是互通的一个会Django的开发者在一周内就能上手Flask的轻量服务。反而用双框架可以逼着自己把“业务逻辑”和“工具逻辑”的边界划清楚不会写到后面变成一个大泥球。1.3 数据库模型与权限设计数据模型这块我建议直接参考实际业务表结构来建不要过度设计。核心表就八张房间表rooms房产信息房间号、地址、面积、户型、当前状态空置/已租/维修中。租客表tenants姓名、手机号、微信号、身份证号、紧急联系人。租赁合同表contracts外键关联房间和租客起止日期、月租金、押金、水电费结算方式、合同状态。报修单表repair_orders外键关联房间和租客问题类型、描述、图片路径、指派师傅、状态、费用、完成时间。账单表bills外键关联合同账单类型租金/水电/押金、金额、周期、状态待缴/部分缴纳/已结清/逾期、截止日期。收款记录表payments外键关联账单收款方式、金额、收款时间、操作人。应付单表payables外键关联报修单或供应商收款人金额应付日期状态未付/已付。维修工表repairmen师傅姓名、手机号、服务类型、结算方式。权限上不用自己造轮子Django自带用户组和权限机制直接在User上扩展一个用户类型字段就够了。运营端和管理员端走Django Admin租客和小程序的登录单独用JWT做接口鉴权角色判断放在中间件里。做法是把Django的User作为主用户表租客、维修工、管理员都是User的不同类型租客登录后拿到的token里带上user_id和role每个API接口在视图层校验角色权限。注意创建模型的时候涉及金额的字段一律用DecimalField不要用FloatField。楼层、电费表读数这类也尽量用DecimalField或IntegerField。Float在Python里精度会漂移账单计算中出现几分钱对不上的问题会让你Debug到怀疑人生。2. 故障报修模块从用户提交到维修工单闭环报修模块是整个系统里交互最频繁、最容易出线上问题的部分因为它的参与方有三方租客、管理员、可能存在的维修师傅。三方各自的流程判断必须清晰不然就会出现“租客报修了管理员以为师傅已经修了师傅根本不知道有这单”的混乱局面。2.1 报修单的状态机设计先定义状态状态机是这个模块的地基。我用一个字符字段来表示但为了方便查询直接存成字符串常量待指派pending租客提交后进入等待管理员处理。此时租客在小程序里只看到“等待响应请保持电话畅通”。待接单assigned已经指派给维修师傅。分两种情况如果团队只有管理员自己维修可以直接跳过这一步如果有外部师傅需要师傅端确认接单。内部用的版本直接把这两个状态合并成“维修中”外部版本才拆开。维修中repairing师傅上门可能产生维修费用此时租客不需要做任何操作。待验收completed工单记录维修结果等待租客确认。这是一个容易忽略的节点——很多系统修完就完事了但租客被返修问题折磨过几次之后就再也不信任这个系统了。所以必须保留租客确认环节租客在24小时内不确认自动视为验收通过。已取消canceled和已关闭closed管理员取消错误工单或者历史工单做归档。状态变更必须留存日志。Django里可以加一个简单的RepairLog表字段就是repair_order外键、from_status、to_status、operator、create_time。这个表有两个作用排查“谁把单子弄丢了”时把状态流转拉出来哪一步卡住了清清楚楚以后做数据复盘时也能算出平均响应时长和平均维修时长优化运营。流转规则用Django的signal或者直接在视图层判断都可以我的建议是用一个常量字典定义合法流转路径ALLOWED_TRANSITIONS { pending: [assigned, canceled, repairing], assigned: [repairing, canceled], repairing: [completed, canceled], completed: [closed, repairing] }视图层在做状态更新之前先检查这一步不合法直接返回400避免脏数据。2.2 报修接口设计与图片上传处理租客在小程序提交报修接口长这样POST /api/repair_orders/请求体 { room_id: 12, issue_type: electric, description: 空调不制冷开了半小时只出热风, images: [https://cdn.example.com/repair/xxx.jpg] }后端接收后要做四件事第一校验租客身份和合同状态。如果这个租客的合同已过期或者房间状态不是已租直接拒绝不然会出现退租的人还在报修的情况。第二图片处理。这里是个典型坑点微信小程序的wx.uploadFile会把图片传到你自己的服务器然后返回一个URL。不要在Django的视图里接收base64编码的图片小程序转出来的base64会非常大HTTP请求体动不动几MBDjango默认的DATA_UPLOAD_MAX_MEMORY_SIZE是2.5MB直接拒绝请求。正确做法是小程序先通过wx.chooseMedia选择图片然后调用wx.uploadFile上传到Flask文件服务Flask把图片存到本地或者对象存储返回URL小程序再把这个URL放到报修请求体里。Flask文件服务的一个简单示例from flask import Flask, request import uuid import osapp Flask(name) UPLOAD_FOLDER /data/media/repair ALLOWED_EXTENSIONS {png, jpg, jpeg, webp}app.post(/upload) def upload(): file request.files.get(file) if not file or file.filename.split(.)[-1].lower() not in ALLOWED_EXTENSIONS: return {code: 400, msg: file type not allowed} ext file.filename.split(.)[-1].lower() filename f{uuid.uuid4().hex}.{ext} file.save(os.path.join(UPLOAD_FOLDER, filename)) return {code: 0, url: fhttps://media.example.com/repair/{filename}}文件名一定要用uuid重命名不要用用户原始文件名。你永远不知道用户会上传一个“房间照片.jpg”还是“恶意脚本.php”重命名能从根源上杜绝一部分路径穿越和注入风险。第三生成报修单号。格式建议BX 年月日 三位序列号比如BX20250315001。这个单号要展示在小程序界面租客报修后凭这个号查询进度比拿数据库主键ID有安全感得多。第四触发通知。向管理员的小程序或者公众号发送新工单提醒。这里用微信的订阅消息subscribe message最合适因为订阅消息可以在用户点击确认后一次性下发不需要长期保持长连接。如果管理员端是浏览器那才考虑WebSocket实时推送。2.3 维修指派与消息通知的实时推送热搜词里有“python django websocket实现后台有数据前端推送”在报修场景里这正是刚需。管理员打开后台的工单列表页不可能刷新一次看一眼必须有新单进来就在页面上弹一个气泡提醒。Django本身不支持WebSocket需要借助channels。django channels的实现思路并不复杂核心就是用channel layer做进程间通信Redis是默认的channel layer后端。配置好channels之后在消费器里监听websocket连接当管理员连上ws://yourdomain/ws/notifications/前端浏览器一直保持这个连接。业务逻辑里产生新工单时往指定channel group发一条消息消费器就把消息推到前端。用Redis做channel layer还有个副产物Flask的定时任务服务也能往这个group推送消息。比如账单生成完毕Flask脚本通过Redis publish一条消息Django channels的consumer把消息转发给在线管理员。整个推送链路就打通了。实际开发中配置channels比写业务代码麻烦得多。几个容易踩的坑第一路由文件ASGI必须正确配置普通HTTP接口也要通过ASGI应用处理否则WebSocket升级协议会失败第二部署时不能用gunicorn直接跑channels要换daphne第三如果用了Nginx需要在location块里显式加上代理WebSocket的请求头否则浏览器一直停留在CONNECTING状态。这些到第5部分部署章节再展开。前端收到新工单推送后要做的是从“今天待办”列表里加载新数据不要直接在推送消息里带完整业务数据只带工单ID前端自己去查避免消息内容被篡改造成数据展示不一致。3. 应收应付模块房东的账本怎么算清楚如果说报修模块是系统的手脚那应收应付模块就是大脑系统有没有价值就看这块做得细不细。很多房屋管理系统能做报修工单但财务台账一塌糊涂月底还是得回到Excel手工对账。这里我用的是会计上“应收应付台账分离”的思路每一笔钱款在应收侧记一笔账在实收侧记一笔账通过账单状态关联起来同样的在应付侧记一笔账在实付侧记一笔账通过应付单状态关联起来。两侧永远不混在一起报表才能分得清。3.1 账务模型应收、实收、欠款、押金先说不容易算明白的几个模型设计。应收账单bills是核心。一张账单一定归属于一份合同因为租金、水电费都是跟合同绑定的。账单类型一般有三种租金、水电、杂费保洁费、维修材料费。每张账单要有自己的唯一编号格式可以考虑FY 年份月份 房间号例如FY2025031201方便月底人工核对时一眼看出是哪个月的哪个房间。账单状态用五个状态未出账only draft、待缴unpaid、部分缴纳partial、已结清paid、逾期overdue。未出账是财务做账用的中间状态比如系统自动生成下个月的账单但还没确认金额管理员审核后再批量置为待缴。这样做的原因是水电费每月不确定必须依赖抄表读数确认。押金不走账单押金是单独的台账。租客交押金时记押金收入表退租时根据房屋损耗情况从押金里扣除应扣款项剩余押金退还。这里要设计一个“押金抵扣单”退租时每一笔扣除都要注明原因关联到对应的报修单或照片否则租客事后找你要押金你解释不清楚。欠款的计算逻辑一个合同下所有应收账单中未结清金额的总和就是欠款。这个字段不需要单独存查询时用聚合函数实时算出来就行。3.2 账单生成与逾期提醒的定时任务设计账单生成的逻辑要在月底跑一次批处理遍历当前有效合同判断本月的账单是否已经生成没有就按合同金额生成有就不重复生成。这里最容易出的问题就是重复生成账单。如果定时器写得不严谨比如任务在凌晨跑的时候服务器刚好重启重启后任务又跑了一遍租客就会在同一个月收到两笔房租账单。我的做法是在账单表加一个unique_together约束合同ID 账单月份字段数据库层面杜绝重复比任何代码判断都可靠。逾期提醒同样是一个定时任务每天早上扫描所有待缴账单如果超过截止日期给租客推送一条订阅消息提醒。要注意的是微信订阅消息只能在下发后模板保持可用状态时发送租客可能拒绝接受订阅消息所以还要同步发一条短信。短信接口可以用阿里云或腾讯云的短信服务单价几分钱成本不是问题。定时任务我建议放在Flask服务里用APScheduler实现而不是用系统的cron。原因是如果用cron你需要额外处理Python环境的加载问题而APScheduler是纯Python解决方案跑起来就一个进程依赖管理跟Flask主服务一致。一个简单的配置from apscheduler.schedulers.background import BackgroundSchedulerscheduler BackgroundScheduler() scheduler.add_job( generate_monthly_bills, triggercron, daylast, hour2, minute0, timezoneAsia/Shanghai ) scheduler.add_job( scan_overdue_bills, triggercron, hour9, minute0, timezoneAsia/Shanghai ) scheduler.start()记得在generate_monthly_bills成功跑完后要写一个日志文件记录批次编号和生成数量。后期如果发现账目对不上能快速定位是哪一次生成任务出了问题。3.3 Excel对账导出与微信支付回调对账导出这个功能看似简单其实最好用Flask来写独立服务。因为Django项目静态文件和媒体文件通常部署在Web服务器内部导出Excel如果要发给管理员需要先把文件生成到临时目录再返回下载链接。Flask这里天然适合把导出逻辑做成一个独立接口Django的业务代码通过requests调用它Flask生成好Excel文件后把文件路径返回给Django异步任务去处理处理完上传到文件存储再推送一个通知给管理员。导出表格的字段我建议这样设计每个Sheet放一个业务维度账单导出表放账单编号、房间号、合同编号、租客姓名、费用类型、金额、状态、截止日期收款记录表放收款流水号、对应账单号、收款时间、金额、支付方式应付表放应付单号、关联报修单号、收款人、金额、状态、付款日期。列头用中文方便运营同事直接看。关于微信支付回调这是应收模块落地时一定要处理的部分。租客在小程序里点“去交房租”其实是调用微信支付统一下单接口拿到支付的prepay_id之后小程序再拉起微信支付。支付成功后微信服务器会向你的支付回调地址POST一个XML里面带着商户订单号和微信支付单号。支付回调地址建议放在Flask服务里因为它的签名验签逻辑和Django主业务的耦合度越低越好。收到回调之后流程是先校验签名和金额确认是有效支付然后根据商户订单号找到本地账单把状态更新为已结清最后向微信返回“SUCCESS”应答。这里的一个经验是回调处理一定要做幂等微信可能会在极端情况下重复推送回调所以更新账单状态的SQL一定要带条件UPDATE bills SET statuspaid WHERE bill_no? AND status!paid避免重复更新导致流水重复记账。4. 微信小程序端多角色入口与开发要点租客端小程序和管理后台虽然同属一套系统但界面设计和使用场景差异很大。租客端必须极简打开小程序看到的是“我要报修”和“我的账单”两个大按钮不需要有多余的运营信息干扰。管理员端的小程序反而可以稍微丰富一点因为管理员需要在手机上快速处理工单、查看财务概览。4.1 小程序页面结构设计我把小程序分成四个Tab页面首页顶部显示当前租房状态包括房间号、房屋状态、距租约到期还有多少天下面两个入口大卡片报修和账单。报修页单选故障类型水电、门窗、家电、燃气、其他填写描述上传现场图片提交后展示工单编号。账单页默认展示当前待缴账单点击进入账单详情包含费用明细和缴费按钮。我的个人资料、历史报修记录、合同信息、联系房东。报修页的故障类型用微信小程序的radio单选组件就能实现热搜词“微信小程序单选框”就在这里派上用场。要注意radio组件的样式在iOS和安卓端表现有差异建议直接用view icon手搓一个可点击的卡片列表选中态用边框和背景色表示样式可控体验更好。4.2 顶部导航栏高度与安全区适配这个坑几乎每个做小程序的人都要踩一遍微信小程序在不同机型上顶部导航栏高度完全不同。iPhone 14 Pro的灵动岛区域和不带刘海的安卓机状态栏高度可能相差几十像素。如果你的页面布局用了fixed定位一不小心内容就会被状态栏盖住。我的解决办法是在页面的onLoad里读取微信提供的全局数据动态计算顶部占位高度const { statusBarHeight } wx.getWindowInfo() this.setData({ statusBarHeight })然后在页面wxml中给顶部区域加一个padding-top绑定这个值。不要试着自己用getSystemInfoSync之类的接口不同基础库版本返回结构有差异wx.getWindowInfo是官方长期稳定支持的接口从基础库2.20.1之后就一直可用。另外热搜词里“微信小程序设置缓存时间”也值得说一句如果你把用户登录态token写在storage里一定要设置合理的过期时间。微信小程序的storage不主动清的话是永久保留的如果token过期了你没有清理逻辑用户点进去还是显示登录成功状态等接口返回401的时候才跳登录体验很差。我推荐在request封装层统一拦截401发现token过期就清除storage并且跳转到登录页重新拿code不要在每一个页面单独处理。4.3 小程序中的图片上传与下载图片上传前面已经提了流程这里补几个细节小程序上传图片用wx.uploadFile它的name参数要和服务端Flask接收字段名保持一致我用的是file上传前一定要限制图片大小小程序端调用wx.compressImage压缩一遍服务端再做一次大小校验两个闸门都过了才允许落盘。热搜词“微信小程序中的视频下载”虽然不是本系统的功能点但有一个相关场景报修时有时候用户想上传一段视频来更清楚地展示故障现象比如空调异响的声音、漏水的位置。视频上传比图片更折腾一是体积大二是微信小程序的视频压缩能力有限。我的建议是第一版先只支持图片上传视频需求用文字描述替代等系统稳定了再加。报修的核心是快速定位问题不是收集多媒材料。4.4 场景小程序端框架选择与工程化技术选型上如果你已经在Django那边写了模板渲染的管理后台小程序可以考虑用uni-app一套代码可以编译成微信小程序、H5和iOS/Android应用方便以后扩展。但如果只在微信生态里运营原生小程序就够了不用引入额外框架带来的编译层调试成本。这个系统里我建议原生实现因为页面数量和逻辑复杂度都不高原生开发文档全、社区案例多遇到问题好查。工程化方面小程序也要分包。把报修流程页面报修提交、报修详情、工单进度拆成一个分包把账单缴费页面拆成另外一个包主包只放Tab页。这样冷启动加载的主包体积变小首次打开更快。热搜词“微信小程序游戏开发”里很多方案并不适用于工具型小程序但分包加载的思路是通用的值得借鉴。5. 环境准备、部署与常见问题排查系统做完了代码写得再漂亮部署不上线就等于零。这一章从零开始讲环境搭建和服务器部署按我现在生产环境的标准来不说虚的。5.1 开发环境准备与依赖管理开始写代码之前先建好Python虚拟环境。用venv不需要额外安装命令如下python3 -m venv venv source venv/bin/activate pip install --upgrade pip依赖写在requirements.txt里。我按实际项目列一份基础的Django4.2.* djangorestframework3.14.* django-cors-headers4.0.* channels4.0.* channels-redis4.2.* daphne4.0.* Flask3.0.* APScheduler3.10.* requests2.31.* gunicorn21.2.* pymysql1.1.* cryptography41.0.*注意Django版本别用太新的Django 5虽然已经发布但channels和daphne对它的支持有时会有滞后。生产环境选4.2是当前最稳的搭配。数据库我用MySQL生产环境不用SQLite的原因是SQLite在高并发写入场景下有锁竞争报修工单更新频繁的时候会出现database is locked。开发阶段用SQLite没有关系但切生产时一定要换MySQLDjango的ORM让你切换数据库只需要改settings里的配置这一步不会有太多工作量。安装MySQL后建好数据库记得utf8mb4编码否则中文存储或emoji会出现乱码和索引长度报错CREATE DATABASE rent_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;5.2 服务器部署Nginx Gunicorn Daphne 的组合生产环境的进程管理我用supervisor它能把Django的Gunicorn进程和Flask进程都管起来崩溃了自动拉起。整个部署架构分三层Nginx监听80和443端口处理SSL证书和静态文件把API请求转发到Gunicorn跑Django把WebSocket请求转发到Daphne跑Channels把Flask服务单独放在8081端口Nginx将特定路径转发过去。Gunicorn的启动参数注意一个关键点Django项目如果用了channels就不能只用gunicorn承载所有流量。正确做法是让gunicorn处理常规HTTPdaphne处理WebSocket升级和HTTP长连接。gunicorn的配置示例gunicorn rent_system.wsgi:application -w 4 -b 127.0.0.1:8000 --timeout 60Daphne启动daphne -b 127.0.0.1 -p 8001 rent_system.asgi:applicationNginx里的WebSocket代理需要特别配置这段配置是从实际项目中抠出来的直接能用的程度map $http_upgrade $connection_upgrade { default upgrade; close; }server { listen 443 ssl; server_name yourdomain.com;location /ws/ { proxy_pass http://127.0.0.1:8001; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header Host $host; } location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /flask/ { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; } location /static/ { alias /var/www/rent_system/static/; expires 7d; }}这里最大的坑是如果不配置Upgrade相关headerWebSocket连接在Nginx这一层就会被拦截前端一直显示连接状态后台也没有报错。排查半天最后发现是Nginx的header没带过去。5.3 高频报错与排查速查表这部分是实际开发和上线阶段最常遇到的问题我整理成一张速查表照表排查能省很多时间问题现象可能原因解决办法小程序request请求报“url not in domain list”小程序后台没有配置合法域名登录微信公众平台把接口域名加到request合法域名本地开发可以用“不校验合法域名”调试真机必须正式配置Django Admin打开显示“DisallowedHost”settings里ALLOWED_HOSTS没配上域名或IP编辑settings.py加上你的服务器IP和域名WebSocket一直连接不上浏览器显示pending状态Nginx没有配置Upgrade头或者Daphne端口未启动按上文配置好map和location并用netstat确认8001端口在监听上传的图片在页面显示403访问图片的域名和服务端域名不在一个域下静态文件权限问题检查Nginx对media路径的访问权限以及对象存储的防盗链配置Flask服务报“Address already in use”上次启动的进程没杀干净lsof -i:8081 找到进程kill后重启Django迁移时报“table already exists”手工在数据库改了表结构迁移记录不一致不破坏数据的前提下先执行python manage.py makemigrations --empty再执行migrate --fake实在不行备份后重建微信支付回调收不到请求支付接口配置的回调URL不是公网可访问地址回调URL必须是https且域名已备案不能用IP地址小程序iOS静音状态下音频播放无效微信小程序默认静音策略在audio组件上配置sessionCategory需要后台音频需求或在页面上明确展示打开声音的指引最后补一个高阶经验Django项目上线后千万不要直接改生产数据库表结构。任何字段变更都走migrations流程在测试环境验证后再上线。我们这个项目上线后有一次因为紧急加字段我在生产库手动ALTER TABLE结果和迁移文件冲突导致后续migrate直接报错折腾了大半天才恢复。生产环境的任何结构变更都不值得省那十分钟的“捷径”。6. 后续扩展方向与个人体会系统跑起来之后可以扩展的方向其实很多。我实际规划过的有这几个报修工单的数据统计分析根据工单类型和房间号做聚合分析哪类故障最高发哪个片区维修成本最高用图表展示在管理后台。这项不用写复杂的算法Django ORM的aggregate和annotate足够搞定。租赁合同到期的自动预警租约到期前30天、15天、7天分别推送提醒给管理员和租客管理员可以提前发布房源或续签租客有充足时间决定去留。后台定时任务已经在跑账单了加一个合同预警的逻辑只是多一分钟的事。水电表读数的OCR识别租客每个月上传水电表照片系统自动识别读数并生成账单。这个可以用现成OCR接口做但要注意读数照片的清晰度和仪表类型电动车牌式电表的识别率不高的时候要允许人工修改。应收账款的信用评分根据租客的历史付款习惯和报修频次生成一个简单的信用分辅助管理员决策续租时候的押金政策。这个模型不需要多复杂把逾期次数、平均逾期天数、报修响应情况几个指标加权算出来就行。最后分享一点体会做这类业务系统最难的不是代码而是把业务规则问清楚。比如押金能不能抵扣最后一个月租金维修费超过多少钱需要租客确认水电费是阶梯价还是固定价这些问题如果开发前不确认开发完再改逻辑成本是翻倍的。我这次最深的教训是应收模块的“部分付款”功能一开始没考虑租客会只交一半房租的情况结果账单状态只有“待缴”和“已结清”上线第一周就有租客打电话说转了一半房租系统显示未缴只好连夜加了一个“partial”状态。前期多花半小时和业务方对一遍异常分支后期能少熬几个通宵。这也是给所有正在做管理系统开发的朋友一句实打实的建议先把流程走一遍再写第一行代码。
返回列表