Загрузка данных
# === Окно для работы с базами данных ===
class DatabaseWindow(tk.Toplevel):
def __init__(self, parent):
super().__init__(parent)
# Убираем сохранение собственного атрибута .parent
# self.parent = parent
self.title("Управление базами данных")
self.geometry("600x400")
# --- ИСПРАВЛЕНИЕ ЗДЕСЬ ---
# Вызываем функцию центрирования только по себе.
# Функция сама найдет главного родителя через self.master
center_on_parent(self)
# Основная структура интерфейса
self.build_ui()
def build_ui(self):
# Основной контейнер
container = ttk.Frame(self)
container.pack(fill="both", expand=True)
# Верхняя панель настроек
top_panel = ttk.Frame(container)
top_panel.pack(fill="x", pady=10)
# Переключатель баз данных
self.use_master_db = tk.BooleanVar(value=False)
style = ttk.Style()
style.configure("RedText.TCheckbutton", foreground="red")
master_db_checkbox = ttk.Checkbutton(
top_panel,
text="Использовать основную базу данных",
variable=self.use_master_db,
style="RedText.TCheckbutton",
)
master_db_checkbox.pack(side="left", padx=10)
# Панель инструментов
tools_panel = ttk.Frame(container)
tools_panel.pack(fill="x", pady=10)
# Кнопка резервного копирования текущей базы
btn_current_backup = ttk.Button(
tools_panel,
text="Создать резервную копию текущей базы",
command=self.backup_current_database,
)
btn_current_backup.pack(side="left", padx=10)
# Кнопка восстановления базы данных
btn_restore = ttk.Button(
tools_panel, text="Восстановить базу данных", command=self.restore_database
)
btn_restore.pack(side="left", padx=10)
# Кнопка миграции баз данных
btn_migrate = ttk.Button(
tools_panel, text="Мигрировать данные", command=self.migrate_databases
)
btn_migrate.pack(side="left", padx=10)
# Таблица резервных копий
backup_columns = ("Дата", "Файл")
self.backups_tree = ttk.Treeview(
container, columns=backup_columns, show="headings"
)
for col in backup_columns:
self.backups_tree.heading(col, text=col)
self.backups_tree.column(col, width=200)
self.backups_tree.pack(fill="both", expand=True)
# Загружаем существующие резервные копии
self.load_backups()
def load_backups(self):
"""Загружает список существующих резервных копий в дерево."""
self.backups_tree.delete(*self.backups_tree.get_children()) # Очищаем дерево
# Директория резервных копий
backup_dir = "backups/"
os.makedirs(backup_dir, exist_ok=True)
# Список всех резервных копий
backups = []
for filename in os.listdir(backup_dir):
if filename.endswith(".db"): # Фильтруем только файлы SQLite
filepath = os.path.join(backup_dir, filename)
creation_time = datetime.fromtimestamp(
os.path.getmtime(filepath)
).strftime("%Y-%m-%d %H:%M:%S")
backups.append({"file": filename, "creation_time": creation_time})
# Сортируем резервные копии по дате создания
sorted_backups = sorted(backups, key=lambda b: b["creation_time"], reverse=True)
# Добавляем записи в TreeView
for backup in sorted_backups:
self.backups_tree.insert(
"", "end", values=(backup["creation_time"], backup["file"])
)
def backup_current_database(self):
"""Создает резервную копию текущей базы данных."""
db_filename = "database.db" if not self.use_master_db.get() else "masterdata.db"
# Полный путь к файлу резервной копии
backup_dir = "backups/"
os.makedirs(backup_dir, exist_ok=True)
now = datetime.now()
backup_filename = f"{now.strftime('%Y-%m-%d_%H-%M-%S')}__{db_filename}"
backup_filepath = os.path.join(backup_dir, backup_filename)
try:
shutil.copy(db_filename, backup_filepath)
messagebox.showinfo(
"Резервное копирование",
f"Резервная копия успешно создана:\n{backup_filepath}",
)
self.load_backups() # Обновляем список резервных копий
except Exception as e:
messagebox.showerror("Ошибка", str(e))
def restore_database(self):
"""Восстанавливает выбранную резервную копию."""
selected_item = self.backups_tree.selection()
if len(selected_item) > 0:
backup_filename = self.backups_tree.item(selected_item)[0]["values"][1]
backup_filepath = os.path.join("backups/", backup_filename)
active_db = (
"database.db" if not self.use_master_db.get() else "masterdata.db"
)
try:
shutil.copy(backup_filepath, active_db)
messagebox.showinfo(
"Восстановление",
f"База данных успешно восстановлена из резервной копии.\nАктивная база данных обновлена.",
)
self.load_backups() # Обновляем список резервных копий
except Exception as e:
messagebox.showerror("Ошибка", str(e))
else:
messagebox.showwarning(
"Предупреждение", "Сначала выберите резервную копию для восстановления."
)
def migrate_databases(self):
"""Выполняет миграцию данных между двумя базами данных."""
if not self.use_master_db.get():
src_db = "database.db"
dest_db = "masterdata.db"
else:
src_db = "masterdata.db"
dest_db = "database.db"
# Создание временной копии исходной базы данных
temp_src_db = f"{src_db}_temp"
shutil.copy(src_db, temp_src_db)
# Перемещение данных
try:
# Открытие обеих баз данных
conn_src = sqlite3.connect(temp_src_db)
conn_dest = sqlite3.connect(dest_db)
# Копирование содержимого одной базы в другую
conn_src.backup(conn_dest)
# Закрытие соединений
conn_src.close()
conn_dest.close()
# Сообщение об успехе
messagebox.showinfo("Миграция", "Данные успешно перенесены.")
except Exception as e:
messagebox.showerror("Ошибка", str(e))