Help Saving to JSON

Question:
The student data and teacher data doesn’t save therefore my printing breaks, I want to be able to save the data in the __init__ function rather than doing it after I create the object. I have tried to use AI but it isn’t working.

Repl link:
https://replit.com/@SalladShooter/Student-Database#main.py

main.py

from Student import *
import random

# List of first names and last names
first_names = ['John', 'Jane', 'Michael', 'Emily', 'David', 'Sarah']
last_names = ['Smith', 'Johnson', 'Brown', 'Wilson', 'Davis', 'Taylor']

# Generate random names
def generate_random_name():
    first_name = random.choice(first_names)
    last_name = random.choice(last_names)
    return first_name, last_name

# Generate random teachers and grades
def generate_random_data():
    teachers = ['Mr. Johnson', 'Ms. Smith', 'Mr. Davis', 'Ms. Brown', 'Mr. Wilson']
    grades = [random.randint(70, 100) for _ in range(len(teachers))]
    return {teacher: f"{grade}%" for teacher, grade in zip(teachers, grades)}

# Generate and save random students
for _ in range(10):
    first_name, last_name = generate_random_name()
    student_data = generate_random_data()
    student = Student(last_name, first_name, student_data)
    print(student)

student.print_class()

Student.py

import json

class Student:
    """
    Represents a student with a last name, first name, and a list of teachers and grades.
    """
    def __init__(self, lastName, firstName, teachers_grades: dict):
        self.lastName = lastName
        self.firstName = firstName
        self.teachers_grades = self._convert_grades(teachers_grades)
        self.save_json()  # Automatically save data when a student is created


    def _convert_grades(self, grades):
        converted_grades = {}
        for teacher, grade in grades.items():
            converted_grades[teacher] = float(grade.strip('%'))
        return converted_grades

    def save_json(self):
        student_database = {
            f"{self.lastName}, {self.firstName}": self.teachers_grades
        }
        with open('student-database.json', 'w') as json_file:
            json.dump(student_database, json_file, indent=4)

    def __str__(self):
        formatted_grades = "\n".join(f"\t| {teacher}: {grade}%" for teacher, grade in self.teachers_grades.items())
        return f"""
{self.lastName}, {self.firstName}
{formatted_grades}
        """

    def print_class(self, teacher_name=None):
        try:
            with open('student-database.json', 'r') as json_file:
                student_database = json.load(json_file)
        except Exception as e:
            print(f"An error occurred while reading the file: {e}")
            student_database = {}
    
        if teacher_name:
            if teacher_name in student_database:
                print(f"\nClass: {teacher_name}\n")
                for student, grade in student_database[teacher_name].items():
                    print(f"\t| {student} | {grade}")
            else:
                print(f"No class found for teacher: {teacher_name}")
        else:
            for teacher, students in student_database.items():
                print(f"\nClass: {teacher}\n")
                for student, grade in students.items():
                    print(f"\t| {student} | {grade}")
                    
    def print_students(self):
        print(f"{self.lastName}, {self.firstName}:")
        for teacher, grade in self.teachers_grades.items():
            print(f"\t| {teacher} | {grade}%")
1 Like

When you open a file using the w mode, you open the file for overwriting, then the data will be written again, the old data will be replaced with new ones.

You need if in the student-database.json there is nothing in the json file, we just enter student data into it, but if there is data in the file, we must read the current data of the file, convert it into a dictionary, add new data to the dictionary and write a new dictionary to the student-database.json file.

Corrected code of the save_json function:

        try:
            with open('student-database.json', 'r') as json_file_r:
                try:
                    data = json.load(json_file_r)
                    data[f"{self.lastName}, {self.firstName}"] = self.teachers_grades
                    with open('student-database.json', 'w') as json_file_w:
                        json.dump(data, json_file_w, indent=4)
                except Exception as err:
                    student_database = {
                        f"{self.lastName}, {self.firstName}": self.teachers_grades
                    }
                    with open('student-database.json', 'w') as json_file_w:
                        json.dump(student_database, json_file_w, indent=4)
        except FileNotFoundError:  # If the file doesn't exist yet.
            student_database = {
                f"{self.lastName}, {self.firstName}": self.teachers_grades
            }
            with open('student-database.json', 'w') as json_file_w:
                json.dump(student_database, json_file_w, indent=4)

