Creating an advanced-level Hospital Management System (HMS) with Flask and Bootstrap 5 involves designing a robust database structure, implementing backend logic, and creating responsive frontend pages. Below is a detailed implementation:

Database Structure

The database will be designed using SQLAlchemy (ORM for Flask). Here's the schema:

Tables

  • Patients: Stores patient information.
  • Doctors: Stores doctor information.
  • Appointments: Stores appointment details.
  • MedicalRecords: Stores medical records of patients.
  • Departments: Stores hospital departments.
  • Users: Stores user accounts (for authentication).

from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
password = db.Column(db.String(200), nullable=False)
role = db.Column(db.String(20), default='patient') # Roles: patient, doctor, admin
patient = db.relationship('Patient', backref='user', uselist=False)
doctor = db.relationship('Doctor', backref='user', uselist=False)
class Patient(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
name = db.Column(db.String(100), nullable=False)
dob = db.Column(db.Date, nullable=False)
gender = db.Column(db.String(10), nullable=False)
phone = db.Column(db.String(15), nullable=False)
appointments = db.relationship('Appointment', backref='patient', lazy=True)
medical_records = db.relationship('MedicalRecord', backref='patient', lazy=True)
class Doctor(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
name = db.Column(db.String(100), nullable=False)
specialization = db.Column(db.String(100), nullable=False)
department_id = db.Column(db.Integer, db.ForeignKey('department.id'), nullable=False)
appointments = db.relationship('Appointment', backref='doctor', lazy=True)
class Department(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
doctors = db.relationship('Doctor', backref='department', lazy=True)
class Appointment(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)
appointment_date = db.Column(db.DateTime, nullable=False)
status = db.Column(db.String(20), default='Scheduled') # Status: Scheduled, Completed, Cancelled
medical_record = db.relationship('MedicalRecord', backref='appointment', uselist=False)
class MedicalRecord(db.Model):
id = db.Column(db.Integer, primary_key=True)
patient_id = db.Column(db.Integer, db.ForeignKey('patient.id'), nullable=False)
appointment_id = db.Column(db.Integer, db.ForeignKey('appointment.id'), nullable=False)
diagnosis = db.Column(db.Text, nullable=False)
prescription = db.Column(db.Text, nullable=False)
notes = db.Column(db.Text)

Flask Application Structure

Here’s the directory structure for the project:


hospital_management_system/

├── app.py
├── models.py
├── forms.py
├── templates/
│ ├── base.html
│ ├── index.html
│ ├── login.html
│ ├── register.html
│ ├── patient_dashboard.html
│ ├── doctor_dashboard.html
│ ├── admin_dashboard.html
│ ├── book_appointment.html
│ ├── view_appointments.html
│ ├── view_medical_records.html
│ ├── manage_doctors.html
│ ├── manage_patients.html
│ └── manage_departments.html
├── static/
│ ├── css/
│ │ └── styles.css
│ ├── js/
│ │ └── scripts.js
│ └── images/
└── requirements.txt

Flask Application Code

app.py


from flask import Flask, render_template, request, redirect, url_for, flash, session
from flask_sqlalchemy import SQLAlchemy
from models import db, User, Patient, Doctor, Department, Appointment, MedicalRecord
from forms import LoginForm, RegistrationForm, AppointmentForm, MedicalRecordForm
from datetime import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hospital_management.db'
db.init_app(app)
# Routes
@app.route('/')
def index():
return render_template('index.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data, password=form.password.data)
db.session.add(user)
db.session.commit()
flash('Registration successful! Please login.', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
@app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and user.password == form.password.data: # Use hashed passwords in production
session['user_id'] = user.id
session['role'] = user.role
flash('Login successful!', 'success')
return redirect(url_for('patient_dashboard') if user.role == 'patient' else 'doctor_dashboard' if user.role == 'doctor' else 'admin_dashboard')
flash('Login failed. Check your email and password.', 'danger')
return render_template('login.html', form=form)
@app.route('/patient_dashboard')
def patient_dashboard():
if 'user_id' not in session or session['role'] != 'patient':
return redirect(url_for('login'))
patient = Patient.query.filter_by(user_id=session['user_id']).first()
return render_template('patient_dashboard.html', patient=patient)
@app.route('/doctor_dashboard')
def doctor_dashboard():
if 'user_id' not in session or session['role'] != 'doctor':
return redirect(url_for('login'))
doctor = Doctor.query.filter_by(user_id=session['user_id']).first()
return render_template('doctor_dashboard.html', doctor=doctor)
@app.route('/admin_dashboard')
def admin_dashboard():
if 'user_id' not in session or session['role'] != 'admin':
return redirect(url_for('login'))
return render_template('admin_dashboard.html')
@app.route('/book_appointment', methods=['GET', 'POST'])
def book_appointment():
if 'user_id' not in session or session['role'] != 'patient':
return redirect(url_for('login'))
form = AppointmentForm()
if form.validate_on_submit():
appointment = Appointment(patient_id=session['user_id'], doctor_id=form.doctor_id.data, appointment_date=form.appointment_date.data)
db.session.add(appointment)
db.session.commit()
flash('Appointment booked successfully!', 'success')
return redirect(url_for('patient_dashboard'))
doctors = Doctor.query.all()
return render_template('book_appointment.html', form=form, doctors=doctors)
@app.route('/view_appointments')
def view_appointments():
if 'user_id' not in session:
return redirect(url_for('login'))
appointments = Appointment.query.filter_by(patient_id=session['user_id']).all()
return render_template('view_appointments.html', appointments=appointments)
@app.route('/view_medical_records')
def view_medical_records():
if 'user_id' not in session:
return redirect(url_for('login'))
patient = Patient.query.filter_by(user_id=session['user_id']).first()
records = MedicalRecord.query.filter_by(patient_id=patient.id).all()
return render_template('view_medical_records.html', records=records)
@app.route('/manage_doctors')
def manage_doctors():
if 'user_id' not in session or session['role'] != 'admin':
return redirect(url_for('login'))
doctors = Doctor.query.all()
return render_template('manage_doctors.html', doctors=doctors)
@app.route('/manage_patients')
def manage_patients():
if 'user_id' not in session or session['role'] != 'admin':
return redirect(url_for('login'))
patients = Patient.query.all()
return render_template('manage_patients.html', patients=patients)
@app.route('/manage_departments')
def manage_departments():
if 'user_id' not in session or session['role'] != 'admin':
return redirect(url_for('login'))
departments = Department.query.all()
return render_template('manage_departments.html', departments=departments)
if __name__ == '__main__':
with app.app_context():
db.create_all()
app.run(debug=True)

models.py


from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(50), unique=True, nullable=False)
email = db.Column(db.String(100), unique=True, nullable=False)
password = db.Column(db.String(200), nullable=False)
role = db.Column(db.String(20), default='patient') # Roles: patient, doctor, admin
patient = db.relationship('Patient', backref='user', uselist=False)
doctor = db.relationship('Doctor', backref='user', uselist=False)
class Patient(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
name = db.Column(db.String(100), nullable=False)
dob = db.Column(db.Date, nullable=False)
gender = db.Column(db.String(10), nullable=False)
phone = db.Column(db.String(15), nullable=False)
appointments = db.relationship('Appointment', backref='patient', lazy=True)
medical_records = db.relationship('MedicalRecord', backref='patient', lazy=True)
class Doctor(db.Model):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
name = db.Column(db.String(100), nullable=False)
specialization = db.Column(db.String(100), nullable=False)
department_id = db.Column(db.Integer, db.ForeignKey('department.id'), nullable=False)
appointments = db.relationship('Appointment', backref='doctor', lazy=True)
class Department(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), nullable=False)
doctors = db.relationship('Doctor', backref='department', lazy=True)
class Appointment(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)
appointment_date = db.Column(db.DateTime, nullable=False)
status = db.Column(db.String(20), default='Scheduled') # Status: Scheduled, Completed, Cancelled
medical_record = db.relationship('MedicalRecord', backref='appointment', uselist=False)
class MedicalRecord(db.Model):
id = db.Column(db.Integer, primary_key=True)
patient_id = db.Column(db.Integer, db.ForeignKey('patient.id'), nullable=False)
appointment_id = db.Column(db.Integer, db.ForeignKey('appointment.id'), nullable=False)
diagnosis = db.Column(db.Text, nullable=False)
prescription = db.Column(db.Text, nullable=False)
notes = db.Column(db.Text)

forms.py


from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, DateField, SelectField, DateTimeField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Email, Length
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=2, max=50)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired(), Length(min=6, max=200)])
submit = SubmitField('Register')
class LoginForm(FlaskForm):
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
submit = SubmitField('Login')
class AppointmentForm(FlaskForm):
doctor_id = SelectField('Doctor', coerce=int, validators=[DataRequired()])
appointment_date = DateTimeField('Appointment Date', format='%Y-%m-%d %H:%M', validators=[DataRequired()])
submit = SubmitField('Book Appointment')
class MedicalRecordForm(FlaskForm):
diagnosis = TextAreaField('Diagnosis', validators=[DataRequired()])
prescription = TextAreaField('Prescription', validators=[DataRequired()])
notes = TextAreaField('Notes')
submit = SubmitField('Save Record')

base.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
<title>{% block title %}Hospital Management System{% endblock %}</title>
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('index') }}">Hospital Management</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
{% if 'user_id' in session %}
{% if session['role'] == 'patient' %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('patient_dashboard') }}">Dashboard</a>
</li>
{% elif session['role'] == 'doctor' %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('doctor_dashboard') }}">Dashboard</a>
</li>
{% elif session['role'] == 'admin' %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('admin_dashboard') }}">Dashboard</a>
</li>
{% endif %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('logout') }}">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('login') }}">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('register') }}">Register</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% with messages = get_flashed_messages() %}
{% if messages %}
<div class="alert alert-info">
{% for message in messages %}
{{ message }}<br>
{% endfor %}
</div>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

