Final Project: Student Grade Management (Part 3)
In the previous two lessons, we built the data layer and the logic layer. In this lesson, we bring it all together — writing a complete command-line menu interface. After completing this lesson, you will have a truly usable student grade management system.
Complete System Code
Combine the code from the previous three lessons into one file, plus the menu interface:
Example: Complete Grade Management System
import json
import os
import statistics
# ====== Configuration ======
DATA_FILE = "grade_system.json"
DEFAULT_DATA = {
"students": {},
"subjects": ["Chinese", "Math", "English"],
"classes": []
}
# ====== Data Layer ======
def load_data():
if not os.path.exists(DATA_FILE):
save_data(DEFAULT_DATA.copy())
return DEFAULT_DATA.copy()
with open(DATA_FILE, "r", encoding="utf-8") as f:
return json.load(f)
def save_data(data):
with open(DATA_FILE, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def add_student(student_id, name, class_name):
data = load_data()
if student_id in data["students"]:
return False, f"Student ID {student_id} already exists!"
data["students"][student_id] = {"name": name, "class_name": class_name, "scores": {}}
if class_name not in data["classes"]:
data["classes"].append(class_name)
save_data(data)
return True, f"Added student: {name} ({student_id})"
def delete_student(student_id):
data = load_data()
if student_id not in data["students"]:
return False, f"Student ID {student_id} does not exist!"
name = data["students"][student_id]["name"]
del data["students"][student_id]
save_data(data)
return True, f"Deleted student: {name}"
def add_score(student_id, subject, score):
data = load_data()
if student_id not in data["students"]:
return False, f"Student ID {student_id} does not exist!"
if subject not in data["subjects"]:
return False, f"Subject {subject} does not exist!"
if not isinstance(score, (int, float)) or score < 0 or score > 100:
return False, "Score must be between 0 and 100!"
data["students"][student_id]["scores"][subject] = score
save_data(data)
return True, f"Entered {data['students'][student_id]['name']}'s {subject}: {score}"
# ====== Logic Layer ======
def get_student_report(student_id):
data = load_data()
student = data["students"].get(student_id)
if not student:
return None
report = {"name": student["name"], "class_name": student["class_name"],
"scores": dict(student["scores"])}
scores = list(student["scores"].values())
if scores:
report["average"] = round(sum(scores) / len(scores), 1)
report["total"] = sum(scores)
report["max_score"] = max(scores)
report["min_score"] = min(scores)
else:
report["average"] = report["total"] = report["max_score"] = report["min_score"] = None
return report
def get_class_ranking(class_name=None):
data = load_data()
results = []
for sid, info in data["students"].items():
if class_name and info["class_name"] != class_name:
continue
scores = list(info["scores"].values())
total = sum(scores) if scores else 0
avg = round(total / len(scores), 1) if scores else 0
results.append({"id": sid, "name": info["name"], "class": info["class_name"],
"total": total, "avg": avg, "count": len(scores)})
results.sort(key=lambda x: x["total"], reverse=True)
for i, r in enumerate(results, 1):
r["rank"] = i
return results
def get_subject_stats():
data = load_data()
stats = {}
for subject in data["subjects"]:
scores = []
for info in data["students"].values():
if subject in info["scores"]:
scores.append(info["scores"][subject])
if scores:
stats[subject] = {"avg": round(sum(scores) / len(scores), 1),
"max": max(scores), "min": min(scores), "count": len(scores)}
return stats
# ====== Presentation Layer ======
def show_main_menu():
print("\n" + "=" * 40)
print("Student Grade Management System")
print("=" * 40)
print("1. Student Management")
print("2. Grade Management")
print("3. Statistics and Reports")
print("4. View Data")
print("5. Exit")
print("=" * 40)
def show_student_menu():
print("\n--- Student Management ---")
print("1. Add Student")
print("2. Delete Student")
print("3. Return to Main Menu")
def show_score_menu():
print("\n--- Grade Management ---")
print("1. Enter Grade")
print("2. Return to Main Menu")
def show_stats_menu():
print("\n--- Statistics and Reports ---")
print("1. Individual Report Card")
print("2. School-Wide Ranking")
print("3. Subject Averages")
print("4. Return to Main Menu")
def student_management():
"""Student management submenu"""
while True:
show_student_menu()
choice = input("Enter choice: ").strip()
if choice == "1":
sid = input("Student ID: ").strip()
name = input("Name: ").strip()
cls = input("Class: ").strip()
success, msg = add_student(sid, name, cls)
print(f" {'OK' if success else 'Error'}: {msg}")
elif choice == "2":
sid = input("Enter student ID to delete: ").strip()
success, msg = delete_student(sid)
print(f" {'OK' if success else 'Error'}: {msg}")
elif choice == "3":
break
else:
print("Invalid choice!")
def score_management():
"""Grade management submenu"""
while True:
show_score_menu()
choice = input("Enter choice: ").strip()
if choice == "1":
sid = input("Student ID: ").strip()
subject = input("Subject: ").strip()
try:
score = float(input("Score (0-100): ").strip())
except ValueError:
print("Error: Score must be a number!")
continue
success, msg = add_score(sid, subject, score)
print(f" {'OK' if success else 'Error'}: {msg}")
elif choice == "2":
break
else:
print("Invalid choice!")
def stats_query():
"""Statistics query submenu"""
while True:
show_stats_menu()
choice = input("Enter choice: ").strip()
if choice == "1":
sid = input("Enter student ID: ").strip()
report = get_student_report(sid)
if not report:
print("Error: Student not found!")
continue
print(f"\nReport Card — {report['name']} ({report['class_name']})")
print("-" * 30)
for subject, score in report["scores"].items():
print(f" {subject}: {score}")
if report["total"] is not None:
print(f" Total: {report['total']}")
print(f" Average: {report['average']}")
print(f" Highest: {report['max_score']}")
print(f" Lowest: {report['min_score']}")
else:
print(" (No grades yet)")
elif choice == "2":
ranking = get_class_ranking()
if not ranking:
print("No data!")
continue
print("\nSchool-Wide Ranking")
print(f"{'Rank':<4}{'Name':<10}{'Class':<10}{'Total':<8}{'Avg':<6}")
print("-" * 38)
for r in ranking:
print(f"{r['rank']:<4}{r['name']:<10}{r['class']:<10}{r['total']:<8}{r['avg']:<6}")
elif choice == "3":
stats = get_subject_stats()
if not stats:
print("No grade data!")
continue
print("\nSubject Statistics")
print(f"{'Subject':<10}{'Average':<10}{'Max':<8}{'Min':<8}{'Count':<4}")
print("-" * 38)
for subject, info in stats.items():
print(f"{subject:<10}{info['avg']:<10}{info['max']:<8}{info['min']:<8}{info['count']:<4}")
elif choice == "4":
break
else:
print("Invalid choice!")
def view_data():
"""View raw data"""
data = load_data()
students = data["students"]
if not students:
print("No student data yet")
return
print(f"\nTotal: {len(students)} students")
for sid, info in sorted(students.items()):
scores = info["scores"]
score_str = ", ".join(f"{s}:{v}" for s, v in scores.items()) if scores else "No grades"
print(f" {sid} {info['name']} ({info['class_name']}) -> {score_str}")
# ====== Main Program ======
def main():
print("Welcome to the Student Grade Management System!")
while True:
show_main_menu()
choice = input("Select option (1-5): ").strip()
if choice == "1":
student_management()
elif choice == "2":
score_management()
elif choice == "3":
stats_query()
elif choice == "4":
view_data()
elif choice == "5":
print("Thank you for using the system! Goodbye!")
break
else:
print("Invalid choice. Please enter 1-5.")
if __name__ == "__main__":
main()
Sample Run
Welcome to the Student Grade Management System!
========================================
Student Grade Management System
========================================
1. Student Management
2. Grade Management
3. Statistics and Reports
4. View Data
5. Exit
========================================
Select option (1-5): 1
--- Student Management ---
1. Add Student
2. Delete Student
3. Return to Main Menu
Enter choice: 1
Student ID: 2024001
Name: Zhang San
Class: Class 1
OK: Added student: Zhang San (2024001)
Project Summary
| Layer | Functions | Responsibility |
|---|---|---|
| Data Layer | load/save_data |
JSON file I/O |
| Entity Layer | add/delete_student |
Student CRUD |
| Entity Layer | add_score |
Grade CRUD |
| Logic Layer | get_student_report |
Individual report card |
| Logic Layer | get_class_ranking |
Ranking calculation |
| Logic Layer | get_subject_stats |
Subject statistics |
| Presentation Layer | main/main_menu |
Menu loop |
| Presentation Layer | student/score/stats_management |
Submenus |
FAQ
while True loop in the command menu cause an infinite loop?break to exit the loop. As long as each menu has a "quit" option, it's safe.in keyword sufficient for fuzzy search, or do I need regular expressions?keyword in name is sufficient. If you need more complex searches (match only at the start, case-insensitive, multi-keyword combinations), you would need regular expressions — covered in Lesson 31..py file directly — anyone with Python installed can run it. To create an executable (.exe), use PyInstaller: pip install pyinstaller && pyinstaller --onefile main.py.Summary
- Three-layer architecture: Data Layer -> Logic Layer -> Presentation Layer, each with clear responsibilities
- Data Layer: JSON file read/write encapsulation, basic CRUD operations
- Logic Layer: Grade statistics, ranking, analysis business rules
- Presentation Layer: Menu interface, input/output, user interaction
- Exception handling: Input validation, empty data handling, file-not-found handling
- The project totals approximately 200 lines of core code, implementing a complete student grade management system
Exercises
-
Beginner (Difficulty: Star): Run the complete system, add 3 students and their grades, and generate a ranking report.
-
Intermediate (Difficulty: Star-Star): Add an "export report" feature to the system that exports the ranking results to a
ranking.csvfile (using thecsvmodule). -
Advanced (Difficulty: Star-Star-Star): Without referring to the code above, build a "Book Sales Management System" from scratch. Features include: add book (title, author, unit price, stock), record sale (book title, quantity -> auto-decrease stock), view inventory report (sorted by sales volume). Use JSON for data persistence.



