LambdaLabTM
Computer Science · Class 12 Project · Subject Code 083
Sample ProjectPython + MySQL⏱️ 12 min read

Blood Donor Directory

Find donors of the right group who are medically eligible to give today.

1Introduction: the problem it solves

A local blood donation drive keeps donor phone numbers in a WhatsApp group and a notebook. When a hospital needs O-negative at short notice, somebody scrolls. Worse, people are called who donated three weeks ago and cannot give again yet.

Both problems are one query: the right group, and only those past the ninety-day gap.

who would use it

A blood donation camp, an NGO, a college NSS unit, or a hospital's volunteer list.

Why it is worth computerising

A local camp's donor list is usually a chat group and a notebook. That is enough until a hospital needs a particular blood group at short notice, at which point somebody scrolls through months of messages while time passes.

The harder problem is eligibility, and it is invisible on paper. A donor who gave three weeks ago cannot give again, and calling them wastes both their time and the camp's. Storing the last donation date lets the computer apply the ninety-day rule to every name at once, so the list produced is not just the right blood group but the people who can actually donate today.

Objectives

  1. To keep donor contacts in one searchable place rather than in a chat group
  2. To find donors of a required blood group in seconds
  3. To exclude anyone who has donated within the last ninety days, automatically
  4. To include first-time donors, whose last donation date is empty
  5. To record a donation and report when that donor may next give

2How the job is done today

Before writing anything it is worth asking how the work is handled at present, and why each of those answers falls short. These were examined:

WhatsApp group and notebook

How most local camps run. It works until somebody needs a specific group urgently, and it cannot tell who is eligible today.

National donor registries (e-RaktKosh)

Authoritative and national. A local camp still needs its own list of people it can actually call this evening.

Spreadsheet of donors

Sortable by group, which is half the problem solved. The eligibility gap still has to be worked out by hand for each name.

3Functionalities

  • A donor table with the blood group, contact, area and last donation date
  • Search by blood group
  • Eligibility built into the search — nobody who donated within ninety days is listed
  • Donors who have never given are included, since NULL means eligible
  • Recording a donation updates the date and reports when they may next give
  • Results grouped by area, so the nearest donors are easy to spot

The functions that provide them

FunctionArgumentsWhat it does
add_donor()name, group, phone, areaAdd a new volunteer, who has not donated yet.
find_eligible()groupEveryone of this group who has not donated in the last 90 days.
record_donation()donor_idStamp today's date against a donor, and say when they may give again.

4Technical details

LanguagePython 3
StorageMySQL, through mysql-connector-python
Modules used
  • mysql.connector — the database connection
  • datetime — the ninety-day eligibility gap
  • MySQL — one table, with a NULL that carries meaning

5How the data is stored

`last_donation` is deliberately allowed to be NULL, and NULL means 'never donated'. The query has to say so explicitly — `last_donation IS NULL OR last_donation <= cut-off` — because a plain comparison silently drops NULL rows, which would hide every first-time donor.

Table: donors

FieldTypeDescription
donor_idINT (primary key, auto)Unique number for each donor
nameVARCHAR(40) (required)Donor's name
blood_groupVARCHAR(4) (required)Blood group, e.g. O+
phoneVARCHAR(12)Contact number
areaVARCHAR(20)Locality, used to find the nearest donors
last_donationDATEDate last donated; empty means never, which counts as eligible

Sample rows in donors

nameblood_groupphonearealast_donation
Ananya SenO+9800000001Gangtok2026-01-10
Rohit DasO+9800000002SingtamNULL
Meera RaiA+9800000003Rangpo2026-08-01
Karan PradhanO+9800000004Gangtok2026-08-20

6How it works, step by step

1
Add

add_donor() INSERTs a new volunteer with last_donation left NULL.

2
Cut-off

date.today() - timedelta(days=90) is the latest donation date that still allows giving today.

3
Search

One SELECT filtered by group and eligibility, ordered by area.

4
Record

record_donation() stamps today's date and reports the next eligible date.

7Source code

donors.py
# ---------------------------------------------------------------------------
# donors.py
#
# Donor directory for the LambdaLab blood donation camp, using Python with
# MySQL.
#
# The point of the program is not the list, it is the eligibility: a donor who
# gave three weeks ago cannot give again, and calling them wastes everybody's
# time.
# ---------------------------------------------------------------------------

import mysql.connector
from datetime import date, timedelta

GAP_DAYS = 90                  # a donor must wait this long between donations

db = mysql.connector.connect(host="localhost", user="root",
                             passwd="camp", database="lambdalab_donors")
cur = db.cursor()


def add_donor(name, group, phone, area):
    """Add a new volunteer, who has not donated yet."""
    # last_donation is left NULL, which is how "never donated" is recorded.
    # NULL is not the same as zero or an empty string: it means there is no
    # value at all.
    cur.execute("INSERT INTO donors (name, blood_group, phone, area, last_donation)"
                " VALUES (%s, %s, %s, %s, NULL)", (name, group, phone, area))

    db.commit()
    print("{} added to the {} list.".format(name, group))


def find_eligible(group):
    """Everyone of this group who has not donated in the last 90 days."""
    # Today minus ninety days is the latest donation date that still allows
    # somebody to give today.
    cutoff = date.today() - timedelta(days=GAP_DAYS)

    # The IS NULL half of this test is essential. A plain comparison drops rows
    # where the value is NULL, so without it every first-time donor — exactly
    # the people most willing to help — would silently disappear from the list.
    cur.execute("SELECT name, phone, area, last_donation FROM donors"
                " WHERE blood_group = %s AND (last_donation IS NULL OR last_donation <= %s)"
                " ORDER BY area", (group, cutoff))

    rows = cur.fetchall()

    print("ELIGIBLE {} DONORS ({} found)".format(group, len(rows)))
    print("{:<18}{:<14}{:<14}{:<12}".format("NAME", "PHONE", "AREA", "LAST GAVE"))

    for name, phone, area, last in rows:
        # A donor with no date shows as "never" rather than as an empty column.
        print("{:<18}{:<14}{:<14}{:<12}".format(name, phone, area,
                                                str(last) if last else "never"))