index.html


{% extends 'base.html' %}
{% block content %}
<h1>Welcome to the Hospital Management System</h1>
<p>Manage your health with ease!</p>
<a href="{{ url_for('register') }}" class="btn btn-primary">Register</a>
<a href="{{ url_for('login') }}" class="btn btn-secondary">Login</a>
{% endblock %}

login.html


{% extends 'base.html' %}
{% block content %}
<h2>Login</h2>
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.email.label(class="form-label") }}
{{ form.email(class="form-control") }}
</div>
<div class="mb-3">
{{ form.password.label(class="form-label") }}
{{ form.password(class="form-control") }}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
{% endblock %}

register.html


{% extends 'base.html' %}
{% block content %}
<h2>Register</h2>
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.username.label(class="form-label") }}
{{ form.username(class="form-control") }}
</div>
<div class="mb-3">
{{ form.email.label(class="form-label") }}
{{ form.email(class="form-control") }}
</div>
<div class="mb-3">
{{ form.password.label(class="form-label") }}
{{ form.password(class="form-control") }}
</div>
{{ form.submit(class="btn btn-primary") }}
</form>
{% endblock %}

patient_dashboard.html


{% extends 'base.html' %}
{% block content %}
<h2>Patient Dashboard</h2>
<p>Welcome, {{ patient.name }}!</p>
<a href="{{ url_for('book_appointment') }}" class="btn btn-primary">Book Appointment</a>
<a href="{{ url_for('view_appointments') }}" class="btn btn-secondary">View Appointments</a>
<a href="{{ url_for('view_medical_records') }}" class="btn btn-info">View Medical Records</a>
{% endblock %}

