Загрузка данных
# -*- coding: utf-8 -*-
# modules/data/database_module.py
import sys
import sqlite3
from pathlib import Path
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session as SqlAlchemySession, declarative_base
# --- НАСТРОЙКА ПУТЕЙ К БАЗАМ ДАННЫХ ---
try:
potential_base = Path.cwd()
if "Dozor" not in str(potential_base):
BASE_DIR = Path(__file__).resolve().parents[4]
else:
BASE_DIR = potential_base
DB_FOLDER = BASE_DIR / "db"
# Основная рабочая база (используется SQLAlchemy и get_db_connection)
DB_PATH = DB_FOLDER / "database.db"
# Дополнительная база мастер-данных
MASTERDATA_PATH = DB_FOLDER / "masterdata.db"
except Exception as e:
print(f"[FATAL] Не удалось вычислить путь к базе данных: {e}")
sys.exit(1)
# --- ИНИЦИАЛИЗАЦИЯ SQLALCHEMY ТОЛЬКО ДЛЯ ОСНОВНОЙ БД ---
engine = create_engine(f"sqlite:///{DB_PATH}", echo=False, connect_args={"check_same_thread": False})
Base = declarative_base()
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
def get_db():
"""
Генератор зависимостей для работы внутри функций/контроллеров (основная БД).
"""
db_session = SessionLocal()
try:
yield db_session
finally:
db_session.close()
def get_db_connection():
"""
Старая функция прямого доступа через sqlite3 для совместимости с менеджером проектов.
ВАЖНО: Подключается строго к основной базе DB_PATH.
"""
try:
if not DB_FOLDER.exists():
print(f"[ACTION] Создаю папку для базы: {DB_FOLDER}")
DB_FOLDER.mkdir(parents=True, exist_ok=True)
conn = sqlite3.connect(DB_PATH)
conn.execute("PRAGMA foreign_keys = ON;")
return conn
except Exception as e:
print(f"[FATAL] Не удалось подключиться к БД по пути {DB_PATH}. Ошибка: {e}")
raise
def _create_tables(cursor):
"""Внутренняя функция создания структуры таблиц."""
cursor.execute('''
CREATE TABLE IF NOT EXISTS groups (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
code TEXT NOT NULL UNIQUE,
gain_group REAL DEFAULT 0.0
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS indicators (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL UNIQUE,
code TEXT NOT NULL UNIQUE,
group_code TEXT NOT NULL,
FOREIGN KEY (group_code) REFERENCES groups(code) ON DELETE CASCADE
)
''')
def _populate_test_data(conn):
"""Заполнение базы тестовыми данными, если таблицы пусты."""
cursor = conn.cursor()
cursor.execute("SELECT COUNT(*) FROM groups")
count = cursor.fetchone()[0]
if count == 0:
print("[INFO] База данных пуста. Заполняю тестовыми данными...")
groups_data = [
("Клубы", "KB", 1.5),
("Фанаты", "FAN", 2.0)
]
cursor.executemany("INSERT INTO groups (name, code, gain_group) VALUES (?, ?, ?)", groups_data)
indicators_data = [
("ЦСКА", "KB-1", "KB"),
("Спартак", "KB-2", "KB"),
("Зенит", "KB-3", "KB"),
("Мужчины", "FAN-1", "FAN"),
("Женщины", "FAN-2", "FAN"),
("Дети", "FAN-3", "FAN")
]
cursor.executemany(
"INSERT INTO indicators (name, code, group_code) VALUES (?, ?, ?)",
indicators_data
)
conn.commit()
print("[SUCCESS] Тестовые данные успешно записаны.")
else:
print("[INFO] База данных уже содержит данные. Пропускаю инициализацию.")
def init_database():
"""
Главная точка входа. Вызывается из main.py.
Проверяет наличие ОБЕИХ баз данных и создает их при необходимости.
"""
print("[INIT] Проверка наличия рабочих баз данных...")
# --- 1. Инициализация database.db (через старую функцию для менеджеров) ---
try:
conn = get_db_connection()
cursor = conn.cursor()
_create_tables(cursor)
_populate_test_data(conn)
except sqlite3.Error as e:
print(f"[ERROR] Ошибка при инициализации DATABASE.DB: {e}")
if conn:
conn.rollback()
finally:
if conn:
conn.close()
# --- 2. Инициализация masterdata.db (отдельное соединение) ---
master_conn = None
try:
if not MASTERDATA_PATH.exists():
print(f"[ACTION] База мастер-данных не найдена. Создаю новую: {MASTERDATA_PATH.name}")
master_conn = sqlite3.connect(MASTERDATA_PATH)
master_conn.execute("PRAGMA foreign_keys = ON;")
master_cursor = master_conn.cursor()
_create_tables(master_cursor)
_populate_test_data(master_conn)
except sqlite3.Error as e:
print(f"[ERROR] Ошибка при инициализации MASTERDATA.DB: {e}")
if master_conn:
master_conn.rollback()
finally:
if master_conn:
master_conn.close()
# --- ЗАГЛУШКИ ДЛЯ GUI ---
class Session:
"""Заглушка класса Session для старых импортов в интерфейсах."""
def __init__(self):
pass
def list_groups():
"""Возвращает тестовые группы для выпадающих списков."""
return [(1, "Клубы"), (2, "Фанаты")]
def get_all_indicators_by_group(group_code):
"""Возвращает тестовые показатели по коду группы."""
mock_data = {
"KB": [(1, "ЦСКА"), (2, "Спартак"), (3, "Зенит")],
"FAN": [(4, "Мужчины"), (5, "Женщины"), (6, "Дети")]
}
return mock_data.get(group_code, [])
if __name__ == "__main__":
init_database()