Creating an advanced-level Blood Bank Management System (BBMS) 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

  • Users: Stores user information (donors, recipients, and admins).
  • Donors: Stores donor information.
  • Recipients: Stores recipient information.
  • BloodInventory: Stores blood inventory details.
  • Donations: Stores donation details.
  • Requests: Stores blood request details.

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='donor') # Roles: donor, recipient, admin
donor = db.relationship('Donor', backref='user', uselist=False)
recipient = db.relationship('Recipient', backref='user', uselist=False)
class Donor(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)
blood_type = db.Column(db.String(5), nullable=False)
phone = db.Column(db.String(15), nullable=False)
donations = db.relationship('Donation', backref='donor', lazy=True)
class Recipient(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)
blood_type = db.Column(db.String(5), nullable=False)
phone = db.Column(db.String(15), nullable=False)
requests = db.relationship('Request', backref='recipient', lazy=True)
class BloodInventory(db.Model):
id = db.Column(db.Integer, primary_key=True)
blood_type = db.Column(db.String(5), nullable=False)
quantity = db.Column(db.Integer, nullable=False)
last_updated = db.Column(db.DateTime, default=datetime.utcnow)
class Donation(db.Model):
id = db.Column(db.Integer, primary_key=True)
donor_id = db.Column(db.Integer, db.ForeignKey('donor.id'), nullable=False)
donation_date = db.Column(db.DateTime, nullable=False)
quantity = db.Column(db.Integer, nullable=False)
class Request(db.Model):
id = db.Column(db.Integer, primary_key=True)
recipient_id = db.Column(db.Integer, db.ForeignKey('recipient.id'), nullable=False)
blood_type = db.Column(db.String(5), nullable=False)
quantity = db.Column(db.Integer, nullable=False)
request_date = db.Column(db.DateTime, nullable=False)
status = db.Column(db.String(20), default='Pending') # Status: Pending, Approved, Rejected

Flask Application Structure

Here’s the directory structure for the project:


blood_bank_management_system/

├── app.py
├── models.py
├── forms.py
├── templates/
│ ├── base.html
│ ├── index.html
│ ├── login.html
│ ├── register.html
│ ├── donor_dashboard.html
│ ├── recipient_dashboard.html
│ ├── admin_dashboard.html
│ ├── donate_blood.html
│ ├── request_blood.html
│ ├── view_inventory.html
│ ├── view_donations.html
│ ├── view_requests.html
│ └── manage_inventory.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, Donor, Recipient, BloodInventory, Donation, Request
from forms import LoginForm, RegistrationForm, DonationForm, RequestForm
from datetime import datetime
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blood_bank_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('donor_dashboard') if user.role == 'donor' else 'recipient_dashboard' if user.role == 'recipient' else 'admin_dashboard')
flash('Login failed. Check your email and password.', 'danger')
return render_template('login.html', form=form)
@app.route('/donor_dashboard')
def donor_dashboard():
if 'user_id' not in session or session['role'] != 'donor':
return redirect(url_for('login'))
donor = Donor.query.filter_by(user_id=session['user_id']).first()
return render_template('donor_dashboard.html', donor=donor)
@app.route('/recipient_dashboard')
def recipient_dashboard():
if 'user_id' not in session or session['role'] != 'recipient':
return redirect(url_for('login'))
recipient = Recipient.query.filter_by(user_id=session['user_id']).first()
return render_template('recipient_dashboard.html', recipient=recipient)
@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('/donate_blood', methods=['GET', 'POST'])
def donate_blood():
if 'user_id' not in session or session['role'] != 'donor':
return redirect(url_for('login'))
form = DonationForm()
if form.validate_on_submit():
donation = Donation(donor_id=session['user_id'], donation_date=datetime.utcnow(), quantity=form.quantity.data)
db.session.add(donation)
db.session.commit()
flash('Donation recorded successfully!', 'success')
return redirect(url_for('donor_dashboard'))
return render_template('donate_blood.html', form=form)
@app.route('/request_blood', methods=['GET', 'POST'])
def request_blood():
if 'user_id' not in session or session['role'] != 'recipient':
return redirect(url_for('login'))
form = RequestForm()
if form.validate_on_submit():
request = Request(recipient_id=session['user_id'], blood_type=form.blood_type.data, quantity=form.quantity.data, request_date=datetime.utcnow())
db.session.add(request)
db.session.commit()
flash('Blood request submitted successfully!', 'success')
return redirect(url_for('recipient_dashboard'))
return render_template('request_blood.html', form=form)
@app.route('/view_inventory')
def view_inventory():
if 'user_id' not in session:
return redirect(url_for('login'))
inventory = BloodInventory.query.all()
return render_template('view_inventory.html', inventory=inventory)
@app.route('/view_donations')
def view_donations():
if 'user_id' not in session or session['role'] != 'donor':
return redirect(url_for('login'))
donations = Donation.query.filter_by(donor_id=session['user_id']).all()
return render_template('view_donations.html', donations=donations)
@app.route('/view_requests')
def view_requests():
if 'user_id' not in session or session['role'] != 'recipient':
return redirect(url_for('login'))
requests = Request.query.filter_by(recipient_id=session['user_id']).all()
return render_template('view_requests.html', requests=requests)
@app.route('/manage_inventory')
def manage_inventory():
if 'user_id' not in session or session['role'] != 'admin':
return redirect(url_for('login'))
inventory = BloodInventory.query.all()
return render_template('manage_inventory.html', inventory=inventory)
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='donor') # Roles: donor, recipient, admin
donor = db.relationship('Donor', backref='user', uselist=False)
recipient = db.relationship('Recipient', backref='user', uselist=False)
class Donor(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)
blood_type = db.Column(db.String(5), nullable=False)
phone = db.Column(db.String(15), nullable=False)
donations = db.relationship('Donation', backref='donor', lazy=True)
class Recipient(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)
blood_type = db.Column(db.String(5), nullable=False)
phone = db.Column(db.String(15), nullable=False)
requests = db.relationship('Request', backref='recipient', lazy=True)
class BloodInventory(db.Model):
id = db.Column(db.Integer, primary_key=True)
blood_type = db.Column(db.String(5), nullable=False)
quantity = db.Column(db.Integer, nullable=False)
last_updated = db.Column(db.DateTime, default=datetime.utcnow)
class Donation(db.Model):
id = db.Column(db.Integer, primary_key=True)
donor_id = db.Column(db.Integer, db.ForeignKey('donor.id'), nullable=False)
donation_date = db.Column(db.DateTime, nullable=False)
quantity = db.Column(db.Integer, nullable=False)
class Request(db.Model):
id = db.Column(db.Integer, primary_key=True)
recipient_id = db.Column(db.Integer, db.ForeignKey('recipient.id'), nullable=False)
blood_type = db.Column(db.String(5), nullable=False)
quantity = db.Column(db.Integer, nullable=False)
request_date = db.Column(db.DateTime, nullable=False)
status = db.Column(db.String(20), default='Pending') # Status: Pending, Approved, Rejected