doctor_dashboard.html


{% extends 'base.html' %}
{% block content %}
<h2>Doctor Dashboard</h2>
<p>Welcome, Dr. {{ doctor.name }}!</p>
<a href="{{ url_for('view_appointments') }}" class="btn btn-secondary">View Appointments</a>
{% endblock %}

admin_dashboard.html


{% extends 'base.html' %}
{% block content %}
<h2>Admin Dashboard</h2>
<p>Welcome, Admin!</p>
<a href="{{ url_for('manage_doctors') }}" class="btn btn-primary">Manage Doctors</a>
<a href="{{ url_for('manage_patients') }}" class="btn btn-secondary">Manage Patients</a>
<a href="{{ url_for('manage_departments') }}" class="btn btn-info">Manage Departments</a>
{% endblock %}

book_appointment.html


{% extends 'base.html' %}
{% block content %}
<h2>Book Appointment</h2>
<form method="POST">
{{ form.hidden_tag() }}
<div class="mb-3">
{{ form.doctor_id.label(class="form-label") }}
{{ form.doctor_id(class="form-control") }}
</div>
<div class="mb-3">
{{ form.appointment_date.label(class="form-label") }}
{{ form.appointment_date(class="form-control") }}
</div>
{{ form.submit(class="btn btn-primary") }}
</form ```html
{% endblock %}

view_appointments.html


{% extends 'base.html' %}
{% block content %}
<h2>Your Appointments</h2>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Doctor</th>
<th>Date</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for appointment in appointments %}
<tr>
<td>{{ appointment.id }}</td>
<td>{{ appointment.doctor.name }}</td>
<td>{{ appointment.appointment_date }}</td>
<td>{{ appointment.status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

view_medical_records.html


{% extends 'base.html' %}
{% block content %}
<h2>Your Medical Records</h2>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Diagnosis</th>
<th>Prescription</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
{% for record in records %}
<tr>
<td>{{ record.id }}</td>
<td>{{ record.diagnosis }}</td>
<td>{{ record.prescription }}</td>
<td>{{ record.notes }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

manage_doctors.html


{% extends 'base.html' %}
{% block content %}
<h2>Manage Doctors</h2>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Specialization</th>
<th>Department</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for doctor in doctors %}
<tr>
<td>{{ doctor.id }}</td>
<td>{{ doctor.name }}</td>
<td>{{ doctor.specialization }}</td>
<td>{{ doctor.department.name }}</td>
<td>
<a href="{{ url_for('edit_doctor', doctor_id=doctor.id) }}" class="btn btn-warning btn-sm">Edit</a>
<a href="{{ url_for('delete_doctor', doctor_id=doctor.id) }}" class="btn btn-danger btn-sm">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

manage_patients.html


{% extends 'base.html' %}
{% block content %}
<h2>Manage Patients</h2>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>DOB</th>
<th>Gender</th>
<th>Phone</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for patient in patients %}
<tr>
<td>{{ patient.id }}</td>
<td>{{ patient.name }}</td>
<td>{{ patient.dob }}</td>
<td>{{ patient.gender }}</td>
<td>{{ patient.phone }}</td>
<td>
<a href="{{ url_for('edit_patient', patient_id=patient.id) }}" class="btn btn-warning btn-sm">Edit</a>
<a href="{{ url_for('delete_patient', patient_id=patient.id) }}" class="btn btn-danger btn-sm">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

manage_departments.html


{% extends 'base.html' %}
{% block content %}
<h2>Manage Departments</h2>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for department in departments %}
<tr>
<td>{{ department.id }}</td>
<td>{{ department.name }}</td>
<td>
<a href="{{ url_for('edit_department', department_id=department.id) }}" class="btn btn-warning btn-sm">Edit</a>
<a href="{{ url_for('delete_department', department_id=department.id ) }}" class="btn btn-danger btn-sm">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

Static Files

styles.css


body {
background-color: #f8f9fa;
}
.navbar {
margin-bottom: 20px;
}
.table {
margin-top: 20px;
}

scripts.js


// Custom JavaScript can be added here
document.addEventListener('DOMContentLoaded', function() {
console.log("Hospital Management System Loaded");
});

Requirements


Flask==2.0.1
Flask-SQLAlchemy==2.5.1
Flask-WTF==0.15.1
WTForms==2.3.3

This structure provides a comprehensive foundation for an advanced Hospital Management System using Flask and Bootstrap 5. You can expand upon this by adding features such as user roles, email notifications, and more complex medical record management.