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

PYTHON
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()
▶ Try it Yourself

Sample Run

TEXT
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

Q Won't the while True loop in the command menu cause an infinite loop?
A No, because each menu has an option (e.g., entering 0 or a specific number) that executes break to exit the loop. As long as each menu has a "quit" option, it's safe.
Q Is the in keyword sufficient for fuzzy search, or do I need regular expressions?
A For this project, 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.
Q How do I package the project for others to use?
A The simplest way is to send the .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


Exercises

  1. Beginner (Difficulty: Star): Run the complete system, add 3 students and their grades, and generate a ranking report.

  2. Intermediate (Difficulty: Star-Star): Add an "export report" feature to the system that exports the ranking results to a ranking.csv file (using the csv module).

  3. 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.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