You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Tkinter中on_return方法触发KeyError: 'id'问题求助

解决UpdateStudent框架跳转时的KeyError问题

每次点击前一窗口的更新按钮,后续的UpdateStudent框架无法正常显示,终端弹出如下错误:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.11_3.11.1008.0_x64__qbz5n2kfra8p0\Lib\tkinter\__init__.py", line 1948, in __call__
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "c:\Users\Charles Mendoza\Desktop\Student Management System\pages.py", line 868, in update_student
    self.go_to_update_form()
  File "c:\Users\Charles Mendoza\Desktop\Student Management System\pages.py", line 880, in go_to_update_form
    self.parent.change_window("UpdateStudent")
  File "c:\Users\Charles Mendoza\Desktop\Student Management System\main.py", line 36, in change_window
    self.frames[name].on_return(**kwargs)
  File "c:\Users\Charles Mendoza\Desktop\Student Management System\pages.py", line 1420, in on_return
    self.student_id = kwargs['id']
                      ~~~~~~^^^^^^
KeyError: 'id'

以下是UpdateStudent类的完整代码:

class UpdateStudent(Frame):
    
    def __init__(self, master):
        Frame.__init__(self, master)
        self.parent = master
        
        self.background = Image.open('pictures/school.jpg')
        self.image_res = self.background.resize((1000, 800))
        self.picture = ImageTk.PhotoImage(self.image_res)
        self.background_panel = Label(self, image = self.picture)
        self.background_panel.pack(fill = BOTH, expand = 'yes')
        
        self.login_box = Frame(self, bg='#DAD8D8', width = "970", height = "770")
        self.login_box.place (x = 10, y = 10)
        
        self.id_label = Label(self, text = "ID:",bg='#DAD8D8')
        self.id_label.place(x = 105, y = 20)
        self.id_label2 = Label(self, text = "XX" , bg = "#DAD8D8")
        self.id_label2.place(x = 150, y = 20)
        self.student_name_label = Label(self, text ="Student Name:", bg = "#DAD8D8")
        self.student_name_label.place(x = 40, y = 40 )
        self.student_name_field = Entry(self)
        self.student_name_field.place(x = 140, y = 40, width = 180)
        self.course_label = Label(self, text = "Course:", bg = "#DAD8D8")
        self.course_label.place(x= 80, y = 60 )
        self.course_field = Entry(self)
        self.course_field.place(x =140, y = 60, width = 180)
        self.birthdate_label = Label(self, text = "Birthdate:", bg = "#DAD8D8")
        self.birthdate_label.place(x = 70, y = 80)
        self.birthdate_field = Entry(self)
        self.birthdate_field.place(x = 140, y = 80, width = 180 )
        self.gender_label = Label(self, text = "Gender:", bg = "#DAD8D8")
        self.gender_label.place(x = 80, y = 100 )
        self.gender_field = Entry(self)
        self.gender_field.place(x =140, y = 100, width = 180 )
        self.contact_number_label = Label(self, text = "Contact Number:", bg = "#DAD8D8")
        self.contact_number_label.place(x = 30, y = 120 )
        self.contact_number_field = Entry(self)
        self.contact_number_field.place(x =140, y = 120, width = 180 )
        self.email_label = Label(self, text = "Email:", bg = "#DAD8D8")
        self.email_label.place(x =90, y = 140)
        self.email_field = Entry(self)
        self.email_field.place(x = 140, y = 140, width = 180)
        self.instructor_label = Label(self, text = "Instructor:", bg = "#DAD8D8")
        self.instructor_label.place(x = 70, y = 160)
        self.instructor_field = Entry(self)
        self.instructor_field.place(x = 140, y = 160, width = 180)
        self.balance_label = Label(self, text = "Balance:", bg = "#DAD8D8")
        self.balance_label.place(x = 80, y = 180)
        self.balance_field = Entry(self)
        self.balance_field.place(x = 140, y = 180, width = 180)
        self.username_label = Label(self, text = "Username:", bg = "#DAD8D8")
        self.username_label.place(x = 70, y = 200)
        self.username_field = Entry(self)
        self.username_field.place(x = 140, y = 200, width = 180)
        self.password_label = Label(self, text = "Password:", bg = "#DAD8D8")
        self.password_label.place(x =70, y = 220 )
        self.password_field = Entry(self)
        self.password_field.place(x = 140, y = 220, width = 180)
        
        self.update_button = Button(self, text="Update Information", command = self.update_student)
        self.update_button.place(x = 200, y = 250)
        
        columns = ('id', 'balance')
        self.table = ttk.Treeview(self, columns = columns, show = 'headings', selectmode = 'browse')
        self.table.heading('id', text = "Student ID")
        
        self.table.heading('balance', text = "Balance")
        self.table.column('id', width = 200)
        self.table.column('balance', width = 120)
        
        self.table.place(x = 400, y = 40)
        self.table.config(height = 20)
        
        self.update_table()
        
    def update_table(self, event = None):
        self.student_list = self.get_student_list()
        
        self.table.delete(*self.table.get_children())
        
        for student in self.student_list:
            row = (
                student.student_name,
                student.course,
                student.birthdate,
                student.gender,
                student.contact_number,
                student.email,
                student.instructor,
                student.balance,
                student.username,
                student.password,
                student.grade
            )
            self.table.insert('', END, values = row)
        
    def get_student_list(self):
        db_conn = database_handler.DBHandler()
        self.Student_list = db_conn.read_student()
        db_conn.close()
        return self.Student_list
    
    def validate_data(self):
        return True
    
    def update_student(self):
        if not self.validate_data():
            return
        
        try:
            self.student_name = self.student_name_field.get()
            self.course = self.course_field.get()
            self.birthdate = self.birthdate_field.get()
            self.gender = self.gender_field.get()
            self.contact_number = int(self.contact_number_field.get())
            self.email = self.email_field.get()
            self.instructor = self.instructor_field.get()
            self.balance = float(self.balance_field.get())
            self.username = self.username_field.get()
            self.password = self.password_field.get()
            
            db_conn = database_handler.DBHandler()
            db_conn.update_student(self.student_list)
            db_conn.close()
            
            self.go_to_view_students()
            
        except ValueError:
            messagebox.showerror('Update Student', "Contact Number and Balance must be a number")
    
    def update_table(self, event = None):
        self.get_student_list()
        self.table.delete(*self.table.get_children())
        
        for student in self.Student_list:
            row = (student.student_name, student.balance)
            self.table.insert('', END, values = row)
            
    def go_to_view_students(self):
        self.parent.change_window("RegistrarViewStudents")
    
    def on_return(self, **kwargs,):
        self.student_id = kwargs['id']
        self.id_label.config(text=self.student_id)
        
        db_conn = database_handler.DBHandler()
        self.student = db_conn.read_one_student(self.student_id)
        db_conn.close()
        
        self.clear_data()
        self.init_data()
        
    def init_data(self):
        self.student_name_field.insert(0, self.student.student_name)
        self.course_field.insert(0, self.student.course)
        self.birthdate_field.insert(0, self.student.birthdate)
        self.gender_field.insert(0, self.student.gender)
        self.contact_number_field.insert(0, int(self.student.contact_number))
        self.email_field.insert(0, self.student.email)
        self.instructor_field.insert(0, self.student.instructor)       
        self.balance_field.insert(0, float(self.student.balance))
        self.username_field.insert(0, self.student.username)
        self.password_field.insert(0, self.student.password)
        
        self.update_table()
        
    def clear_data(self):
        self.student_name_field.delete(0, END)
        self.course_field.delete(0, END)
        self.birthdate_field.delete(0, END)
        self.gender_field.delete(0, END)
        self.contact_number_field.delete(0, END)
        self.email_field.delete(0, END)
        self.instructor_field.delete(0, END)
        self.balance_field.delete(0, END)
        self.username_field.delete(0, END)
        self.password_field.delete(0, END)

