医疗信息化建设已经成为现代医院管理的核心需求,而电子病历系统作为医疗信息化的基础组成部分,其开发质量直接影响医疗服务的效率与安全。我最近完成了一个基于Flask框架的电子病历管理系统开发项目,这个系统采用Python作为主要开发语言,结合了前后端分离的设计理念,实现了患者管理、病历记录和医生权限控制等核心功能。
选择Flask框架主要基于以下几个考量:首先,Flask作为轻量级框架,具有极高的灵活性,可以按需引入各种扩展;其次,Python在数据处理方面的优势特别适合医疗数据的处理;再者,Flask的学习曲线相对平缓,便于团队协作开发。在实际开发中,我们采用了Flask 2.0版本,它提供了更好的异步支持和性能优化。
系统架构采用经典的MVC模式,分为三层:
提示:在医疗系统开发中,数据安全和隐私保护是首要考虑因素,我们在架构设计阶段就将安全机制作为核心组件进行规划。
患者信息管理是系统的基础功能,我们设计了完整的信息录入、查询和修改流程。核心数据结构包括:
python复制class Patient(db.Model):
id = db.Column(db.Integer, primary_key=True)
medical_record_number = db.Column(db.String(20), unique=True) # 病历号
name = db.Column(db.String(50), nullable=False)
gender = db.Column(db.String(10))
birth_date = db.Column(db.Date)
id_card = db.Column(db.String(18), unique=True) # 身份证号
phone = db.Column(db.String(15))
address = db.Column(db.String(200))
emergency_contact = db.Column(db.String(50)) # 紧急联系人
emergency_phone = db.Column(db.String(15)) # 紧急联系电话
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
在实现增删改查功能时,我们特别注意了几个关键点:
病历管理是系统的核心功能,我们设计了结构化的病历模板,包含以下主要字段:
病历表的设计考虑了医疗数据的特殊性:
python复制class MedicalRecord(db.Model):
id = db.Column(db.Integer, primary_key=True)
patient_id = db.Column(db.Integer, db.ForeignKey('patient.id'), nullable=False)
doctor_id = db.Column(db.Integer, db.ForeignKey('doctor.id'), nullable=False)
visit_type = db.Column(db.String(20)) # 门诊/急诊/住院
visit_date = db.Column(db.DateTime, default=datetime.utcnow)
chief_complaint = db.Column(db.Text)
history_of_present_illness = db.Column(db.Text)
physical_examination = db.Column(db.Text)
auxiliary_examination = db.Column(db.Text)
diagnosis = db.Column(db.Text)
treatment_plan = db.Column(db.Text)
medical_orders = db.Column(db.Text)
status = db.Column(db.String(20), default='draft') # draft/final/archived
created_at = db.Column(db.DateTime, default=datetime.utcnow)
updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
注意:病历数据一旦提交(final状态)就不能直接修改,必须通过修订流程,这是医疗数据完整性的基本要求。
基于RBAC(基于角色的访问控制)模型,我们设计了多层次的医生权限系统:
角色定义:
权限控制实现:
python复制from flask_principal import Principal, Permission, RoleNeed
# 定义权限
admin_permission = Permission(RoleNeed('admin'))
chief_physician_permission = Permission(RoleNeed('chief_physician'))
resident_permission = Permission(RoleNeed('resident'))
nurse_permission = Permission(RoleNeed('nurse'))
# 在视图函数中使用权限控制
@app.route('/records/<int:record_id>', methods=['PUT'])
@chief_physician_permission.require(http_exception=403)
def update_record(record_id):
# 实现病历更新逻辑
我们最终选择了MySQL作为生产环境数据库,主要考虑到:
核心表关系设计如下:

