Загрузка данных
import os
import random
import sqlite3
from datetime import datetime, timedelta
DB_NAME = "electronics_store.db"
# ==============================================================================
# 1. ИНИЦИАЛИЗАЦИЯ СХЕМЫ БАЗЫ ДАННЫХ
# ==============================================================================
CREATE_TABLES_SQL = """
PRAGMA foreign_keys = ON;
CREATE TABLE IF NOT EXISTS Category (
category_id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT
);
CREATE TABLE IF NOT EXISTS Brand (
brand_id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT
);
CREATE TABLE IF NOT EXISTS Brand_Category (
brand_id INTEGER NOT NULL,
category_id INTEGER NOT NULL,
PRIMARY KEY (brand_id, category_id),
FOREIGN KEY (brand_id) REFERENCES Brand(brand_id) ON DELETE CASCADE,
FOREIGN KEY (category_id) REFERENCES Category(category_id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS Supplier (
supplier_id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
contact_person VARCHAR(100),
phone VARCHAR(20),
email VARCHAR(100),
address TEXT
);
CREATE TABLE IF NOT EXISTS User (
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
phone VARCHAR(20),
password_hash VARCHAR(255) NOT NULL,
address TEXT
);
CREATE TABLE IF NOT EXISTS Product (
product_id INTEGER PRIMARY KEY AUTOINCREMENT,
name VARCHAR(100) NOT NULL,
description TEXT,
price DECIMAL(10, 2) NOT NULL,
stock INTEGER NOT NULL DEFAULT 0,
category_id INTEGER NOT NULL,
brand_id INTEGER NOT NULL,
supplier_id INTEGER NOT NULL,
warranty VARCHAR(50),
FOREIGN KEY (category_id) REFERENCES Category(category_id),
FOREIGN KEY (brand_id) REFERENCES Brand(brand_id),
FOREIGN KEY (supplier_id) REFERENCES Supplier(supplier_id)
);
CREATE TABLE IF NOT EXISTS Orders (
order_id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
order_date DATETIME NOT NULL,
status VARCHAR(20) NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL DEFAULT 0.00,
delivery_address TEXT,
FOREIGN KEY (user_id) REFERENCES User(user_id)
);
CREATE TABLE IF NOT EXISTS Order_Item (
order_item_id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
quantity INTEGER NOT NULL DEFAULT 1,
price DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES Orders(order_id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES Product(product_id)
);
CREATE TABLE IF NOT EXISTS Delivery (
delivery_id INTEGER PRIMARY KEY AUTOINCREMENT,
order_id INTEGER UNIQUE NOT NULL,
courier VARCHAR(100),
tracking_number VARCHAR(50),
delivery_date DATETIME,
status VARCHAR(20) NOT NULL,
FOREIGN KEY (order_id) REFERENCES Orders(order_id) ON DELETE CASCADE
);
"""
def get_connection():
conn = sqlite3.connect(DB_NAME)
conn.execute("PRAGMA foreign_keys = ON;")
conn.row_factory = sqlite3.Row
return conn
def init_db():
with get_connection() as conn:
conn.executescript(CREATE_TABLES_SQL)
# ==============================================================================
# 2. ГЕНЕРАЦИЯ СЛУЧАЙНЫХ ДАННЫХ (SEEDING)
# ==============================================================================
def seed_data():
conn = get_connection()
cursor = conn.cursor()
# Проверка, заполнена ли уже БД
cursor.execute("SELECT COUNT(*) FROM User;")
if cursor.fetchone()[0] > 0:
print("[!] База данных уже содержит данные. Пропуск генерации.")
conn.close()
return
print("[+] Генерация реалистичных случайных данных...")
# 1. Категории
categories = [
("Смартфоны", "Мобильные телефоны и аксессуары"),
("Ноутбуки", "Портативные компьютеры и ультрабуки"),
("Телевизоры", "Smart TV, OLED и 4K панели"),
("Аудио", "Наушники, акустика и колонки"),
("Умный дом", "Датчики, розетки и хабы"),
]
cursor.executemany(
"INSERT INTO Category (name, description) VALUES (?, ?)", categories
)
# 2. Бренды
brands = [
("Apple", "Американская корпорация"),
("Samsung", "Южнокорейский гигант электроники"),
("Sony", "Японский производитель мультимедиа"),
("Xiaomi", "Китайский бренд доступной техники"),
("ASUS", "Тайваньский производитель ПК"),
]
cursor.executemany(
"INSERT INTO Brand (name, description) VALUES (?, ?)", brands
)
# 3. Связь Бренд-Категория
brand_categories = [
(1, 1),
(1, 2),
(1, 4), # Apple: Смартфоны, Ноутбуки, Аудио
(2, 1),
(2, 2),
(2, 3), # Samsung: Смартфоны, Ноутбуки, ТВ
(3, 3),
(3, 4), # Sony: ТВ, Аудио
(4, 1),
(4, 4),
(4, 5), # Xiaomi: Смартфоны, Аудио, Умный дом
(5, 2), # ASUS: Ноутбуки
]
cursor.executemany(
"INSERT INTO Brand_Category (brand_id, category_id) VALUES (?, ?)",
brand_categories,
)
# 4. Поставщики
suppliers = [
(
"ООО ТехноИмпорт",
"Иван Петров",
"+79991112233",
"info@technoimport.ru",
"г. Москва, ул. Складская, 10",
),
(
"АО ЭлектроСнаб",
"Елена Сидорова",
"+79992223344",
"sales@electrosnab.ru",
"г. Санкт-Петербург, Невский пр., 50",
),
(
"Global Tech Ltd",
"Дмитрий Ковалев",
"+79993334455",
"contact@globaltech.com",
"г. Новосибирск, ул. Ленина, 12",
),
]
cursor.executemany(
"INSERT INTO Supplier (name, contact_person, phone, email, address) VALUES (?, ?, ?, ?, ?)",
suppliers,
)
# 5. Пользователи
first_names = ["Алексей", "Мария", "Сергей", "Анна", "Михаил", "Ольга"]
last_names = [
"Иванов",
"Смирнова",
"Кузнецов",
"Попова",
"Васильев",
"Соколова",
]
cities = ["Москва", "Казань", "Екатеринбург", "Нижний Новгород", "Самара"]
users = []
for i in range(1, 10):
fname = random.choice(first_names)
lname = random.choice(last_names)
name = f"{fname} {lname}"
email = f"user{i}_{random.randint(100, 999)}@example.com"
phone = f"+7900{random.randint(1000000, 9999999)}"
pwd_hash = f"hash_{random.randint(100000, 999999)}"
address = f"г. {random.choice(cities)}, ул. Лесная, д. {random.randint(1, 100)}"
users.append((name, email, phone, pwd_hash, address))
cursor.executemany(
"INSERT INTO User (name, email, phone, password_hash, address) VALUES (?, ?, ?, ?, ?)",
users,
)
# 6. Товары
product_templates = [
("Смартфон Pro", 1, [1, 2, 4], 60000, 120000, "12 месяцев"),
("Ультрабук Slim", 2, [1, 2, 5], 80000, 200000, "24 месяца"),
("Телевизор 4K 55'", 3, [2, 3], 45000, 110000, "12 месяцев"),
("Беспроводные наушники", 4, [1, 3, 4], 5000, 30000, "12 месяцев"),
("Умный хаб", 5, [4], 3000, 8000, "6 месяцев"),
]
products = []
for name_prefix, cat_id, available_brands, min_p, max_p, warranty in product_templates:
for _ in range(2): # по 2 товара каждого вида
b_id = random.choice(available_brands)
s_id = random.randint(1, len(suppliers))
full_name = f"{name_prefix} v{random.randint(1, 5)}"
price = round(random.uniform(min_p, max_p), 2)
stock = random.randint(5, 50)
desc = f"Высококачественный {full_name} с гарантийным обслуживанием."
products.append(
(
full_name,
desc,
price,
stock,
cat_id,
b_id,
s_id,
warranty,
)
)
cursor.executemany(
"""INSERT INTO Product (name, description, price, stock, category_id, brand_id, supplier_id, warranty)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
products,
)
# 7. Заказы, Позиции заказа, Доставка
statuses_order = ["Новый", "В обработке", "Завершен", "Отменен"]
statuses_delivery = ["В пути", "Доставлено", "Ожидает курьера"]
couriers = [
"СДЭК",
"Яндекс Доставка",
"Почта России",
"Собственная служба",
]
for order_id_iter in range(1, 11):
u_id = random.randint(1, len(users))
days_ago = random.randint(1, 30)
order_date = datetime.now() - timedelta(
days=days_ago, hours=random.randint(1, 10)
)
status = random.choice(statuses_order)
delivery_addr = f"г. {random.choice(cities)}, ул. Центральная, д. {random.randint(1, 50)}"
cursor.execute(
"INSERT INTO Orders (user_id, order_date, status, total_amount, delivery_address) VALUES (?, ?, ?, 0, ?)",
(u_id, order_date.strftime("%Y-%m-%d %H:%M:%S"), status, delivery_addr),
)
order_id = cursor.lastrowid
# Позиции заказа
num_items = random.randint(1, 3)
total_sum = 0.0
chosen_products = random.sample(range(1, len(products) + 1), num_items)
for p_id in chosen_products:
cursor.execute(
"SELECT price FROM Product WHERE product_id = ?", (p_id,)
)
price = cursor.fetchone()[0]
qty = random.randint(1, 2)
total_sum += float(price) * qty
cursor.execute(
"INSERT INTO Order_Item (order_id, product_id, quantity, price) VALUES (?, ?, ?, ?)",
(order_id, p_id, qty, price),
)
# Обновляем итоговую сумму заказа
cursor.execute(
"UPDATE Orders SET total_amount = ? WHERE order_id = ?",
(total_sum, order_id),
)
# Создаем доставку для завершенных или обрабатываемых заказов
if status in ["В обработке", "Завершен"]:
del_status = (
"Доставлено" if status == "Завершен" else random.choice(statuses_delivery)
)
del_date = order_date + timedelta(days=random.randint(1, 3))
track_num = f"TRK{random.randint(100000, 999999)}"
cursor.execute(
"""INSERT INTO Delivery (order_id, courier, tracking_number, delivery_date, status)
VALUES (?, ?, ?, ?, ?)""",
(
order_id,
random.choice(couriers),
track_num,
del_date.strftime("%Y-%m-%d %H:%M:%S"),
del_status,
),
)
conn.commit()
conn.close()
print("[+] Генерация тестовых данных успешно завершена!")
# ==============================================================================
# 3. МЕНЮ И CRUD-ОПЕРАЦИИ
# ==============================================================================
TABLES = [
"Category",
"Brand",
"Brand_Category",
"Supplier",
"User",
"Product",
"Orders",
"Order_Item",
"Delivery",
]
def print_table(rows, columns):
"""Красивый вывод табличных данных в консоль"""
if not rows:
print("\n[i] Записи не найдены.")
return
col_widths = {col: len(col) for col in columns}
for row in rows:
for col in columns:
val_str = str(row[col]) if row[col] is not None else "NULL"
col_widths[col] = max(col_widths[col], len(val_str))
header = " | ".join(col.ljust(col_widths[col]) for col in columns)
separator = "-+-".join("-" * col_widths[col] for col in columns)
print("\n" + header)
print(separator)
for row in rows:
line = " | ".join(
(str(row[col]) if row[col] is not None else "NULL").ljust(
col_widths[col]
)
for col in columns
)
print(line)
print()
def get_table_schema(table_name):
"""Получить информацию о столбцах таблицы"""
conn = get_connection()
cursor = conn.cursor()
cursor.execute(f"PRAGMA table_info({table_name});")
columns = cursor.fetchall()
conn.close()
return columns # list of tuples: (cid, name, type, notnull, dflt_value, pk)
def handle_read(table_name):
"""Чтение (READ) данных"""
conn = get_connection()
cursor = conn.cursor()
cursor.execute(f"SELECT * FROM {table_name}")
rows = cursor.fetchall()
if rows:
columns = rows[0].keys()
print(f"\n=== Содержимое таблицы: {table_name} ===")
print_table(rows, columns)
else:
print(f"\n[i] Таблица {table_name} пуста.")
conn.close()
def handle_create(table_name):
"""Создание (CREATE) записи"""
cols_info = get_table_schema(table_name)
fields = []
values = []
print(f"\n--- Добавление записи в {table_name} ---")
for col in cols_info:
col_name = col[1]
is_pk = col[5]
# Пропускаем автоинкрементный PK (если он один)
if is_pk and "INT" in col[2].upper():
continue
val = input(f"Введите '{col_name}' ({col[2]}): ").strip()
if val == "":
values.append(None)
else:
values.append(val)
fields.append(col_name)
placeholders = ", ".join(["?"] * len(fields))
fields_str = ", ".join(fields)
sql = f"INSERT INTO {table_name} ({fields_str}) VALUES ({placeholders})"
try:
conn = get_connection()
cursor = conn.cursor()
cursor.execute(sql, values)
conn.commit()
print("[+] Запись успешно добавлена!")
except Exception as e:
print(f"[!] Ошибка при добавлении: {e}")
finally:
conn.close()
def handle_update(table_name):
"""Обновление (UPDATE) записи"""
cols_info = get_table_schema(table_name)
pk_cols = [col[1] for col in cols_info if col[5] > 0]
if not pk_cols:
print("[!] Таблица не имеет первичного ключа для обновления.")
return
handle_read(table_name)
print(f"--- Обновление записи в {table_name} ---")
where_clauses = []
where_values = []
for pk in pk_cols:
val = input(f"Введите значение PK '{pk}' для изменяемой записи: ").strip()
where_clauses.append(f"{pk} = ?")
where_values.append(val)
set_clauses = []
update_values = []
print("Введите новые значения (оставьте пустым, чтобы не менять):")
for col in cols_info:
col_name = col[1]
if col_name in pk_cols:
continue
val = input(f"Новое значение для '{col_name}': ")
if val != "":
set_clauses.append(f"{col_name} = ?")
update_values.append(val)
if not set_clauses:
print("[i] Ничего не изменено.")
return
sql = f"UPDATE {table_name} SET {', '.join(set_clauses)} WHERE {' AND '.join(where_clauses)}"
full_params = update_values + where_values
try:
conn = get_connection()
cursor = conn.cursor()
cursor.execute(sql, full_params)
conn.commit()
if cursor.rowcount > 0:
print("[+] Запись успешно обновлена!")
else:
print("[!] Запись с указанным PK не найдена.")
except Exception as e:
print(f"[!] Ошибка при обновлении: {e}")
finally:
conn.close()
def handle_delete(table_name):
"""Удаление (DELETE) записи"""
cols_info = get_table_schema(table_name)
pk_cols = [col[1] for col in cols_info if col[5] > 0]
if not pk_cols:
print("[!] Не удалось определить первичный ключ.")
return
handle_read(table_name)
print(f"--- Удаление записи из {table_name} ---")
where_clauses = []
where_values = []
for pk in pk_cols:
val = input(f"Введите значение PK '{pk}' для удаления: ").strip()
where_clauses.append(f"{pk} = ?")
where_values.append(val)
sql = f"DELETE FROM {table_name} WHERE {' AND '.join(where_clauses)}"
try:
conn = get_connection()
cursor = conn.cursor()
cursor.execute(sql, where_values)
conn.commit()
if cursor.rowcount > 0:
print("[+] Запись успешно удалена!")
else:
print("[!] Запись не найдена.")
except Exception as e:
print(f"[!] Ошибка при удалении: {e}")
finally:
conn.close()
def table_menu(table_name):
"""Подменю CRUD-операций для конкретной таблицы"""
while True:
print(f"\n=== Управление таблицей: [{table_name}] ===")
print("1. Посмотреть записи (READ)")
print("2. Добавить запись (CREATE)")
print("3. Изменить запись (UPDATE)")
print("4. Удалить запись (DELETE)")
print("0. Назад в главное меню")
choice = input("Выберите действие (0-4): ").strip()
if choice == "1":
handle_read(table_name)
elif choice == "2":
handle_create(table_name)
elif choice == "3":
handle_update(table_name)
elif choice == "4":
handle_delete(table_name)
elif choice == "0":
break
else:
print("[!] Неверный ввод, повторите попытку.")
def main_menu():
"""Главное меню программы"""
init_db()
seed_data()
while True:
print("\n==========================================")
print(" СУБД: Магазин электроники (Main Menu) ")
print("==========================================")
print("Выберите таблицу для работы:")
for idx, tbl in enumerate(TABLES, 1):
print(f"{idx}. {tbl}")
print("0. Выход из программы")
choice = input("\nВведите номер (0-9): ").strip()
if choice == "0":
print("\nЗавершение работы. До свидания!")
break
elif choice.isdigit() and 1 <= int(choice) <= len(TABLES):
selected_table = TABLES[int(choice) - 1]
table_menu(selected_table)
else:
print("[!] Ошибка ввода. Укажите число из списка.")
if __name__ == "__main__":
main_menu()