Student Report Card System | Class 12 CS Project

Student Report Card System – Class 12 CS Project in Python

CBSE Class 12 Computer Science Investigatory Project

Topics Covered: File Handling, CSV Module, Functions,  Lists, Dictionaries, String Formatting

 

# ============================================================
#  STUDENT REPORT CARD SYSTEM
#  CBSE Class 12 Computer Science Investigatory Project
#  Topics Covered: File Handling, CSV Module, Functions,
#                  Lists, Dictionaries, String Formatting
# ============================================================
#
#  REQUIREMENTS:
#    - Python 3.x  (no extra pip install needed)
#    - Modules used: csv, os, datetime (all built-in)
#
#  HOW TO RUN:
#    python student_report_card.py
#
#  FILE CREATED:
#    students.csv  — stores all student records
# ============================================================

import csv
import os
from datetime import datetime

# ─────────────────────────────────────────────
#  CONSTANTS
# ─────────────────────────────────────────────

CSV_FILE = "students.csv"

SUBJECTS = ["English", "Mathematics", "Science", "Social_Science", "Computer_Science"]

FIELDNAMES = ["Roll_No", "Name", "Class", "Section",
              "English", "Mathematics", "Science",
              "Social_Science", "Computer_Science",
              "Total", "Percentage", "Grade", "Result", "Date"]

# Grade boundaries
def get_grade(percentage):
    if percentage >= 91:
        return "A1"
    elif percentage >= 81:
        return "A2"
    elif percentage >= 71:
        return "B1"
    elif percentage >= 61:
        return "B2"
    elif percentage >= 51:
        return "C1"
    elif percentage >= 41:
        return "C2"
    elif percentage >= 33:
        return "D"
    else:
        return "E (Fail)"

def get_result(marks_list):
    """Pass only if all subjects >= 33"""
    for m in marks_list:
        if m < 33:
            return "FAIL"
    return "PASS"

# ─────────────────────────────────────────────
#  FILE HANDLING — CSV OPERATIONS
# ─────────────────────────────────────────────

def initialize_file():
    """Create CSV file with header if it doesn't exist."""
    if not os.path.exists(CSV_FILE):
        with open(CSV_FILE, "w", newline="") as f:
            writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
            writer.writeheader()
        print(f"\n  [INFO] New data file '{CSV_FILE}' created.")

def read_all_students():
    """Read all student records from CSV. Returns list of dicts."""
    records = []
    with open(CSV_FILE, "r", newline="") as f:
        reader = csv.DictReader(f)
        for row in reader:
            records.append(row)
    return records