forms.py


from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, DateField, SelectField, IntegerField, 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 DonationForm(FlaskForm):
quantity = IntegerField('Quantity (in ml)', validators=[DataRequired()])
submit = SubmitField('Donate Blood')
class RequestForm(FlaskForm):
blood_type = SelectField('Blood Type', choices=[('A+', 'A+'), ('A-', 'A-'), ('B+', 'B+'), ('B-', 'B-'), ('O+', 'O+'), ('O-', 'O-'), ('AB+', 'AB+'), ('AB-', 'AB-')], validators=[DataRequired()])
quantity = IntegerField('Quantity (in ml)', validators=[DataRequired()])
submit = SubmitField('Request Blood')

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 %}Blood Bank 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') }}">Blood Bank 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'] == 'donor' %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('donor_dashboard') }}">Dashboard</a>
</li>
{% elif session['role'] == 'recipient' %}
<li class="nav-item">
<a class="nav-link" href="{{ url_for('recipient_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 Blood Bank Management System</h1>
<p>Your contribution can save lives!</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 %}

donor_dashboard.html


{% extends 'base.html' %}
{% block content %}
<h2>Donor Dashboard</h2>
<p>Welcome, {{ donor.name }}!</p>
<a href="{{ url_for('donate_blood') }}" class="btn btn-primary">Donate Blood</a>
<a href="{{ url_for('view_donations') }}" class="btn btn-secondary">View Donations</a>
{% endblock %}

recipient_dashboard.html


{% extends 'base.html' %}
{% block content %}
<h2>Recipient Dashboard</h2>
<p>Welcome, {{ recipient.name }}!</p>
<a href="{{ url_for('request_blood') }}" class="btn btn-primary">Request Blood</a>
<a href="{{ url_for('view_requests') }}" class="btn btn-secondary">View Requests</a>
{% endblock %}

admin_dashboard.html


{% extends 'base.html' %}
{% block content %}
<h2>Admin Dashboard</h2>
<p>Welcome, Admin!</p>
<a href="{{ url_for('manage_inventory') }}" class="btn btn-primary">Manage Inventory</a>
<a href="{{ url_for('view_inventory') }}" class="btn btn-secondary">View Inventory</a>
{% endblock %}

donate_blood.html


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

request_blood.html


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

view_inventory.html


{% extends 'base.html' %}
{% block content %}
<h2>Blood Inventory</h2>
<table class="table">
<thead>
<tr>
<th>Blood Type</th>
<th>Quantity (in ml)</th>
<th>Last Updated</th>
</tr>
</thead>
<tbody>
{% for item in inventory %}
<tr>
<td>{{ item.blood_type }}</td>
<td>{{ item.quantity }}</td>
<td>{{ item.last_updated }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

view_donations.html


{% extends 'base.html' %}
{% block content %}
<h2>Your Donations</h2>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Donation Date</th>
<th>Quantity (in ml)</th>
</tr>
</thead>
<tbody>
{% for donation in donations %}
<tr>
<td>{{ donation.id }}</td>
<td>{{ donation.donation_date }}</td>
<td>{{ donation.quantity }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

view_requests.html


{% extends 'base.html' %}
{% block content %}
<h2>Your Requests</h2>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Blood Type</th>
<th> Quantity (in ml)</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for request in requests %}
<tr>
<td>{{ request.id }}</td>
<td>{{ request.blood_type }}</td>
<td>{{ request.quantity }}</td>
<td>{{ request.status }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

manage_inventory.html


{% extends 'base.html' %}
{% block content %}
<h2>Manage Blood Inventory</h2>
<table class="table">
<thead>
<tr>
<th>Blood Type</th>
<th>Quantity (in ml)</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for item in inventory %}
<tr>
<td>{{ item.blood_type }}</td>
<td>{{ item.quantity }}</td>
<td>
<a href="{{ url_for('edit_inventory', inventory_id=item.id) }}" class="btn btn-warning btn-sm">Edit</a>
<a href="{{ url_for('delete_inventory', inventory_id=item.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("Blood Bank 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 Blood Bank Management System using Flask and Bootstrap 5. You can expand upon this by adding features such as user roles, email notifications, and more complex blood inventory management.