json.dump. Не сохраняет данные после закрытия окна
Есть рабочий код библиотеки с графическим интерфейсом. Но код не сохраняет данные которые ты вводишь(условно добавил книгу закрыл окно программы и она отсутствует в списке книг. Аналогично если закрыть PyCharm).Ошибка у меня такая. Ошибка при загрузке данных: module 'json' has no attribute 'load' Ошибка при сохранении данных: module 'json' has no attribute 'dump' Сам код при этом работает но не сохраняет. Вот сам код.
import tkinter as tk
from tkinter import messagebox, ttk
import json
import os
class Book:
def __init__(self, title, author, year, isbn, available=True):
self.title = title
self.author = author
self.year = year
self.isbn = isbn
self.available = available
self.borrower = None
def to_dict(self):
return {
'title': self.title,
'author': self.author,
'year': self.year,
'isbn': self.isbn,
'available': self.available,
'borrower': self.borrower
}
@classmethod
def from_dict(cls, data):
book = cls(data['title'], data['author'], data['year'], data['isbn'], data['available'])
book.borrower = data['borrower']
return book
class User:
def __init__(self, username, password, is_admin=False):
self.username = username
self.password = password
self.is_admin = is_admin
self.borrowed_books = []
def to_dict(self):
return {
'username': self.username,
'password': self.password,
'is_admin': self.is_admin,
'borrowed_books': self.borrowed_books
}
@classmethod
def from_dict(cls, data):
user = cls(data['username'], data['password'], data['is_admin'])
user.borrowed_books = data['borrowed_books']
return user
class Library:
def __init__(self):
self.books = []
self.users = []
self.data_file = "library_data.txt"
# Загружаем данные при инициализации
self.load_data()
# Добавляем администратора по умолчанию, если нет пользователей
if not self.users:
self.users.append(User("admin", "admin", True))
self.save_data()
def save_data(self):
data = {
'books': [book.to_dict() for book in self.books],
'users': [user.to_dict() for user in self.users]
}
try:
with open(self.data_file, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
except Exception as e:
print(f"Ошибка при сохранении данных: {e}")
def load_data(self):
if not os.path.exists(self.data_file):
return
try:
with open(self.data_file, 'r', encoding='utf-8') as f:
data = json.load(f)
self.books = [Book.from_dict(book_data) for book_data in data.get('books', [])]
self.users = [User.from_dict(user_data) for user_data in data.get('users', [])]
except Exception as e:
print(f"Ошибка при загрузке данных: {e}")
def add_book(self, book):
self.books.append(book)
self.save_data()
def find_books(self, search_term):
return [book for book in self.books if search_term.lower() in book.title.lower() or
search_term.lower() in book.author.lower() or
search_term == book.isbn]
def checkout_book(self, isbn, user):
for book in self.books:
if book.isbn == isbn and book.available:
book.available = False
book.borrower = user.username
user.borrowed_books.append(isbn)
self.save_data()
return True
return False
def return_book(self, isbn, user):
for book in self.books:
if book.isbn == isbn and not book.available and book.borrower == user.username:
book.available = True
book.borrower = None
if isbn in user.borrowed_books:
user.borrowed_books.remove(isbn)
self.save_data()
return True
return False
def add_user(self, user):
self.users.append(user)
self.save_data()
def authenticate(self, username, password):
for user in self.users:
if user.username == username and user.password == password:
return user
return None
def get_user_books(self, username):
user_books = []
for book in self.books:
if book.borrower == username:
user_books.append(book)
return user_books
class LibraryApp:
def __init__(self, root):
self.root = root
self.root.title("Система управления библиотекой")
self.root.geometry("800x600")
self.library = Library()
self.current_user = None
self.show_login_frame()
def show_login_frame(self):
self.clear_window()
self.login_frame = tk.Frame(self.root)
self.login_frame.pack(pady=100)
tk.Label(self.login_frame, text="Логин:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5)
self.username_entry = tk.Entry(self.login_frame, font=("Arial", 12))
self.username_entry.grid(row=0, column=1, padx=5, pady=5)
tk.Label(self.login_frame, text="Пароль:", font=("Arial", 12)).grid(row=1, column=0, padx=5, pady=5)
self.password_entry = tk.Entry(self.login_frame, show="*", font=("Arial", 12))
self.password_entry.grid(row=1, column=1, padx=5, pady=5)
login_button = tk.Button(self.login_frame, text="Войти", command=self.login, font=("Arial", 12))
login_button.grid(row=2, column=0, columnspan=2, pady=10)
# Подсказка для тестирования
hint_label = tk.Label(self.root, text="Для теста: admin / admin", fg="gray")
hint_label.pack(side="bottom", pady=10)
def login(self):
username = self.username_entry.get()
password = self.password_entry.get()
self.current_user = self.library.authenticate(username, password)
if self.current_user:
self.show_main_menu()
else:
messagebox.showerror("Ошибка", "Неверный логин или пароль")
def show_main_menu(self):
self.clear_window()
# Заголовок
welcome_label = tk.Label(self.root,
text=f"Добро пожаловать, {self.current_user.username}!",
font=("Arial", 14, "bold"))
welcome_label.pack(pady=20)
# Кнопки меню
buttons_frame = tk.Frame(self.root)
buttons_frame.pack(pady=20)
button_style = {"font": ("Arial", 12), "width": 20, "height": 2}
tk.Button(buttons_frame, text="Просмотреть все книги",
command=self.show_all_books, **button_style).pack(pady=5)
tk.Button(buttons_frame, text="Поиск книги",
command=self.show_search_books, **button_style).pack(pady=5)
tk.Button(buttons_frame, text="Взять книгу",
command=self.show_checkout_book, **button_style).pack(pady=5)
tk.Button(buttons_frame, text="Вернуть книгу",
command=self.show_return_book, **button_style).pack(pady=5)
tk.Button(buttons_frame, text="Мои книги",
command=self.show_user_books, **button_style).pack(pady=5)
if self.current_user.is_admin:
tk.Button(buttons_frame, text="Добавить книгу",
command=self.show_add_book, **button_style).pack(pady=5)
tk.Button(buttons_frame, text="Добавить пользователя",
command=self.show_add_user, **button_style).pack(pady=5)
tk.Button(buttons_frame, text="Выйти",
command=self.logout, **button_style).pack(pady=20)
def show_user_books(self):
self.clear_window()
back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
back_button.pack(anchor="nw", padx=10, pady=10)
title_label = tk.Label(self.root, text="Мои книги", font=("Arial", 14, "bold"))
title_label.pack(pady=10)
user_books = self.library.get_user_books(self.current_user.username)
if not user_books:
no_books_label = tk.Label(self.root, text="У вас нет взятых книг.", font=("Arial", 12))
no_books_label.pack(pady=20)
return
# Создаем Treeview для отображения книг в виде таблицы
tree_frame = tk.Frame(self.root)
tree_frame.pack(fill="both", expand=True, padx=10, pady=10)
tree = ttk.Treeview(tree_frame, columns=("Title", "Author", "Year", "ISBN"), show="headings")
# Настройка колонок
tree.heading("Title", text="Название")
tree.heading("Author", text="Автор")
tree.heading("Year", text="Год")
tree.heading("ISBN", text="ISBN")
tree.column("Title", width=200)
tree.column("Author", width=150)
tree.column("Year", width=50)
tree.column("ISBN", width=100)
# Добавление книг в таблицу
for book in user_books:
tree.insert("", "end", values=(book.title, book.author, book.year, book.isbn))
# Добавляем скроллбар
scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
tree.pack(fill="both", expand=True)
def show_all_books(self):
self.clear_window()
back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
back_button.pack(anchor="nw", padx=10, pady=10)
title_label = tk.Label(self.root, text="Все книги в библиотеке", font=("Arial", 14, "bold"))
title_label.pack(pady=10)
if not self.library.books:
no_books_label = tk.Label(self.root, text="В библиотеке нет книг.", font=("Arial", 12))
no_books_label.pack(pady=20)
return
# Создаем Treeview для отображения книг в виде таблицы
tree_frame = tk.Frame(self.root)
tree_frame.pack(fill="both", expand=True, padx=10, pady=10)
tree = ttk.Treeview(tree_frame, columns=("Title", "Author", "Year", "ISBN", "Status", "Borrower"),
show="headings")
# Настройка колонок
tree.heading("Title", text="Название")
tree.heading("Author", text="Автор")
tree.heading("Year", text="Год")
tree.heading("ISBN", text="ISBN")
tree.heading("Status", text="Статус")
tree.heading("Borrower", text="Взята пользователем")
tree.column("Title", width=200)
tree.column("Author", width=150)
tree.column("Year", width=50)
tree.column("ISBN", width=100)
tree.column("Status", width=100)
tree.column("Borrower", width=150)
# Добавление книг в таблицу
for book in self.library.books:
status = "Доступна" if book.available else "Выдана"
borrower = book.borrower if book.borrower else "-"
tree.insert("", "end", values=(book.title, book.author, book.year, book.isbn, status, borrower))
# Добавляем скроллбар
scrollbar = ttk.Scrollbar(tree_frame, orient="vertical", command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
tree.pack(fill="both", expand=True)
def show_search_books(self):
self.clear_window()
back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
back_button.pack(anchor="nw", padx=10, pady=10)
title_label = tk.Label(self.root, text="Поиск книги", font=("Arial", 14, "bold"))
title_label.pack(pady=10)
search_frame = tk.Frame(self.root)
search_frame.pack(pady=10)
tk.Label(search_frame, text="Поиск (название, автор или ISBN):", font=("Arial", 12)).pack(side="left")
self.search_entry = tk.Entry(search_frame, font=("Arial", 12), width=30)
self.search_entry.pack(side="left", padx=5)
search_button = tk.Button(search_frame, text="Найти", command=self.search_books, font=("Arial", 12))
search_button.pack(side="left")
# Место для результатов поиска
self.results_frame = tk.Frame(self.root)
self.results_frame.pack(fill="both", expand=True, padx=10, pady=10)
def search_books(self):
# Очищаем предыдущие результаты
for widget in self.results_frame.winfo_children():
widget.destroy()
search_term = self.search_entry.get()
found_books = self.library.find_books(search_term)
if not found_books:
no_results_label = tk.Label(self.results_frame, text="Книги не найдены.", font=("Arial", 12))
no_results_label.pack(pady=20)
return
# Создаем Treeview для отображения результатов
tree = ttk.Treeview(self.results_frame, columns=("Title", "Author", "Year", "ISBN", "Status"), show="headings")
# Настройка колонок
tree.heading("Title", text="Название")
tree.heading("Author", text="Автор")
tree.heading("Year", text="Год")
tree.heading("ISBN", text="ISBN")
tree.heading("Status", text="Статус")
tree.column("Title", width=200)
tree.column("Author", width=150)
tree.column("Year", width=50)
tree.column("ISBN", width=100)
tree.column("Status", width=100)
# Добавление книг в таблицу
for book in found_books:
status = "Доступна" if book.available else "Выдана"
tree.insert("", "end", values=(book.title, book.author, book.year, book.isbn, status))
# Добавляем скроллбар
scrollbar = ttk.Scrollbar(self.results_frame, orient="vertical", command=tree.yview)
tree.configure(yscrollcommand=scrollbar.set)
scrollbar.pack(side="right", fill="y")
tree.pack(fill="both", expand=True)
def show_checkout_book(self):
self.clear_window()
back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
back_button.pack(anchor="nw", padx=10, pady=10)
title_label = tk.Label(self.root, text="Взять книгу", font=("Arial", 14, "bold"))
title_label.pack(pady=10)
checkout_frame = tk.Frame(self.root)
checkout_frame.pack(pady=20)
tk.Label(checkout_frame, text="ISBN книги:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5)
self.isbn_entry = tk.Entry(checkout_frame, font=("Arial", 12))
self.isbn_entry.grid(row=0, column=1, padx=5, pady=5)
checkout_button = tk.Button(checkout_frame, text="Взять", command=self.checkout_book, font=("Arial", 12))
checkout_button.grid(row=1, column=0, columnspan=2, pady=10)
def checkout_book(self):
isbn = self.isbn_entry.get()
if self.library.checkout_book(isbn, self.current_user):
messagebox.showinfo("Успех", "Книга успешно выдана")
else:
messagebox.showerror("Ошибка", "Не удалось выдать книгу. Возможно, она уже выдана или не существует.")
def show_return_book(self):
self.clear_window()
back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
back_button.pack(anchor="nw", padx=10, pady=10)
title_label = tk.Label(self.root, text="Вернуть книгу", font=("Arial", 14, "bold"))
title_label.pack(pady=10)
return_frame = tk.Frame(self.root)
return_frame.pack(pady=20)
tk.Label(return_frame, text="ISBN книги:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5)
self.return_isbn_entry = tk.Entry(return_frame, font=("Arial", 12))
self.return_isbn_entry.grid(row=0, column=1, padx=5, pady=5)
return_button = tk.Button(return_frame, text="Вернуть", command=self.return_book, font=("Arial", 12))
return_button.grid(row=1, column=0, columnspan=2, pady=10)
def return_book(self):
isbn = self.return_isbn_entry.get()
if self.library.return_book(isbn, self.current_user):
messagebox.showinfo("Успех", "Книга успешно возвращена")
else:
messagebox.showerror("Ошибка", "Не удалось вернуть книгу. Возможно, она не была выдана или не существует.")
def show_add_book(self):
self.clear_window()
back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
back_button.pack(anchor="nw", padx=10, pady=10)
title_label = tk.Label(self.root, text="Добавить новую книгу", font=("Arial", 14, "bold"))
title_label.pack(pady=10)
add_frame = tk.Frame(self.root)
add_frame.pack(pady=20)
tk.Label(add_frame, text="Название:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5, sticky="e")
self.title_entry = tk.Entry(add_frame, font=("Arial", 12))
self.title_entry.grid(row=0, column=1, padx=5, pady=5)
tk.Label(add_frame, text="Автор:", font=("Arial", 12)).grid(row=1, column=0, padx=5, pady=5, sticky="e")
self.author_entry = tk.Entry(add_frame, font=("Arial", 12))
self.author_entry.grid(row=1, column=1, padx=5, pady=5)
tk.Label(add_frame, text="Год издания:", font=("Arial", 12)).grid(row=2, column=0, padx=5, pady=5, sticky="e")
self.year_entry = tk.Entry(add_frame, font=("Arial", 12))
self.year_entry.grid(row=2, column=1, padx=5, pady=5)
tk.Label(add_frame, text="ISBN:", font=("Arial", 12)).grid(row=3, column=0, padx=5, pady=5, sticky="e")
self.isbn_add_entry = tk.Entry(add_frame, font=("Arial", 12))
self.isbn_add_entry.grid(row=3, column=1, padx=5, pady=5)
add_button = tk.Button(add_frame, text="Добавить", command=self.add_book, font=("Arial", 12))
add_button.grid(row=4, column=0, columnspan=2, pady=10)
def add_book(self):
title = self.title_entry.get()
author = self.author_entry.get()
year = self.year_entry.get()
isbn = self.isbn_add_entry.get()
if not all([title, author, year, isbn]):
messagebox.showerror("Ошибка", "Все поля должны быть заполнены")
return
self.library.add_book(Book(title, author, year, isbn))
messagebox.showinfo("Успех", "Книга успешно добавлена")
self.show_main_menu()
def show_add_user(self):
self.clear_window()
back_button = tk.Button(self.root, text="Назад", command=self.show_main_menu)
back_button.pack(anchor="nw", padx=10, pady=10)
title_label = tk.Label(self.root, text="Добавить нового пользователя", font=("Arial", 14, "bold"))
title_label.pack(pady=10)
add_user_frame = tk.Frame(self.root)
add_user_frame.pack(pady=20)
tk.Label(add_user_frame, text="Логин:", font=("Arial", 12)).grid(row=0, column=0, padx=5, pady=5, sticky="e")
self.new_username_entry = tk.Entry(add_user_frame, font=("Arial", 12))
self.new_username_entry.grid(row=0, column=1, padx=5, pady=5)
tk.Label(add_user_frame, text="Пароль:", font=("Arial", 12)).grid(row=1, column=0, padx=5, pady=5, sticky="e")
self.new_password_entry = tk.Entry(add_user_frame, show="*", font=("Arial", 12))
self.new_password_entry.grid(row=1, column=1, padx=5, pady=5)
self.is_admin_var = tk.BooleanVar()
tk.Checkbutton(add_user_frame, text="Администратор", variable=self.is_admin_var,
font=("Arial", 12)).grid(row=2, column=0, columnspan=2, pady=5)
add_user_button = tk.Button(add_user_frame, text="Добавить", command=self.add_user, font=("Arial", 12))
add_user_button.grid(row=3, column=0, columnspan=2, pady=10)
def add_user(self):
username = self.new_username_entry.get()
password = self.new_password_entry.get()
is_admin = self.is_admin_var.get()
if not username or not password:
messagebox.showerror("Ошибка", "Логин и пароль должны быть заполнены")
return
# Проверка, существует ли уже пользователь с таким логином
for user in self.library.users:
if user.username == username:
messagebox.showerror("Ошибка", "Пользователь с таким логином уже существует")
return
self.library.add_user(User(username, password, is_admin))
messagebox.showinfo("Успех", "Пользователь успешно добавлен")
self.show_main_menu()
def logout(self):
self.current_user = None
self.show_login_frame()
def clear_window(self):
for widget in self.root.winfo_children():
widget.destroy()
if __name__ == "__main__":
root = tk.Tk()
app = LibraryApp(root)
root.mainloop()
Код сделан с помощью нейросети сам только учусь.