问题分析

  1. KeyError根源:前一窗口调用change_window("UpdateStudent")时,未传入包含学生ID的参数,导致on_return方法无法从kwargs中获取id。
  2. 代码冗余问题:类中定义了两个同名的update_table方法,后定义的会覆盖前一个,导致表格渲染逻辑混乱。
  3. 更新逻辑错误:update_student方法传入整个学生列表而非单个学生对象,不符合单条数据更新的业务逻辑。

修复方案

1. 补全跳转时的参数传递

修改前一窗口的go_to_update_form方法,传入选中的学生ID:

def go_to_update_form(self):
    # 获取Treeview中选中的学生ID(根据实际列索引调整)
    selected_item = self.table.selection()[0]
    student_id = self.table.item(selected_item)['values'][0]
    self.parent.change_window("UpdateStudent", id=student_id)

2. 增强on_return的容错性

添加参数缺失判断,避免程序崩溃:

def on_return(self, **kwargs):
    self.student_id = kwargs.get('id')
    if not self.student_id:
        messagebox.showerror("错误", "未选择要更新的学生")
        self.go_to_view_students()
        return
    self.id_label.config(text=self.student_id)
    
    db_conn = database_handler.DBHandler()
    self.student = db_conn.read_one_student(self.student_id)
    db_conn.close()
    
    self.clear_data()
    self.init_data()

3. 合并重复的update_table方法

删除重复方法,保留匹配表格列定义的版本:

def update_table(self, event=None):
    self.get_student_list()
    self.table.delete(*self.table.get_children())
    
    for student in self.Student_list:
        # 匹配columns定义的('id', 'balance')列
        row = (student.id, student.balance)
        self.table.insert('', END, values=row)

4. 修正单条学生数据更新逻辑

修改update_student方法,传入单个学生的更新数据:

def update_student(self):
    if not self.validate_data():
        return
    
    try:
        updated_student = {
            'id': self.student_id,
            'student_name': self.student_name_field.get(),
            'course': self.course_field.get(),
            'birthdate': self.birthdate_field.get(),
            'gender': self.gender_field.get(),
            'contact_number': int(self.contact_number_field.get()),
            'email': self.email_field.get(),
            'instructor': self.instructor_field.get(),
            'balance': float(self.balance_field.get()),
            'username': self.username_field.get(),
            'password': self.password_field.get()
        }
        
        db_conn = database_handler.DBHandler()
        db_conn.update_student(updated_student)
        db_conn.close()
        
        messagebox.showinfo("成功", "学生信息更新完成")
        self.go_to_view_students()
        
    except ValueError:
        messagebox.showerror('更新学生', "联系电话和余额必须为数字")

内容的提问来源于stack exchange,提问作者Charles Mendoza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 15:29:53