In this function, first the student-database.json file opens for reading. Next, in the try block, the file data is decrypted. If the file is empty, an error will be caused and the except block will be executed, in which the data is simply written to the file. If there is already data in the file, then the file will be decrypted and its contents will fit into the dictionary, new data will be added to this dictionary, and a new dictionary will be written to the file.

1 Like

@KAlexK ok the students are working but the classes don’t work anymore. The save-json should also make classes with every student in that class with the grade.

1 Like

Hey there! I’ve fixed your code. Previously, your save_json method was overwriting the entire JSON file with the current student’s data. This meant that each time a new student was created, the previous student’s data would be lost. Instead of initializing the student_database as an empty dictionary every time, I load the existing data from the JSON file (if it exists). If the file doesn’t exist, it starts with an empty dictionary. I updated student_database by adding the new student’s data with a key that consists of their last name and first name (e.g., {self.lastName}, {self.firstName}). After updating student_database with the new student’s data, I save the entire updated dictionary back to the JSON file:

import json

class Student:
    """
    Represents a student with a last name, first name, and a list of teachers and grades.
    """
    def __init__(self, lastName, firstName, teachers_grades: dict):
        self.lastName = lastName
        self.firstName = firstName
        self.teachers_grades = self._convert_grades(teachers_grades)
        self.save_json()  # Automatically save data when a student is created

    def _convert_grades(self, grades):
        converted_grades = {}
        for teacher, grade in grades.items():
            converted_grades[teacher] = float(grade.strip('%'))
        return converted_grades

    def save_json(self):
        try:
            with open('student-database.json', 'r') as json_file:
                student_database = json.load(json_file)
        except FileNotFoundError:
            student_database = {}

        student_database[f"{self.lastName}, {self.firstName}"] = self.teachers_grades

        with open('student-database.json', 'w') as json_file:
            json.dump(student_database, json_file, indent=4)

    def __str__(self):
        formatted_grades = "\n".join(f"\t| {teacher}: {grade}%" for teacher, grade in self.teachers_grades.items())
        return f"""
{self.lastName}, {self.firstName}
{formatted_grades}
        """

    def print_class(self, teacher_name=None):
        try:
            with open('student-database.json', 'r') as json_file:
                student_database = json.load(json_file)
        except FileNotFoundError:
            student_database = {}
        except Exception as e:
            print(f"An error occurred while reading the file: {e}")
    
        if teacher_name:
            if teacher_name in student_database:
                print(f"\nClass: {teacher_name}\n")
                for student, grade in student_database[teacher_name].items():
                    print(f"\t| {student} | {grade}")
            else:
                print(f"No class found for teacher: {teacher_name}")
        else:
            for teacher, students in student_database.items():
                print(f"\nClass: {teacher}\n")
                for student, grade in students.items():
                    print(f"\t| {student} | {grade}")
                    
    def print_students(self):
        print(f"{self.lastName}, {self.firstName}:")
        for teacher, grade in self.teachers_grades.items():
            print(f"\t| {teacher} | {grade}%")

@Sky It still isn’t printing out the teachers correctly or saving them, for reference it should be like this:

Class: Mr. Brown
    | Brown, John | 87
    | Taylor, Emily | 92
    | etc…

It should also be save similar to how it is printed.

1 Like

So how is it printing instead?

IMG_0344

1 Like

There is no way; I ran the code on my local machine, and the code printed fine.

Is that how it’s printing? I’ll take a look right now. But, it saves I know that for a fact so.

1 Like