def record_donation(donor_id):
    """Stamp today's date against a donor, and say when they may give again."""
    cur.execute("UPDATE donors SET last_donation = %s WHERE donor_id = %s",
                (date.today(), donor_id))

    db.commit()
    print("Thank you. Next donation possible after {}.".format(
        date.today() + timedelta(days=GAP_DAYS)))


# --- the program itself ----------------------------------------------------

find_eligible("O+")            # who can give O+ blood today

db.close()
schema.sql
CREATE DATABASE IF NOT EXISTS lambdalab_donors;
USE lambdalab_donors;

CREATE TABLE donors (
    donor_id      INT PRIMARY KEY AUTO_INCREMENT,
    name          VARCHAR(40) NOT NULL,
    blood_group   VARCHAR(4)  NOT NULL,
    phone         VARCHAR(12),
    area          VARCHAR(20),
    last_donation DATE DEFAULT NULL
);

INSERT INTO donors (name, blood_group, phone, area, last_donation) VALUES
    ('Ananya Sen',    'O+', '9800000001', 'Gangtok', '2026-01-10'),
    ('Rohit Das',     'O+', '9800000002', 'Singtam', NULL),
    ('Meera Rai',     'A+', '9800000003', 'Rangpo',  '2026-08-01'),
    ('Karan Pradhan', 'O+', '9800000004', 'Gangtok', '2026-08-20');
⬇️ Take it with you

The full report as a PDF — cover page, certificate, index, code, output, future scope and references, ready to print and fill in. Or the code on its own as a zip.

or one file:

8Sample output

This is a real run, not a mock-up — the transcript below is what the program actually printed.

Command Prompt
C:\LambdaLab\Projects\Blood-Donors> python donors.py
ELIGIBLE O+ DONORS (2 found)
NAME              PHONE         AREA          LAST GAVE   
Ananya Sen        9800000001    Gangtok       2026-01-10  
Rohit Das         9800000002    Singtam       never
Note
Before this will run, import schema.sql into MySQL and change the user and password in the connect() call to your own. The output above is what the queries return against the sample rows in that schema.

9Testing

Every case below was actually run and the result recorded as it appeared — including the ones expected to fail.

Test caseExpectedActual
Eligible O+ donors todayTwo, one of whom has never given2 eligible
A donor who gave six days agoExcluded by the ninety-day rule1 extra if the gap is ignored
A first-time donor, last_donation NULLIncludedRohit Das is included
Without the IS NULL test in the WHEREFirst-timers silently disappear1 found instead of 2
A blood group nobody hasNo rows, no error0 eligible

Two kinds of case are in there on purpose. The boundary cases test the edge of a rule, where a program is most often wrong by one. The failure cases check that it refuses cleanly and says why, instead of quietly producing a wrong answer.

10Advantages

Set against the ways the job is done today:

  • A donor of the right group is found in seconds, not by scrolling
  • Nobody ineligible is called, which respects the donor's time
  • First-time donors are included rather than filtered out by accident
  • The list is ordered by area, so the nearest are contacted first
  • The next eligible date is recorded the moment a donation is made

11Future scope

What this version does not do

A report should be honest about its own limits, and each of these is the reason for one of the additions below:

  • Age, weight and haemoglobin, which real eligibility also depends on, are not recorded
  • The ninety-day gap is applied to everyone; it differs by type of donation
  • There is no record of which hospital or camp a donation went to
  • Contact details are stored in plain text, with no access control

Proposed enhancements

This is also where you make the project yours. Pick one or two of these, or something nobody here thought of:

  • Send a group SMS to everyone eligible in one area
  • Record which hospital each donation went to
  • A thank-you message on the donor's anniversary
  • Age and weight checks, which real eligibility also depends on
  • A public page where a hospital can raise a request

12What you may have to teach yourself

CBSE expects some self-learning in a project, and says so. For this one, that means:

  • How NULL behaves in a WHERE clause — this project fails quietly if you get it wrong
  • The real medical rules for donation gaps in India, which differ by donation type
  • Handling personal data responsibly: ask before you store a phone number

13Conclusion

A request for a blood group now produces a list of people who can actually donate today, rather than a list of everybody who once said they would.

The interesting part was the NULL. A donor who has never given has no last-donation date, and a query written without thinking about that would have hidden exactly the people most willing to help.

14References

Every report needs a bibliography. This one used:

  • Computer Science with Python, Class XII — the NCERT / CBSE prescribed textbook, for the chapters on database concepts, SQL and interfacing Python with a database
  • Computer Science with Python, Class XI — for functions, lists, dictionaries and string handling
  • Python 3 documentation — https://docs.python.org/3/
  • MySQL 8.0 Reference Manual and the Connector/Python Developer Guide — https://dev.mysql.com/doc/
  • CBSE Senior School Curriculum, Computer Science (Subject Code 083) — the project guidelines this report follows
  • LambdaLab — https://www.lambdalab.in
Key Takeaway
The PDF above is the whole report. Cover page, certificate, acknowledgement, index, everything on this page, and the references — in the order CBSE marks them, ready to print. The cover page, certificate and acknowledgement arrive with blank rules where names go, because a certificate with somebody else's name printed on it is not a template. Fill those in, get the certificate signed, and replace the problem with one you have looked into yourself.