ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Flask开发医院预约挂号系统实战指南

Flask开发医院预约挂号系统实战指南 1. 项目概述最近用Flask框架开发了一套医院预约挂号系统主要解决传统医院挂号排队时间长、号源管理混乱的问题。这个系统实现了患者在线预约、医生排班管理、管理员数据统计等核心功能已经在本地医院试运行了3个月日均处理预约量超过200人次。系统采用PythonFlask作为技术栈主要基于以下考虑Flask轻量灵活适合快速开发中小型Web应用SQLAlchemy提供的ORM能简化数据库操作Jinja2模板引擎学习成本低与Flask集成度高整体架构简单后期维护成本低2. 系统架构设计2.1 技术选型后端框架Flask 2.0.1优势微内核设计、扩展性强、文档完善关键扩展Flask-WTF表单处理、Flask-Login认证、Flask-SQLAlchemyORM前端技术基础模板Jinja2内置于Flask静态资源Bootstrap 5 jQuery 3.6交互增强AxiosAJAX请求数据库MySQL 8.0生产环境/SQLite开发环境选择依据MySQL适合高并发场景SQLite便于开发测试2.2 三层架构设计表示层Templates ↑↓ 业务逻辑层Flask Views ↑↓ 数据访问层SQLAlchemy Models典型请求流程用户访问URL → 2. Flask路由匹配视图函数 → 3. 视图调用模型查询数据 → 4. 渲染模板返回响应3. 核心功能实现3.1 患者模块3.1.1 预约挂号流程app.route(/make_appointment, methods[GET, POST]) login_required def make_appointment(): if request.method POST: # 获取表单数据 doctor_id request.form.get(doctor_id) time_slot request.form.get(time_slot) # 冲突检测 if Appointment.query.filter_by(doctor_iddoctor_id, time_slottime_slot).first(): flash(该时间段已被预约, error) return redirect(url_for(doctor_list)) # 创建预约 new_appoint Appointment( patient_idcurrent_user.id, doctor_iddoctor_id, time_slotdatetime.strptime(time_slot, %Y-%m-%d %H:%M), statuspending ) db.session.add(new_appoint) db.session.commit() # 生成预约号规则科室首字母日期序号 appoint_no f{new_appoint.doctor.department[:2]}{time_slot[:10].replace(-,)}{new_appoint.id:04d} return render_template(appoint_success.html, appoint_noappoint_no) # GET请求显示医生列表 doctors Doctor.query.all() return render_template(doctor_list.html, doctorsdoctors)关键点使用login_required装饰器确保登录状态时间冲突检测防止重复预约预约号生成规则包含科室和日期信息3.2 医生模块3.2.1 排班批量导入from openpyxl import load_workbook app.route(/upload_schedule, methods[POST]) admin_required def upload_schedule(): if file not in request.files: return 未选择文件, 400 file request.files[file] if not file.filename.endswith(.xlsx): return 仅支持Excel文件, 400 wb load_workbook(file) ws wb.active for row in ws.iter_rows(min_row2, values_onlyTrue): doctor_id, date, time_range row start_time, end_time time_range.split(-) # 按30分钟间隔生成时间段 current datetime.strptime(f{date} {start_time}, %Y-%m-%d %H:%M) end datetime.strptime(f{date} {end_time}, %Y-%m-%d %H:%M) while current end: slot ScheduleSlot( doctor_iddoctor_id, start_timecurrent, end_timecurrent timedelta(minutes30), is_availableTrue ) db.session.add(slot) current timedelta(minutes30) db.session.commit() return 排班表导入成功, 200实现细节使用openpyxl解析Excel文件自动将时间范围拆分为30分钟间隔的时间段事务处理确保数据一致性4. 数据库设计4.1 核心表结构class Patient(UserMixin, db.Model): __tablename__ patients id db.Column(db.Integer, primary_keyTrue) name db.Column(db.String(80), nullableFalse) phone db.Column(db.String(20), uniqueTrue, nullableFalse) id_card db.Column(db.String(18), uniqueTrue) # 身份证号 password_hash db.Column(db.String(128)) appointments db.relationship(Appointment, backrefpatient, lazydynamic) class Doctor(db.Model): __tablename__ doctors id db.Column(db.Integer, primary_keyTrue) name db.Column(db.String(80), nullableFalse) title db.Column(db.String(50)) # 职称 department db.Column(db.String(50), nullableFalse) # 科室 specialty db.Column(db.Text) # 专长描述 schedule_slots db.relationship(ScheduleSlot, backrefdoctor, lazydynamic) class Appointment(db.Model): __tablename__ appointments id db.Column(db.Integer, primary_keyTrue) patient_id db.Column(db.Integer, db.ForeignKey(patients.id)) doctor_id db.Column(db.Integer, db.ForeignKey(doctors.id)) schedule_slot_id db.Column(db.Integer, db.ForeignKey(schedule_slots.id)) create_time db.Column(db.DateTime, defaultdatetime.utcnow) status db.Column(db.String(20), defaultpending) # pending/completed/cancelled symptoms db.Column(db.Text) # 症状描述4.2 索引优化# 在模型定义后添加索引 db.Index(idx_appointment_doctor_time, Appointment.doctor_id, Appointment.schedule_slot_id) db.Index(idx_schedule_doctor_time, ScheduleSlot.doctor_id, ScheduleSlot.start_time)设计考量患者和医生信息分离存储预约记录关联具体时间段为高频查询字段添加复合索引5. 安全防护5.1 认证安全from werkzeug.security import generate_password_hash, check_password_hash class Patient(UserMixin, db.Model): # ... def set_password(self, password): self.password_hash generate_password_hash(password) def check_password(self, password): return check_password_hash(self.password_hash, password)5.2 请求防护from flask_limiter import Limiter from flask_limiter.util import get_remote_address limiter Limiter( app, key_funcget_remote_address, default_limits[200 per day, 50 per hour] ) app.route(/login, methods[POST]) limiter.limit(10 per minute) def login(): # 登录逻辑5.3 敏感数据保护from flask_talisman import Talisman Talisman( app, force_httpsTrue, session_cookie_secureTrue, content_security_policy{ default-src: self, script-src: [self, cdn.jsdelivr.net], style-src: [self, unsafe-inline, cdn.jsdelivr.net] } )6. 部署方案6.1 生产环境部署# 安装依赖 pip install gunicorn # 启动命令 gunicorn -w 4 -b 0.0.0.0:8000 --access-logfile - --error-logfile - app:app6.2 Nginx配置server { listen 80; server_name yourdomain.com; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location /static { alias /path/to/your/static/files; expires 30d; } }6.3 数据库备份# 每日备份脚本 mysqldump -u username -p database_name /backups/hospital_$(date %Y%m%d).sql7. 扩展功能7.1 短信通知集成import requests def send_sms(phone, message): url https://sms-api.example.com/send params { phone: phone, text: message, apikey: your_api_key } try: resp requests.get(url, paramsparams) return resp.status_code 200 except Exception as e: app.logger.error(fSMS发送失败: {str(e)}) return False7.2 数据统计报表app.route(/stats/department) admin_required def department_stats(): # 按科室统计预约量 stats db.session.query( Doctor.department, func.count(Appointment.id) ).join(Doctor).filter( Appointment.create_time datetime.now() - timedelta(days30) ).group_by(Doctor.department).all() return render_template(stats_department.html, statsstats)8. 常见问题解决8.1 并发预约冲突问题现象多个用户同时预约同一时间段时可能出现超订解决方案app.route(/make_appointment, methods[POST]) login_required def make_appointment(): try: # 开启事务 db.session.begin() # 使用SELECT FOR UPDATE锁定记录 slot db.session.query(ScheduleSlot).filter_by( idrequest.form.get(slot_id) ).with_for_update().first() if not slot.is_available: db.session.rollback() return 该时段已被预约, 400 # 创建预约记录 appointment Appointment(...) slot.is_available False db.session.add(appointment) db.session.commit() return 预约成功 except Exception as e: db.session.rollback() return 预约失败, 5008.2 性能优化建议数据库连接池配置from sqlalchemy.pool import QueuePool SQLALCHEMY_ENGINE_OPTIONS { poolclass: QueuePool, pool_size: 10, max_overflow: 20, pool_timeout: 30 }缓存热门科室数据from flask_caching import Cache cache Cache(config{CACHE_TYPE: SimpleCache}) app.route(/departments) cache.cached(timeout3600) def list_departments(): return jsonify([d.name for d in Department.query.all()])9. 项目总结这套系统经过三个月的开发和优化目前已经稳定运行。在实现过程中有几个关键经验值得分享时间处理要统一所有时间字段都存储为UTC时间在显示时根据用户时区转换事务管理要严谨涉及多表更新的操作必须放在事务中日志记录要全面关键操作都要记录日志便于问题排查对于想要扩展功能的开发者建议考虑增加在线问诊功能对接医保支付系统开发微信小程序端整个项目的源码结构清晰遵循了Flask最佳实践适合作为中级Python开发者的学习参考。在部署时需要注意做好定时备份和安全防护特别是患者隐私数据的保护。
返回列表