def write_all_students(records):
    """Overwrite CSV with given list of dicts."""
    with open(CSV_FILE, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
        writer.writeheader()
        writer.writerows(records)

def append_student(record):
    """Append a single student record to CSV."""
    with open(CSV_FILE, "a", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=FIELDNAMES)
        writer.writerow(record)

def roll_exists(roll_no):
    """Check if a Roll Number already exists."""
    records = read_all_students()
    for r in records:
        if r["Roll_No"] == str(roll_no):
            return True
    return False

# ─────────────────────────────────────────────
#  DISPLAY HELPERS
# ─────────────────────────────────────────────

LINE = "=" * 72

def print_header(title):
    print("\n" + LINE)
    print(f"  {title.upper()}")
    print(LINE)

def print_report_card(r):
    """Print a formatted report card for one student."""
    print("\n" + "+" + "-" * 60 + "+")
    print("|{:^60}|".format("STUDENT REPORT CARD"))
    print("|{:^60}|".format("CBSE Class 12 — Academic Year 2025-26"))
    print("+" + "-" * 60 + "+")
    print(f"  Roll No    : {r['Roll_No']}")
    print(f"  Name       : {r['Name']}")
    print(f"  Class      : {r['Class']}  |  Section : {r['Section']}")
    print(f"  Date       : {r['Date']}")
    print("+" + "-" * 60 + "+")
    print(f"  {'SUBJECT':<25} {'MARKS (out of 100)':>20}")
    print("  " + "-" * 45)
    for sub in SUBJECTS:
        label = sub.replace("_", " ")
        print(f"  {label:<25} {r[sub]:>20}")
    print("  " + "-" * 45)
    print(f"  {'TOTAL':<25} {r['Total']:>20}")
    print(f"  {'PERCENTAGE':<25} {r['Percentage']:>19}%")
    print(f"  {'GRADE':<25} {r['Grade']:>20}")
    print(f"  {'RESULT':<25} {r['Result']:>20}")
    print("+" + "-" * 60 + "+\n")

def print_table(records):
    """Print all students as a compact table."""
    if not records:
        print("\n  [!] No records found.\n")
        return
    print("\n" + LINE)
    header = f"  {'Roll':<6} {'Name':<20} {'Class':<6} {'Sec':<4} {'Total':<7} {'%':<7} {'Grade':<6} {'Result'}"
    print(header)
    print("  " + "-" * 68)
    for r in records:
        row = (f"  {r['Roll_No']:<6} {r['Name']:<20} {r['Class']:<6} "
               f"{r['Section']:<4} {r['Total']:<7} {r['Percentage']:<7} "
               f"{r['Grade']:<6} {r['Result']}")
        print(row)
    print(LINE)

# ─────────────────────────────────────────────
#  FEATURE 1 — ADD STUDENT
# ─────────────────────────────────────────────

def add_student():
    print_header("Add New Student")

    # ── Roll Number ──
    while True:
        roll = input("  Enter Roll Number : ").strip()
        if not roll.isdigit():
            print("  [!] Roll number must be numeric. Try again.")
            continue
        if roll_exists(roll):
            print(f"  [!] Roll No {roll} already exists. Use Update option.")
            return
        break

    name = input("  Enter Student Name : ").strip().title()
    if not name:
        print("  [!] Name cannot be empty.")
        return

    cls = input("  Enter Class (e.g. 12) : ").strip()
    section = input("  Enter Section (e.g. A) : ").strip().upper()

    # ── Marks Input ──
    print("\n  Enter marks for each subject (0 – 100):\n")
    marks = {}
    for sub in SUBJECTS:
        while True:
            try:
                m = int(input(f"    {sub.replace('_', ' '):<22}: "))
                if 0 <= m <= 100:
                    marks[sub] = m
                    break
                else:
                    print("    [!] Marks must be between 0 and 100.")
            except ValueError:
                print("    [!] Please enter a valid integer.")

    # ── Calculations ──
    marks_list = list(marks.values())
    total      = sum(marks_list)
    percentage = round(total / len(SUBJECTS), 2)
    grade      = get_grade(percentage)
    result     = get_result(marks_list)
    date       = datetime.today().strftime("%d-%m-%Y")

    record = {
        "Roll_No"         : roll,
        "Name"            : name,
        "Class"           : cls,
        "Section"         : section,
        "English"         : marks["English"],
        "Mathematics"     : marks["Mathematics"],
        "Science"         : marks["Science"],
        "Social_Science"  : marks["Social_Science"],
        "Computer_Science": marks["Computer_Science"],
        "Total"           : total,
        "Percentage"      : percentage,
        "Grade"           : grade,
        "Result"          : result,
        "Date"            : date,
    }

    append_student(record)
    print(f"\n  ✓ Student '{name}' (Roll No: {roll}) added successfully!")
    print_report_card(record)

# ─────────────────────────────────────────────
#  FEATURE 2 — VIEW REPORT CARD (by Roll No)
# ─────────────────────────────────────────────

def view_report_card():
    print_header("View Student Report Card")
    roll = input("  Enter Roll Number to search : ").strip()
    records = read_all_students()
    for r in records:
        if r["Roll_No"] == roll:
            print_report_card(r)
            return
    print(f"\n  [!] No student found with Roll No: {roll}\n")

# ─────────────────────────────────────────────
#  FEATURE 3 — DISPLAY ALL STUDENTS
# ─────────────────────────────────────────────

def display_all():
    print_header("All Student Records")
    records = read_all_students()
    if not records:
        print("\n  [!] No records in the database yet.\n")
        return
    print(f"\n  Total Students: {len(records)}")
    print_table(records)

# ─────────────────────────────────────────────
#  FEATURE 4 — UPDATE MARKS
# ─────────────────────────────────────────────

def update_student():
    print_header("Update Student Marks")
    roll = input("  Enter Roll Number to update : ").strip()
    records = read_all_students()
    found = False

    for i, r in enumerate(records):
        if r["Roll_No"] == roll:
            found = True
            print(f"\n  Found: {r['Name']} | Class {r['Class']}-{r['Section']}")
            print("\n  Re-enter marks for each subject (press Enter to keep old value):\n")

            for sub in SUBJECTS:
                while True:
                    old = r[sub]
                    val = input(f"    {sub.replace('_',' '):<22} [current: {old}]: ").strip()
                    if val == "":
                        break   # keep old
                    if val.isdigit() and 0 <= int(val) <= 100:
                        r[sub] = val
                        break
                    else:
                        print("    [!] Enter a number between 0 and 100.")

            # Recalculate
            marks_list    = [int(r[s]) for s in SUBJECTS]
            r["Total"]      = sum(marks_list)
            r["Percentage"] = round(r["Total"] / len(SUBJECTS), 2)
            r["Grade"]      = get_grade(r["Percentage"])
            r["Result"]     = get_result(marks_list)
            r["Date"]       = datetime.today().strftime("%d-%m-%Y")

            records[i] = r
            write_all_students(records)
            print(f"\n  ✓ Marks updated for Roll No: {roll}")
            print_report_card(r)
            break

    if not found:
        print(f"\n  [!] No student found with Roll No: {roll}\n")

# ─────────────────────────────────────────────
#  FEATURE 5 — DELETE STUDENT
# ─────────────────────────────────────────────

def delete_student():
    print_header("Delete Student Record")
    roll = input("  Enter Roll Number to delete : ").strip()
    records = read_all_students()
    new_records = [r for r in records if r["Roll_No"] != roll]

    if len(new_records) == len(records):
        print(f"\n  [!] No student found with Roll No: {roll}\n")
        return

    confirm = input(f"  Are you sure you want to delete Roll No {roll}? (yes/no): ").strip().lower()
    if confirm == "yes":
        write_all_students(new_records)
        print(f"\n  ✓ Record with Roll No {roll} deleted successfully.\n")
    else:
        print("  [i] Deletion cancelled.\n")

# ─────────────────────────────────────────────
#  FEATURE 6 — SEARCH BY NAME
# ─────────────────────────────────────────────

def search_by_name():
    print_header("Search Student by Name")
    keyword = input("  Enter name (or part of name) to search : ").strip().lower()
    records = read_all_students()
    results = [r for r in records if keyword in r["Name"].lower()]

    if not results:
        print(f"\n  [!] No student found matching '{keyword}'\n")
    else:
        print(f"\n  Found {len(results)} record(s):\n")
        print_table(results)

# ─────────────────────────────────────────────
#  FEATURE 7 — CLASS TOPPER
# ─────────────────────────────────────────────

def class_topper():
    print_header("Class Topper")
    records = read_all_students()
    if not records:
        print("\n  [!] No records available.\n")
        return

    topper = max(records, key=lambda r: float(r["Percentage"]))
    print(f"\n  🏆 CLASS TOPPER: {topper['Name']}  (Roll No: {topper['Roll_No']})")
    print(f"     Percentage : {topper['Percentage']}%  |  Grade : {topper['Grade']}")
    print_report_card(topper)

# ─────────────────────────────────────────────
#  FEATURE 8 — SUBJECT-WISE STATISTICS
# ─────────────────────────────────────────────

def subject_statistics():
    print_header("Subject-Wise Statistics")
    records = read_all_students()
    if not records:
        print("\n  [!] No records available.\n")
        return

    print(f"\n  {'SUBJECT':<25} {'HIGHEST':>8} {'LOWEST':>8} {'AVERAGE':>10}")
    print("  " + "-" * 55)
    for sub in SUBJECTS:
        marks = [int(r[sub]) for r in records]
        high  = max(marks)
        low   = min(marks)
        avg   = round(sum(marks) / len(marks), 2)
        print(f"  {sub.replace('_',' '):<25} {high:>8} {low:>8} {avg:>10}")
    print()

# ─────────────────────────────────────────────
#  FEATURE 9 — PASS / FAIL LIST
# ─────────────────────────────────────────────

def pass_fail_list():
    print_header("Pass / Fail Summary")
    records = read_all_students()
    if not records:
        print("\n  [!] No records available.\n")
        return

    passed = [r for r in records if r["Result"] == "PASS"]
    failed = [r for r in records if r["Result"] == "FAIL"]

    print(f"\n  Total Students : {len(records)}")
    print(f"  Passed         : {len(passed)}")
    print(f"  Failed         : {len(failed)}")

    if failed:
        print("\n  --- FAILED STUDENTS ---")
        print_table(failed)
    else:
        print("\n  🎉 All students have PASSED!\n")

# ─────────────────────────────────────────────
#  FEATURE 10 — GRADE-WISE DISTRIBUTION
# ─────────────────────────────────────────────

def grade_distribution():
    print_header("Grade-Wise Distribution")
    records = read_all_students()
    if not records:
        print("\n  [!] No records available.\n")
        return

    grade_order = ["A1", "A2", "B1", "B2", "C1", "C2", "D", "E (Fail)"]
    dist = {g: 0 for g in grade_order}
    for r in records:
        g = r["Grade"]
        if g in dist:
            dist[g] += 1

    print(f"\n  {'GRADE':<12} {'COUNT':>6}  BAR")
    print("  " + "-" * 40)
    for g in grade_order:
        bar = "█" * dist[g]
        print(f"  {g:<12} {dist[g]:>6}  {bar}")
    print()

# ─────────────────────────────────────────────
#  MAIN MENU
# ─────────────────────────────────────────────

def main_menu():
    initialize_file()
    while True:
        print("\n" + LINE)
        print("       STUDENT REPORT CARD SYSTEM — CBSE CLASS 12")
        print(LINE)
        print("   1. Add New Student")
        print("   2. View Report Card (by Roll No)")
        print("   3. Display All Students")
        print("   4. Update Student Marks")
        print("   5. Delete Student Record")
        print("   6. Search Student by Name")
        print("   7. Class Topper")
        print("   8. Subject-Wise Statistics")
        print("   9. Pass / Fail Summary")
        print("  10. Grade-Wise Distribution")
        print("   0. Exit")
        print(LINE)

        choice = input("  Enter your choice: ").strip()

        if   choice == "1": add_student()
        elif choice == "2": view_report_card()
        elif choice == "3": display_all()
        elif choice == "4": update_student()
        elif choice == "5": delete_student()
        elif choice == "6": search_by_name()
        elif choice == "7": class_topper()
        elif choice == "8": subject_statistics()
        elif choice == "9": pass_fail_list()
        elif choice == "10": grade_distribution()
        elif choice == "0":
            print("\n  Thank you for using Student Report Card System. Goodbye!\n")
            break
        else:
            print("\n  [!] Invalid choice. Please enter a number from 0 to 10.\n")

# ─────────────────────────────────────────────
#  ENTRY POINT
# ─────────────────────────────────────────────

if __name__ == "__main__":
    main_menu()

 

Copywrite © 2020-2026, CBSE Python,
All Rights Reserved