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()