主要表结构说明:
患者表(patients):
医生表(doctors):
病历表(medical_records):
医嘱表(medical_orders):
审计表(audit_logs):
针对医疗系统的特点,我们实施了以下优化措施:
索引优化:
查询优化:
分区策略:
python复制# 示例查询优化
from sqlalchemy.orm import joinedload
# 获取患者及其病历的优化查询
patient = Patient.query.options(
joinedload(Patient.medical_records)
).filter_by(medical_record_number='2023IM001').first()
我们采用RESTful风格设计系统API,主要特点包括:
以下是几个关键API的实现示例:
python复制from flask_restful import Resource, Api
api = Api(app)
class PatientResource(Resource):
def get(self, patient_id=None):
if patient_id:
patient = Patient.query.get_or_404(patient_id)
return patient_schema.dump(patient)
else:
patients = Patient.query.all()
return patients_schema.dump(patients)
def post(self):
data = request.get_json()
errors = patient_schema.validate(data)
if errors:
return {'errors': errors}, 400
patient = Patient(**data)
db.session.add(patient)
db.session.commit()
return patient_schema.dump(patient), 201
api.add_resource(PatientResource, '/api/v1/patients', '/api/v1/patients/<int:patient_id>')
python复制class MedicalRecordResource(Resource):
@jwt_required()
def get(self, record_id=None):
current_user = get_jwt_identity()
if record_id:
record = MedicalRecord.query.get_or_404(record_id)
# 权限检查
if not check_permission(current_user, record):
return {'message': '无权访问此病历'}, 403
return record_schema.dump(record)
else:
# 根据角色返回不同范围的病历
records = get_accessible_records(current_user)
return records_schema.dump(records)
api.add_resource(MedicalRecordResource, '/api/v1/records', '/api/v1/records/<int:record_id>')
使用Swagger UI自动生成API文档,便于前后端协作:
python复制from flask_swagger_ui import get_swaggerui_blueprint
SWAGGER_URL = '/api/docs'
API_URL = '/static/swagger.json'
swaggerui_blueprint = get_swaggerui_blueprint(
SWAGGER_URL,
API_URL,
config={'app_name': "电子病历系统API"}
)
app.register_blueprint(swaggerui_blueprint, url_prefix=SWAGGER_URL)
python复制from flask_jwt_extended import JWTManager, create_access_token, jwt_required
app.config['JWT_SECRET_KEY'] = 'super-secret-key' # 生产环境应从配置读取
app.config['JWT_ACCESS_TOKEN_EXPIRES'] = timedelta(hours=1)
jwt = JWTManager(app)
@app.route('/login', methods=['POST'])
def login():
username = request.json.get('username')
password = request.json.get('password')
user = User.query.filter_by(username=username).first()
if not user or not bcrypt.check_password_hash(user.password, password):
return jsonify({"msg": "用户名或密码错误"}), 401
access_token = create_access_token(identity=user.id)
return jsonify(access_token=access_token)
敏感数据加密:
数据传输安全:
审计日志:
python复制from flask_cors import CORS
CORS(app, resources={
r"/api/*": {
"origins": ["https://hospital.com"],
"methods": ["GET", "POST", "PUT", "DELETE"],
"allow_headers": ["Authorization", "Content-Type"]
}
})
python复制from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
limiter = Limiter(
app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)
@app.route('/api/reset-password', methods=['POST'])
@limiter.limit("3 per hour")
def reset_password():
# 密码重置逻辑
我们采用Nginx+Gunicorn+MySQL的部署架构:
应用服务器:
Web服务器:
数据库服务器:
为简化部署,我们提供了Docker方案:
dockerfile复制# Dockerfile示例
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "-w 4", "-k gevent", "-b :5000", "app:app"]
使用docker-compose编排多容器环境:
yaml复制version: '3'
services:
web:
build: .
ports:
- "5000:5000"
depends_on:
- db
environment:
- DATABASE_URL=mysql://user:password@db/emr
db:
image: mysql:5.7
volumes:
- db_data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=emr
- MYSQL_USER=user
- MYSQL_PASSWORD=password
volumes:
db_data:
缓存策略:
静态资源优化:
数据库连接池:
python复制from sqlalchemy import create_engine
from sqlalchemy.pool import QueuePool
engine = create_engine(
'mysql://user:password@localhost/emr',
poolclass=QueuePool,
pool_size=10,
max_overflow=20,
pool_recycle=3600
)
我们采用测试金字塔模型,从下到上实施测试:
单元测试(70%):
集成测试(20%):
E2E测试(10%):
python复制# 示例测试用例
def test_patient_creation(client, db_session):
data = {
"name": "张三",
"gender": "男",
"birth_date": "1990-01-01",
"phone": "13800138000"
}
response = client.post('/api/v1/patients', json=data)
assert response.status_code == 201
assert Patient.query.count() == 1
python复制import factory
class PatientFactory(factory.alchemy.SQLAlchemyModelFactory):
class Meta:
model = Patient
sqlalchemy_session = db.session
name = factory.Faker('name')
gender = factory.Iterator(['男', '女'])
birth_date = factory.Faker('date_of_birth')
预提交钩子:
CI流水线:
部署前测试:
在实际开发过程中,我们积累了一些有价值的经验:
医疗数据特殊性处理:
性能优化技巧:
调试技巧:
扩展性考虑:
对于类似项目的开发者,我有几点建议:
这个系统后续还可以扩展以下功能: