Below there is a full code for my app Staff Manager. The app does allow basic staff management, like adding, removing or changing details of employees. As it is one of my first GUI apps and I am self-taught (I have been learning for about 6 months now, a couple of hours every day after work) I would like to see what you guys think about my code. Would like to see the opinion of other people. Any advice on improvements (to my work and code) is welcome. Won't get upset if I will get criticized. Here to learn and improve.
from json.decoder import JSONDecodeError
import tkinter as tk
from tkinter import StringVar, Toplevel, ttk
import os, json
import copy
class Staff_Manager(tk.Tk):
def __init__(self) -> None:
super().__init__()
self.check_save_file()
self.geometry("1520x600")
self.title("Staff Manager")
self.iconbitmap("icon.ico")
self.buttons()
self.data_view()
self.update
self.delete
self.is_retired
# check if data save file exists and if not create one.
def check_save_file(self):
current_path = os.path.dirname(__file__)
json_file = f'{current_path}\\emp_data.json'
if os.path.isfile(json_file) == True and os.stat(json_file).st_size != 0:
pass
else:
with open(json_file, 'w+') as f:
data = {"people": []}
json.dump(data, f)
def buttons(self):
# managing buttons, main window
add = ttk.Button(self, text= 'Add', command= Add_New_Emp)
add.place(x= 10, y= 10, width= 75)
amend = ttk.Button(self, text= 'Amend', command= self.amend)
amend.place(x= 10, y= 45, width= 75)
refresh = ttk.Button(self, text= 'Refresh', command= self.update)
refresh.place(x= 10, y= 80, width= 75)
retire = ttk.Button(self, text= 'Retire', command= self.is_retired)
retire.place(x= 10, y= 135, width= 75, height= 40)
remove = ttk.Button(self, text= 'Remove', command= self.delete)
remove.place(x= 10, y= 230, width= 75, height= 40)
exit_button = ttk.Button(self, text= 'EXIT', command= self.destroy)
exit_button.place(x= 10, y= 538, width= 75, height= 40)
def data_view(self):
#create columns for tree view
columns = ('#1', '#2', '#3', '#4', '#5', '#6', '#7')
self.view_panel = ttk.Treeview(self, columns= columns, show= 'headings', height= 27)
self.view_panel.place(x= 90, y= 10)
# headings
self.view_panel.heading('#1', text= 'Name')
self.view_panel.heading('#2', text= 'Surname')
self.view_panel.heading('#3', text= 'Position')
self.view_panel.heading('#4', text= 'DoB')
self.view_panel.heading('#5', text= 'Start Date')
self.view_panel.heading('#6', text= 'End Date')
self.view_panel.heading('#7', text= 'Retired?')
# set up the scrollbar
scrollbar = ttk.Scrollbar(self, orient= tk.VERTICAL, command= self.view_panel.yview)
self.view_panel.configure(yscrollcommand= scrollbar.set)
scrollbar.place(x= 1495, y= 10, height= 575)
# insert data
with open('emp_data.json', 'r') as f:
empty_file = False
try:
data = json.load(f)
except JSONDecodeError:
empty_file = True
pass
employees = []
if empty_file == False:
for item in data["people"]:
name = item["name"]
surname = item["surname"]
position = item["position"]
dob = item["dob"]
start = item["start"]
end = item["end"]
retired = item["retired"]
employees.append((name, surname, position, dob, start, end, retired))
# insert all the data to the view panel
for emp in employees:
self.view_panel.insert('', tk.END, values= emp)
# update information on the view panel
def update(self):
self.data_view()
# amend emp data
def amend(self):
amend_win = tk.Tk()
amend_win.geometry('350x250')
amend_win.title('Amend Employee Details')
amend_win.iconbitmap('icon.ico')
# cancel button
def is_cancel():
amend_win.destroy()
# change button
def is_amended(to_change, new_personal_data):
current_item = self.view_panel.focus()
info = self.view_panel.item(current_item)
details = info["values"]
to_remove = {
"name": str(details[0]),
"surname": str(details[1]),
"position": str(details[2]),
"dob": str(details[3]),
"start": str(details[4]),
"end": str(details[5]),
"retired": str(details[6])
}
to_remove = copy.deepcopy(to_remove)
details_dict = {
"name": str(details[0]),
"surname": str(details[1]),
"position": str(details[2]),
"dob": str(details[3]),
"start": str(details[4]),
"end": str(details[5]),
"retired": str(details[6])
}
for key, value in details_dict.items():
if key == to_change:
details_dict[f"{to_change}"] = new_personal_data
with open('emp_data.json', 'r') as f:
data = json.load(f)
new_data = {
"people": []
}
for emp_dict in data["people"]:
if to_remove != emp_dict:
new_data["people"].append(emp_dict)
new_data["people"].append(details_dict)
with open('emp_data.json', 'w') as f:
json.dump(new_data, f, indent= 4)
amend_win.destroy()
# check if data is not empty, if is: n/a
def is_empty(data):
if len(data) == 0:
return 'n/a'
else:
return data
main_choice_lbl = ttk.Label(amend_win, text= 'What would you like to change?', font= ('Arial', 12))
main_choice_lbl.place(x= 10, y= 10)
self.data_options = ('name', 'surname', 'position', 'dob', 'start', 'end')
self.choice = StringVar()
options = ttk.OptionMenu(amend_win,
self.choice,
self.data_options[0],
*self.data_options)
options.place(x= 10, y= 47)
options.config(width= 15)
new_emp_data = ttk.Label(amend_win, text= 'New data:', font= ('Arial', 12))
new_emp_data.place(x= 10, y= 90)
main_entry = ttk.Entry(amend_win, justify= 'right')
main_entry.place(x= 10, y= 130)
ok_button = ttk.Button(amend_win, text= 'CHANGE', command= lambda: is_amended(self.choice.get(), is_empty(main_entry.get())))
ok_button.place(x= 60, y= 200)
cancel_button = ttk.Button(amend_win, text= 'CANCEL', command= is_cancel)
cancel_button.place(x= 150, y= 200)
def delete(self):
# get the "clicked" emp
current_item = self.view_panel.focus()
# get the info of "clicked" emp : dict
info = self.view_panel.item(current_item)
# get details of "clicked" emp, "values" are stored emp data : list
details = info["values"]
# set the data to json format (need to convert some int to str as program is creating all data as strings)
details_dict = {
"name": str(details[0]),
"surname": str(details[1]),
"position": str(details[2]),
"dob": str(details[3]),
"start": str(details[4]),
"end": str(details[5]),
"retired": str(details[6])
}
with open('emp_data.json', 'r') as f:
data = json.load(f)
new_data = {
"people": []
}
for emp_dict in data["people"]:
if details_dict != emp_dict:
new_data['people'].append(emp_dict)
with open('emp_data.json', 'w') as f:
json.dump(new_data, f, indent= 4)
def is_retired(self):
retired_win = tk.Tk()
retired_win.geometry('280x130')
# cancel button
def is_cancel():
retired_win.destroy()
def is_ok():
current_item = self.view_panel.focus()
info = self.view_panel.item(current_item)
details = info["values"]
to_remove = {
"name": str(details[0]),
"surname": str(details[1]),
"position": str(details[2]),
"dob": str(details[3]),
"start": str(details[4]),
"end": str(details[5]),
"retired": str(details[6])
}
to_remove = copy.deepcopy(to_remove)
details_dict = {
"name": str(details[0]),
"surname": str(details[1]),
"position": str(details[2]),
"dob": str(details[3]),
"start": str(details[4]),
"end": str(details[5]),
"retired": str(details[6])
}
# for key, value in details_dict.items():
details_dict["retired"] = "Yes"
with open('emp_data.json', 'r') as f:
data = json.load(f)
new_data = {
"people": []
}
for emp_dict in data["people"]:
if to_remove != emp_dict:
new_data["people"].append(emp_dict)
new_data["people"].append(details_dict)
with open('emp_data.json', 'w') as f:
json.dump(new_data, f, indent= 4)
retired_win.destroy()
ret_lbl = ttk.Label(retired_win, text= "Are you sure you want to RETIRE your employee?")
ret_lbl.place(x= 10, y= 20)
ok_button = ttk.Button(retired_win, text= 'RETIRE', command= is_ok)
ok_button.place(x= 40, y= 60)
cancel_button = ttk.Button(retired_win, text= 'CANCEL', command= is_cancel)
cancel_button.place(x= 150, y= 60)
class Add_New_Emp(Toplevel):
def __init__(self) -> None:
super().__init__()
self.geometry('380x400')
self.title('Employee Data')
self.iconbitmap('icon.ico')
self.labels()
self.data_entry()
# set labels
def labels(self):
name_lbl = ttk.Label(self, text= 'Name:', font= ('Arial', 12))
name_lbl.place(x= 10, y= 10)
surname_lbl = ttk.Label(self, text= 'Surname:', font= ('Arial', 12))
surname_lbl.place(x= 10, y= 50)
position_lbl = ttk.Label(self, text= 'Position:', font= ('Arial', 12))
position_lbl.place(x= 10, y= 90)
dob_lbl = ttk.Label(self, text= 'Date of Birth:', font= ('Arial', 12))
dob_lbl.place(x= 10, y= 130)
start_lbl = ttk.Label(self, text= 'Start Date:', font= ('Arial', 12))
start_lbl.place(x= 10, y= 170)
end_lbl = ttk.Label(self, text= 'End Date:', font= ('Arial', 12))
end_lbl.place(x= 10, y= 210)
retired_lbl = ttk.Label(self, text= 'Retired?', font= ('Arial', 12))
retired_lbl.place(x= 10, y= 250)
# set data entry points
def data_entry(self):
def is_empty(data):
if len(data) == 0:
return 'n/a'
else:
return data
# accepting details, pressing ok button
def is_ok():
# get all the data
name = is_empty(name_ent.get())
surname = is_empty(surname_ent.get())
position = is_empty(position_ent.get())
dob = is_empty(dob_ent.get())
start = is_empty(start_ent.get())
end = is_empty(end_ent.get())
retired = retired_var.get()
# append row to the employee data file
with open('emp_data.json', 'r+') as f:
data = json.load(f)
new_emp = {
"name": name,
"surname": surname,
"position": position,
"dob": dob,
"start": start,
"end": end,
"retired": retired
}
data["people"].append(new_emp)
with open('emp_data.json', 'w') as f:
json.dump(data, f, indent= 4)
self.destroy()
# cancelation of adding new emp
def is_cancel():
self.destroy()
name_ent = ttk.Entry(self, justify= 'right')
name_ent.place(x= 215, y= 10)
surname_ent = ttk.Entry(self, justify= 'right')
surname_ent.place(x= 215, y= 50)
position_ent = ttk.Entry(self, justify= 'right')
position_ent.place(x= 215, y= 90)
dob_ent = ttk.Entry(self, justify= 'right')
dob_ent.place(x= 215, y= 130)
start_ent = ttk.Entry(self, justify= 'right')
start_ent.place(x= 215, y= 170)
end_ent = ttk.Entry(self, justify= 'right')
end_ent.place(x= 215, y= 210)
retired_var = StringVar(value= 'No')
retired_chk = ttk.Checkbutton(
self,
text= 'Yes',
onvalue= 'Yes',
offvalue= 'No',
variable= retired_var)
retired_chk.place(x= 215, y= 250)
ok_button = ttk.Button(self, text= 'ADD', command= is_ok)
ok_button.place(x= 100, y= 350)
cancel_button = ttk.Button(self, text= 'CANCEL', command= is_cancel)
cancel_button.place(x= 200, y= 350)
if __name__ == "__main__":
Staff_Manager().mainloop()
2 Answers 2
PEP 8
You deviate from the Style Guide for Python Code in a couple of areas:
- Keyword arguments should not have spaces around the equals. For example
should beadd = ttk.Button(self, text= 'Add', command= Add_New_Emp)
add = ttk.Button(self, text='Add', command=Add_New_Emp)
- Class names should be
CapitalizedWords
, notCapitalized_Words_With_Underscores
. SoStaff_Manager
andAdd_New_Emp
should beStaffManager
andAddNewEmp
.
Type Hints
The only place I see type hints used is def __init__(self) -> None:
. Clearly you've just started using them, but you need to use them more, and run your could through a checker (mypy
, pylint
, ...)
Dead code
self.buttons()
self.data_view()
self.update
self.delete
self.is_retired
The last three "statements" do nothing, and should be deleted.
Poor naming
Functions named is_xxx()
look like functions which do not modify any state and return a True
or False
result. Your functions change the state of the program, and return nothing. Find better names, like do_cancel()
and perform_amend
.
Reuse Components
Each time .data_view()
is called, a new ttk.Treeview
is created, and placed on top of where the previous one was.
Create the ttk.Treeview
once, and refresh its contents when information changes.
PathLib
os.path.isfile(file)
and os.stat(file)
are old-school functions. You should start using the newer pathlib
. Eg)
from pathlib import Path
...
json_file = Path(__file__).parent / 'emp_data.json'
if json_file.is_file() and json_file.stat().st_size != 0:
...
Consistent Filename
Sometimes you use f'{current_path}\\emp_data.json'
to specify the database file, other times you use with open('emp_data.json', 'w') as f:
which might be writing to a completely different location!
Data Access Object
I'm seeing a lot of duplicate code for reading and writing to the emp_data.json
database. You should create and use a Data Access Object to manage the your database.
For example:
class EmployeeDB:
def __init__(self, json_file: Path) -> None:
self._file = json_file
# Create an empty database, if file doesn't exist or is empty
if not json_file.is_file() or json_file.stat().st_size == 0:
self.save([])
def load(self) -> list:
employees = []
with open(self._file, 'r') as f:
data = json.load(f)
for item in data['people']:
...
return employees
def save(self, employees: list) -> None:
with open(self._file, 'w') as f:
data = {"people": employees}
json.dump(data, f, indent=4)
class StaffManager(tk.Tk):
def __init__(self, database: EmployeeDB) -> None:
self._db = database
...
...
...
if __name__ == '__main__':
db = EmployeeDB(Path('emp_data.json'))
StaffManager(db).mainloop()
Dataclass
Each employee is a dictionary.
You should create an actual Employee
dataclass to hold the information. From that, you can add additional methods, like .age()
which could return a calculated value based on .dob
from dataclasses import dataclass
@dataclass
class Employee:
name: str
surname: str
position: str
dob: str
start: str
end: str
retired: str
The EmployeeDB
could now use list[Employee]
as type-hints, instead of a bare list
.
There are many more changes I'd make, but this is a good start. I look forward to reviewing the next revision.
-
\$\begingroup\$ Thank you very much for your extensive answer. A lot to learn from it for me. This is what I wanted so I can improve. Thank You very much. Dead code and Class Names are already corrected. \$\endgroup\$Jakub– Jakub2021年09月29日 19:49:24 +00:00Commented Sep 29, 2021 at 19:49
Not sure if I should create a new post or answer in this one. Here is a revised version of my Staff Manager APP.
Improved:
- Class Names
- Function Names
- Type Hints (yes previously I thought I only have to do only int, str etc.)
- PeP 8 (still learning and improving this one all the time)
- Dead Code removed
- Created Data Access Object (Thank you, that was a brilliant idea)
- Filename (specified in one place, will always have to be the same)
- Tried to reuse components more (view panel is being closed and created now if there are any changes to display)
Not happened yet:
- Pathlib, yes still used os as I never used Pathlib in the past, currently learning that module as well.
- Dataclass, haven't done it in this version. Actually planning now to create a "proper" app with more functionality where I will use dataclass as it is a brilliant idea, although this app is meant to be very simple.
Any advice, comments will be appreciated. A few small changes happened and Thanks to AJNeufeld also 290 lines of code went down to 225 lines while the program does exactly the same thing and everything is working as it is supposed. The data file is still in human-readable form (although it would be easier to store data as lists and just correctly display them in the app).
import json
from os import path
import tkinter as tk
from tkinter import StringVar, ttk
import os
from tkinter.constants import CENTER, NO
from ttkbootstrap import Style
class Window(tk.Tk):
def __init__(self, database: object) -> None:
super().__init__()
self._db = database
self.geometry('1000x500')
self.title('Staff Manager')
self.iconbitmap('icon.ico')
self.buttons()
self.data_view()
# set theme for the app (from ttkbootstrap)
style = Style(theme='darkly')
self = style.master
def buttons(self) -> None:
# managing buttons, main window
add = ttk.Button(self, text='Add', command=self.add_new_emp)
add.place(x=10, y=10, width=75, height=40)
amend = ttk.Button(self, text='Amend', command=self.amend_emp)
amend.place(x=10, y=55, width=75, height=40)
retire = ttk.Button(self, text='Retire', command=self.retire_emp)
retire.place(x=10, y=100, width=75, height=40)
remove = ttk.Button(self, text='Remove', command=self.delete_emp)
remove.place(x=10, y=180, width=75, height=40)
exit_button = ttk.Button(self, text= 'EXIT', command=self.destroy)
exit_button.place(x=10, y=450, width=75, height=40)
def data_view(self) -> None:
# create columns
columns = ('#1', '#2', '#3', '#4', '#5', '#6', '#7')
self.view_panel = ttk.Treeview(self, columns=columns, show='headings', height=27, selectmode='browse')
self.view_panel.place(x=90, y=10, width=890, height=480)
# headings
self.view_panel.heading('#1', text='Name')
self.view_panel.heading('#2', text='Surname')
self.view_panel.heading('#3', text='Position')
self.view_panel.heading('#4', text='DoB')
self.view_panel.heading('#5', text='Start Date')
self.view_panel.heading('#6', text='End Date')
self.view_panel.heading('#7', text='Retired?')
# set colums properties
self.view_panel.column('#1', anchor=CENTER, stretch=NO, width=135)
self.view_panel.column('#2', anchor=CENTER, stretch=NO, width=135)
self.view_panel.column('#3', anchor=CENTER, stretch=NO, width=135)
self.view_panel.column('#4', anchor=CENTER, stretch=NO, width=135)
self.view_panel.column('#5', anchor=CENTER, stretch=NO, width=135)
self.view_panel.column('#6', anchor=CENTER, stretch=NO, width=135)
self.view_panel.column('#7', anchor=CENTER, stretch=NO, width=80)
# set scrollbal for view panel
scrollbar = ttk.Scrollbar(self, orient= tk.VERTICAL, command= self.view_panel.yview)
self.view_panel.configure(yscrollcommand=scrollbar.set)
scrollbar.place(x=980, y=10, width=20, height=480)
for emp in EmployeeDatabase.load(self._db):
self.view_panel.insert('', tk.END, values=emp)
def refresh_view_panel(self) -> None:
self.view_panel.destroy()
self.data_view()
def add_new_emp(self) -> None:
new_emp_win = tk.Toplevel(self)
new_emp_win.geometry('380x400')
new_emp_win.title('Add New Employee')
new_emp_win.iconbitmap('icon.ico')
def check_empty_entry(data: str) -> str:
if len(data) == 0:
return 'n/a'
else:
return data
def accept_new_emp() -> None:
# get all the data
name = check_empty_entry(name_ent.get())
surname = check_empty_entry(surname_ent.get())
position = check_empty_entry(position_ent.get())
dob = check_empty_entry(dob_ent.get())
start = check_empty_entry(start_ent.get())
end = check_empty_entry(end_ent.get())
retired = retired_var.get()
new_emp = [name, surname, position, dob, start, end, retired]
EmployeeDatabase.save(self._db, employees=new_emp)
new_emp_win.destroy()
self.refresh_view_panel()
# set labels for Add New Emp window
name_lbl = ttk.Label(new_emp_win, text='Name:', font=('Arial', 12))
name_lbl.place(x=10, y=10)
surname_lbl = ttk.Label(new_emp_win, text='Surname:', font=('Arial', 12))
surname_lbl.place(x=10, y=50)
position_lbl = ttk.Label(new_emp_win, text='Position:', font=('Arial', 12))
position_lbl.place(x=10, y=90)
dob_lbl = ttk.Label(new_emp_win, text='Date of Birth:', font=('Arial', 12))
dob_lbl.place(x=10, y=130)
start_lbl = ttk.Label(new_emp_win, text='Start Date:', font=('Arial', 12))
start_lbl.place(x=10, y=170)
end_lbl = ttk.Label(new_emp_win, text='End Date:', font=('Arial', 12))
end_lbl.place(x=10, y=210)
retired_lbl = ttk.Label(new_emp_win, text='Retired?', font=('Arial', 12))
retired_lbl.place(x=10, y=250)
# set entry points for data
name_ent = ttk.Entry(new_emp_win, justify='right')
name_ent.place(x=215, y=10)
surname_ent = ttk.Entry(new_emp_win, justify='right')
surname_ent.place(x=215, y=50)
position_ent = ttk.Entry(new_emp_win, justify='right')
position_ent.place(x=215, y=90)
dob_ent = ttk.Entry(new_emp_win, justify='right')
dob_ent.place(x=215, y=130)
start_ent = ttk.Entry(new_emp_win, justify='right')
start_ent.place(x=215, y=170)
end_ent = ttk.Entry(new_emp_win, justify='right')
end_ent.place(x=215, y=210)
retired_var = StringVar(value='No')
retired_chk = ttk.Checkbutton(
new_emp_win,
text='Yes',
onvalue='Yes',
offvalue='No',
variable=retired_var)
retired_chk.place(x=215, y=250)
ok_button = ttk.Button(new_emp_win, text='ADD', command=accept_new_emp)
ok_button.place(x=100, y=350)
cancel_button = ttk.Button(new_emp_win, text='CANCEL', command=new_emp_win.destroy)
cancel_button.place(x=200, y=350)
def delete_emp(self) -> None:
# get "clicked" emp
current_emp = self.view_panel.focus()
emp_info = self.view_panel.item(current_emp)
emp_details = emp_info["values"]
# need it as tuple for 'for loop' comparison
emp_details = tuple(emp_details)
# delete emp
new_data = []
for employee in EmployeeDatabase.load(self._db):
if employee != emp_details:
new_data.append(employee)
EmployeeDatabase.create_new(self._db, [])
for emp in new_data:
EmployeeDatabase.save(self._db, emp)
# update view panel
self.refresh_view_panel()
def change_details(self, change_detail_index: int, new_detail: str) -> None:
# get 'clicked' emp
current_emp = self.view_panel.focus()
emp_info = self.view_panel.item(current_emp)
details = emp_info["values"]
# need it as tuple for 'for loop' comparison
details_tup = tuple(details)
emp_to_change = details
# copy rest of emps
new_data = []
for employee in EmployeeDatabase.load(self._db):
if employee != details_tup:
new_data.append(employee)
# append emp with changed detail
details[change_detail_index] = new_detail
new_data.append(details)
EmployeeDatabase.create_new(self._db, [])
# write to database
for emp in new_data:
EmployeeDatabase.save(self._db, emp)
self.refresh_view_panel()
def amend_emp(self) -> None:
amend_win = tk.Toplevel()
amend_win.geometry('250x250')
amend_win.title('Amend Employee Details')
amend_win.iconbitmap('icon.ico')
# check if data is not empty, if is: n/a
def is_empty(data: str) -> str:
if len(data) == 0:
return 'n/a'
else:
return data
main_choice_lbl = ttk.Label(amend_win, text='What would you like to change?', font=('Arial', 12))
main_choice_lbl.place(x=10, y=10)
self.data_options = ('Name', 'Surname', 'Position', 'DoB', 'Start', 'End')
self.choice = StringVar()
options = ttk.OptionMenu(amend_win,
self.choice,
self.data_options[0],
*self.data_options)
options.place(x=10, y=47)
options.config(width=15)
new_emp_data = ttk.Label(amend_win, text='New data:', font=('Arial', 12))
new_emp_data.place(x=10, y=90)
main_entry = ttk.Entry(amend_win, justify='right')
main_entry.place(x=10, y=130)
ok_button = ttk.Button(amend_win, text='CHANGE', command=lambda: [self.change_details(self.data_options.index(self.choice.get()), is_empty(main_entry.get())), amend_win.destroy()])
ok_button.place(x=60, y=200)
cancel_button = ttk.Button(amend_win, text='CANCEL', command=amend_win.destroy)
cancel_button.place(x=150, y=200)
def retire_emp(self) -> None:
retired_win = tk.Toplevel()
retired_win.geometry('280x130')
ret_lbl = ttk.Label(retired_win, text="Are you sure you want to RETIRE your employee?")
ret_lbl.place(x=10, y=20)
ok_button = ttk.Button(retired_win, text='RETIRE', command=lambda: [self.change_details(6, "Yes"), retired_win.destroy()])
ok_button.place(x=40, y=60)
cancel_button = ttk.Button(retired_win, text='CANCEL', command=retired_win.destroy)
cancel_button.place(x=150, y=60)
class EmployeeDatabase:
def __init__(self, json_file: str) -> None:
self._file = json_file
if os.path.isfile(json_file) == True and os.stat(json_file).st_size != 0:
pass
else:
self.create_new([])
def load(self) -> list[str]:
employees: list[str] = []
with open(self._file, 'r') as f:
data = json.load(f)
for item in data["people"]:
name: str = item["name"]
surname: str = item["surname"]
position: str = item["position"]
dob: str = item["dob"]
start: str = item["start"]
end: str = item["end"]
retired: str = item["retired"]
employees.append((name, surname, position, dob, start, end, retired))
return employees
def create_new(self, employees: list) -> None:
with open(self._file, 'w') as f:
data = {"people": employees}
json.dump(data, f, indent=4)
def save(self, employees: list[str]) -> None:
new_emp = {
"name": employees[0],
"surname": employees[1],
"position": employees[2],
"dob": employees[3],
"start": employees[4],
"end": employees[5],
"retired": employees[6]
}
with open(self._file, 'r') as f:
data = json.load(f)
data["people"].append(new_emp)
with open(self._file, 'w') as f:
json.dump(data, f, indent=4)
if __name__ == '__main__':
path = f'{os.path.dirname(__file__)}\\emp_db.json'
db = EmployeeDatabase(path)
Window(database= db).mainloop()
-
1\$\begingroup\$ In general, do not bother posting quick updates like this. Instead, wait a day or two (or seven) to get all the responses, then if you want more feedback post a new question with your updated code. (And if you want "help" feel free to post a link to an online repository for the code.) \$\endgroup\$aghast– aghast2021年10月04日 21:09:03 +00:00Commented Oct 4, 2021 at 21:09
-
\$\begingroup\$ Thank you. Will remember for the next time. \$\endgroup\$Jakub– Jakub2021年10月04日 21:13:44 +00:00Commented Oct 4, 2021 at 21:13