Building a Patient Management System Using Python (Object Oriented Programming), Flask Framework and PostgreSQL Database
In the real world, many software systems require robust architectures that are scalable, maintainable, and connected to powerful databases. One common use case is a Patient Management System—an application to manage patient records, appointments, and medical histories. In this article, we’ll explore how to build a simplified version of such a system using Python’s object-oriented programming (OOP) paradigm, Flask framework and connect it to a PostgreSQL database.
🔧 Tech Stack
The complete source code is available at : https://github.com/Jayaprakashsuseelam/ModernWebApplications/tree/master/Python-oop
🏗️ Object-Oriented Programming Concepts Implementation
📋 Overview
This Patient Management System demonstrates comprehensive Object-Oriented Programming (OOP) concepts using Python. The project showcases real-world application of OOP principles with a complete architecture including models, services, factories, and design patterns.
🎯 Core OOP Concepts Implemented
1. 🔗 Inheritance
Definition: A mechanism that allows a class to inherit properties and methods from another class.
Implementation:
# Abstract Base Class
class BaseModel(ABC):
def __init__(self, **kwargs):
self._id = kwargs.get('id')
# ... common attributes
# Concrete Class inheriting from Base
class Patient(BaseModel):
def __init__(self, first_name, last_name, **kwargs):
super().__init__(**kwargs) # Call parent constructor
self._first_name = first_name
# ... patient-specific attributes
Benefits:
2. 🔒 Encapsulation
Definition: Bundling data and methods that operate on that data within a single unit (class) and restricting access to some of the object's components.
Implementation:
class Patient(BaseModel):
def __init__(self, first_name, last_name, **kwargs):
# Private attributes (encapsulation)
self._first_name = first_name
self._last_name = last_name
self._date_of_birth = date_of_birth
# Public properties with validation (controlled access)
@property
def first_name(self) -> str:
return self._first_name
@first_name.setter
def first_name(self, value: str):
if not self._validate_name(value):
raise ValueError("Invalid first name")
self._first_name = value
# Private validation method (hidden implementation)
def _validate_name(self, name: str) -> bool:
return bool(re.match(r"^[A-Za-z\s\-']{2,50}$", name.strip()))
Benefits:
3. 🔄 Polymorphism
Definition: The ability to present the same interface for different underlying forms (data types or classes).
Implementation:
# Abstract method in base class
class BaseModel(ABC):
@abstractmethod
def to_dict(self) -> Dict[str, Any]:
pass
# Different implementations in derived classes
class Patient(BaseModel):
def to_dict(self) -> Dict[str, Any]:
return {
'id': self._id,
'first_name': self._first_name,
'last_name': self._last_name,
# ... patient-specific fields
}
# Polymorphic usage
patients = [patient1, patient2, patient3]
patient_dicts = [p.to_dict() for p in patients] # Same interface, different implementations
Benefits:
4. 🎭 Abstraction
Definition: Hiding complex implementation details and showing only necessary features.
Implementation:
# Abstract base class
class BaseModel(ABC):
@abstractmethod
def validate(self) -> bool:
"""Validate model data - must be implemented by subclasses"""
pass
@abstractmethod
def _get_insert_data(self) -> tuple[List[str], List[Any]]:
"""Get fields and values for INSERT - must be implemented by subclasses"""
pass
# Concrete implementation hides complexity
class Patient(BaseModel):
def validate(self) -> bool:
# Complex validation logic hidden from users
return (
self._validate_name(self._first_name) and
self._validate_date(self._date_of_birth) and
self._validate_gender(self._gender) and
self._validate_contact(self._contact_number)
)
Benefits:
🏭 Design Patterns Implemented
1. Factory Pattern
Purpose: Create objects without specifying their exact classes.
Implementation:
class ModelFactory(ABC):
@abstractmethod
def create_model(self, model_type: str, **kwargs) -> BaseModel:
pass
class PatientModelFactory(ModelFactory):
def create_model(self, model_type: str, **kwargs) -> BaseModel:
if model_type == 'patient':
return Patient(**kwargs)
def create_adult_patient(self, **kwargs) -> Patient:
# Specialized factory method
patient = Patient(**kwargs)
if not patient.is_adult():
raise ValueError("Patient must be 18 or older")
return patient
2. Service Layer Pattern
Purpose: Separate business logic from data access logic.
Implementation:
class BaseService(ABC, Generic[T]):
def __init__(self, model_class: type[T]):
self._model_class = model_class
def create(self, **kwargs) -> T:
# Business logic here
instance = self._model_class(**kwargs)
instance.save()
return instance
class PatientService(BaseService[Patient]):
def get_statistics(self) -> Dict[str, Any]:
# Complex business logic
all_patients = self.get_all()
adults = [p for p in all_patients if p.is_adult()]
# ... statistical calculations
3. Singleton Pattern
Purpose: Ensure a class has only one instance.
Implementation:
class ModelFactoryRegistry:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
cls._instance._factories = {}
return cls._instance
📁 Project Structure
Python-oop/
├── models/ # 🔗 Inheritance & Abstraction
│ ├── __init__.py
│ ├── base_model.py # Abstract Base Class
│ └── patient.py # Concrete Patient Model
├── services/ # 🏭 Service Layer Pattern
│ ├── __init__.py
│ ├── base_service.py # Abstract Service
│ └── patient_service.py # Concrete Patient Service
├── factories/ # 🏭 Factory Pattern
│ ├── __init__.py
│ └── model_factory.py # Factory Implementation
├── web_app_oop.py # 🌐 Main OOP Application
├── web_app_postgresql.py # 🗄️ PostgreSQL Version
├── web_app.py # 💾 In-Memory Version
├── oop_demo.py # 🧪 OOP Concepts Demo
├── check_db.py # 🔍 Database Debug Tool
├── db.py # 🔌 Database Connection
├── templates/
│ └── index.html # 🎨 Frontend Interface
├── README_OOP_CONCEPTS.md # 📚 OOP Documentation
├── README_POSTGRESQL.md # 🗄️ Database Documentation
├── requirements_postgresql.txt # 📦 Dependencies
└── env_template.txt # ⚙️ Configuration Template
🚀 How to Run the OOP Application
1. Setup Environment
# Activate virtual environment
source ../.venv/Scripts/activate
# Install dependencies
pip install Flask==2.3.3 psycopg2-binary python-dotenv
2. Configure Database
# Create .env file
cp env_template.txt .env
# Edit .env with your PostgreSQL credentials
DB_NAME=hospital_db
DB_USER=admin_user
DB_PASSWORD=admin_pwd
DB_HOST=localhost
DB_PORT=5432
3. Run OOP Application
python web_app_oop.py
4. Access OOP Features
🔧 OOP Features Demonstration
1. Inheritance Demo
# BaseModel provides common functionality
patient = Patient(first_name="John", last_name="Doe", ...)
patient.save() # Inherited from BaseModel
patient.delete() # Inherited from BaseModel
2. Encapsulation Demo
# Private attributes with controlled access
patient.first_name = "Jane" # Uses setter with validation
print(patient.first_name) # Uses getter
# patient._first_name # Direct access discouraged
3. Polymorphism Demo
# Same interface, different implementations
models = [patient1, patient2, patient3]
for model in models:
print(model.to_dict()) # Polymorphic method call
4. Factory Pattern Demo
# Create objects without specifying exact class
factory = PatientModelFactory()
patient = factory.create_model('patient', **data)
adult_patient = factory.create_adult_patient(**data)
📊 Advanced OOP Features
1. Generic Types
class BaseService(ABC, Generic[T]):
def __init__(self, model_class: type[T]):
self._model_class = model_class
2. Magic Methods
def __str__(self) -> str:
return f"Patient({self.get_full_name()}, ID: {self._id})"
def __eq__(self, other) -> bool:
return self._id == other._id
3. Class Methods
@classmethod
def get_by_id(cls, patient_id: int) -> Optional['Patient']:
# Factory method for creating instances
4. Property Decorators
@property
def age(self) -> Optional[int]:
return self.get_age()
@age.setter
def age(self, value: int):
# Cannot set age directly - calculated from date_of_birth
raise AttributeError("Age is calculated from date of birth")
🎯 OOP Benefits Demonstrated
1. Code Reusability
2. Maintainability
3. Scalability
4. Testability
🔍 API Endpoints Demonstrating OOP
🏆 Learning Outcomes
This project demonstrates:
🚀 How to Run Different Versions
1. 🧪 OOP Concepts Demo (No Database Required)
python oop_demo.py
Shows: All OOP concepts in action with sample data
2. 💾 In-Memory Version (No Database Setup)
python web_app.py
Features:
3. 🗄️ PostgreSQL Version (Persistent Storage)
# Setup database
cp env_template.txt .env
# Edit .env with your PostgreSQL credentials
# Run application
python web_app_postgresql.py
Features:
4. 🏗️ Full OOP Version (Recommended)
# Setup database
cp env_template.txt .env
# Edit .env with your PostgreSQL credentials
# Run OOP application
python web_app_oop.py
Features:
🌐 Web Interface Access
Main Application
OOP Demo Endpoints
Advanced API Endpoints (Optional)
🔧 OOP Features in Action
1. Inheritance Example
# Patient inherits from BaseModel
patient = Patient(first_name="John", last_name="Doe", ...)
patient.save() # Inherited from BaseModel
patient.delete() # Inherited from BaseModel
2. Encapsulation Example
# Private attributes with controlled access
patient.first_name = "Jane" # Uses setter with validation
print(patient.first_name) # Uses getter
3. Polymorphism Example
# Same interface, different implementations
patients = [patient1, patient2, patient3]
for patient in patients:
print(patient.to_dict()) # Polymorphic method call
4. Factory Pattern Example
# Create objects without specifying exact class
factory = PatientModelFactory()
patient = factory.create_model('patient', **data)
adult_patient = factory.create_adult_patient(**data)
5. Service Layer Example
# Business logic separation
service = PatientService()
patients = service.get_all()
stats = service.get_statistics()
Patient Listing & Add new patient User Interface
Edit patient info User Interface
This project successfully demonstrates:
The Patient Management System is now fully functional with persistent PostgreSQL storage, comprehensive OOP architecture, and a beautiful web interface!
#PythonProgramming
#ObjectOrientedProgramming
#PostgreSQL
#PythonOOP
#Flask
#FlaskFramework
#PatientManagementSystem
#HealthcareTech
#BackendDevelopment
#DatabaseIntegration
#PythonProjects
#MedicalSoftware
#PythonDataclasses
#psycopg2
#CRUDOperations
#PythonTutorial
#SoftwareArchitecture