From 4b4acdcb1b323e804ff40791fc73c4a36df382e0 Mon Sep 17 00:00:00 2001 From: Daniel Haus Date: Wed, 11 Feb 2026 15:43:30 +0300 Subject: [PATCH] filter's fix --- controllers/catalog_controller.py | 20 +++--- main.py | 5 +- models/database.py | 43 ++++------- models/toy_model.py | 114 ++++++++++-------------------- models/user_model.py | 24 ++++--- views/catalog_view.py | 109 ++++++++++++++++------------ 6 files changed, 144 insertions(+), 171 deletions(-) diff --git a/controllers/catalog_controller.py b/controllers/catalog_controller.py index ba32ed4..7f3d9a1 100644 --- a/controllers/catalog_controller.py +++ b/controllers/catalog_controller.py @@ -5,20 +5,18 @@ from views.catalog_view import CatalogView class CatalogController: def __init__(self, database, full_name, role, auth): self.database = database - self.model = ToyModel(database) - self.view = CatalogView(full_name, role) self.auth = auth self.role = role + self.model = ToyModel(database) - self.view.refresh_button.clicked.connect( - self.load_data - ) - self.view.sort_button.clicked.connect( - self.sort_by_price - ) - self.view.logout_button.clicked.connect( - self.logout - ) + age_groups = self.model.get_age_groups() + suppliers = self.model.get_suppliers() + + self.view = CatalogView(full_name, role, age_groups, suppliers) + + self.view.refresh_button.clicked.connect(self.load_data) + self.view.sort_button.clicked.connect(self.sort_by_price) + self.view.logout_button.clicked.connect(self.logout) self.load_data() diff --git a/main.py b/main.py index b1466ed..e0ad9d7 100644 --- a/main.py +++ b/main.py @@ -2,11 +2,14 @@ import sys from PyQt6.QtWidgets import QApplication from models.database import Database from controllers.auth_controller import AuthController +from config import DB_NAME, DB_USER, DB_PASSWORD def main(): app = QApplication(sys.argv) - database = Database() + database = Database(dbname=DB_NAME, + user=DB_USER, + password=DB_PASSWORD) controller = AuthController(database) controller.show() sys.exit(app.exec()) diff --git a/models/database.py b/models/database.py index 8ec52a6..d2dc0c4 100644 --- a/models/database.py +++ b/models/database.py @@ -1,36 +1,23 @@ import psycopg2 -from psycopg2.extras import RealDictCursor -from config import ( - DB_HOST, - DB_PORT, - DB_NAME, - DB_USER, - DB_PASSWORD, -) class Database: - def __init__(self): - self.connection = psycopg2.connect( - host=DB_HOST, - port=DB_PORT, - dbname=DB_NAME, - user=DB_USER, - password=DB_PASSWORD, - cursor_factory=RealDictCursor, + def __init__(self, dbname, user, password, host="localhost", port=5432): + self.conn = psycopg2.connect( + dbname=dbname, user=user, password=password, host=host, port=port ) - def fetch_all(self, query: str, params: tuple = ()): - with self.connection.cursor() as cursor: - cursor.execute(query, params) - return cursor.fetchall() + def query(self, sql, params=None): + with self.conn.cursor() as cur: + cur.execute(sql, params or ()) + if cur.description: + return cur.fetchall() + return None - def fetch_one(self, query: str, params: tuple = ()): - with self.connection.cursor() as cursor: - cursor.execute(query, params) - return cursor.fetchone() + def fetch_one(self, sql, params=None): + with self.conn.cursor() as cur: + cur.execute(sql, params or ()) + return cur.fetchone() - def execute(self, query: str, params: tuple = ()): - with self.connection.cursor() as cursor: - cursor.execute(query, params) - self.connection.commit() + def commit(self): + self.conn.commit() diff --git a/models/toy_model.py b/models/toy_model.py index 079744d..ff771ed 100644 --- a/models/toy_model.py +++ b/models/toy_model.py @@ -1,87 +1,47 @@ -from models.database import Database - - class ToyModel: - def __init__(self, database: Database): - self.database = database + def __init__(self, database: "Database"): + self.db = database def get_all(self): - query = """ - SELECT t.toy_id, - t.toy_name, - c.category_name, - m.manufacturer_name, - t.price, - t.discount, - COALESCE(s.quantity, 0) AS quantity, - STRING_AGG(DISTINCT a.age_label, ', ') AS ages, - STRING_AGG(DISTINCT sup.supplier_name, ', ') AS suppliers + sql = """ + SELECT t.toy_name, c.category_name, m.manufacturer_name, + STRING_AGG(DISTINCT ag.age_label, ', ') AS ages, + STRING_AGG(DISTINCT s.supplier_name, ', ') AS suppliers, + t.price, t.discount, st.quantity FROM toys t JOIN categories c ON t.category_id = c.category_id JOIN manufacturers m ON t.manufacturer_id = m.manufacturer_id - LEFT JOIN stock s ON t.toy_id = s.toy_id - LEFT JOIN toy_age_groups ta ON t.toy_id = ta.toy_id - LEFT JOIN age_groups a ON ta.age_group_id = a.age_group_id + LEFT JOIN toy_age_groups tag ON t.toy_id = tag.toy_id + LEFT JOIN age_groups ag ON tag.age_group_id = ag.age_group_id LEFT JOIN toy_suppliers ts ON t.toy_id = ts.toy_id - LEFT JOIN suppliers sup ON ts.supplier_id = sup.supplier_id - GROUP BY t.toy_id, c.category_name, - m.manufacturer_name, s.quantity - ORDER BY t.toy_name + LEFT JOIN suppliers s ON ts.supplier_id = s.supplier_id + LEFT JOIN stock st ON t.toy_id = st.toy_id + GROUP BY t.toy_id, c.category_name, m.manufacturer_name, t.price, t.discount, st.quantity + ORDER BY t.toy_id """ - return self.database.fetch_all(query) + rows = self.db.query(sql) + toys = [] + for r in rows: + toys.append({ + "toy_name": r[0], + "category_name": r[1], + "manufacturer_name": r[2], + "ages": r[3] or "", + "suppliers": r[4] or "", + "price": float(r[5]), + "discount": int(r[6]), + "quantity": int(r[7] or 0), + }) + return toys - def search_by_age(self, age: str): - query = """ - SELECT * - FROM ( - SELECT t.toy_id, - t.toy_name, - c.category_name, - m.manufacturer_name, - t.price, - t.discount, - COALESCE(s.quantity, 0) AS quantity, - STRING_AGG(DISTINCT a.age_label, ', ') AS ages, - STRING_AGG(DISTINCT sup.supplier_name, ', ') AS suppliers - FROM toys t - JOIN categories c ON t.category_id = c.category_id - JOIN manufacturers m ON t.manufacturer_id = m.manufacturer_id - LEFT JOIN stock s ON t.toy_id = s.toy_id - LEFT JOIN toy_age_groups ta ON t.toy_id = ta.toy_id - LEFT JOIN age_groups a ON ta.age_group_id = a.age_group_id - LEFT JOIN toy_suppliers ts ON t.toy_id = ts.toy_id - LEFT JOIN suppliers sup ON ts.supplier_id = sup.supplier_id - GROUP BY t.toy_id, c.category_name, - m.manufacturer_name, s.quantity - ) sub - WHERE ages ILIKE %s - """ - return self.database.fetch_all(query, (f"%{age}%",)) + def sort_by_price(self, ascending=True): + toys = self.get_all() + return sorted(toys, key=lambda x: x["price"], reverse=not ascending) - def sort_by_price(self): - query = """ - SELECT * - FROM ( - SELECT t.toy_id, - t.toy_name, - c.category_name, - m.manufacturer_name, - t.price, - t.discount, - COALESCE(s.quantity, 0) AS quantity, - STRING_AGG(DISTINCT a.age_label, ', ') AS ages, - STRING_AGG(DISTINCT sup.supplier_name, ', ') AS suppliers - FROM toys t - JOIN categories c ON t.category_id = c.category_id - JOIN manufacturers m ON t.manufacturer_id = m.manufacturer_id - LEFT JOIN stock s ON t.toy_id = s.toy_id - LEFT JOIN toy_age_groups ta ON t.toy_id = ta.toy_id - LEFT JOIN age_groups a ON ta.age_group_id = a.age_group_id - LEFT JOIN toy_suppliers ts ON t.toy_id = ts.toy_id - LEFT JOIN suppliers sup ON ts.supplier_id = sup.supplier_id - GROUP BY t.toy_id, c.category_name, - m.manufacturer_name, s.quantity - ) sub - ORDER BY price - """ - return self.database.fetch_all(query) + def get_age_groups(self): + rows = self.db.query("SELECT age_label FROM age_groups ORDER BY age_group_id") + return [r[0] for r in rows] + + def get_suppliers(self): + rows = self.db.query("SELECT supplier_name FROM suppliers ORDER BY supplier_id") + return [r[0] for r in rows] diff --git a/models/user_model.py b/models/user_model.py index 3d7af3e..fbf2fb8 100644 --- a/models/user_model.py +++ b/models/user_model.py @@ -1,17 +1,23 @@ from models.database import Database - class UserModel: - def __init__(self, database: Database): - self.database = database + def __init__(self, database): + self.db = database - def authenticate(self, login: str, password: str): - query = """ - SELECT u.user_id, - u.full_name, - r.role_name + def authenticate(self, login, password): + sql = """ + SELECT u.login, u.password, u.full_name, r.role_name FROM users u JOIN roles r ON u.role_id = r.role_id WHERE u.login = %s AND u.password = %s """ - return self.database.fetch_one(query, (login, password)) + row = self.db.fetch_one(sql, (login, password)) + if row: + return { + "login": row[0], + "password": row[1], + "full_name": row[2], + "role_name": row[3], + } + return None + diff --git a/views/catalog_view.py b/views/catalog_view.py index 0d317ee..5d7811f 100644 --- a/views/catalog_view.py +++ b/views/catalog_view.py @@ -1,82 +1,101 @@ from PyQt6.QtWidgets import ( - QWidget, - QVBoxLayout, - QPushButton, - QLabel, - QTableWidget, - QTableWidgetItem, + QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, + QTableWidget, QTableWidgetItem, QComboBox ) from PyQt6.QtGui import QColor from config import DISCOUNT_COLOR, OUT_OF_STOCK_COLOR class CatalogView(QWidget): - def __init__(self, full_name: str, role: str): + def __init__(self, full_name, role, age_groups, suppliers): super().__init__() + self.user_role = role self.setWindowTitle("Каталог игрушек") + self.setFixedSize(860, 500) self.layout = QVBoxLayout() + self.user_label = QLabel(f"{full_name} ({role})") - self.user_label = QLabel( - f"{full_name} ({role})" - ) - + # Кнопки self.refresh_button = QPushButton("Обновить") self.sort_button = QPushButton("Сортировать по цене") self.logout_button = QPushButton("Выйти") + # Фильтры + self.filter_age_combo = QComboBox() + self.filter_supplier_combo = QComboBox() + + self.filter_age_combo.addItem("Все возрастные категории") + for age in age_groups: + self.filter_age_combo.addItem(age) + + self.filter_supplier_combo.addItem("Все поставщики") + for sup in suppliers: + self.filter_supplier_combo.addItem(sup) + + # Включаем фильтры по роли + self.filter_age_combo.setEnabled(role in ("Покупатель", "Сотрудник", "Администратор")) + self.filter_supplier_combo.setEnabled(role in ("Сотрудник", "Администратор")) + + # Панель фильтров и кнопок + top_layout = QHBoxLayout() + top_layout.addWidget(self.refresh_button) + top_layout.addWidget(self.sort_button) + top_layout.addWidget(self.filter_age_combo) + top_layout.addWidget(self.filter_supplier_combo) + top_layout.addWidget(self.logout_button) + self.table = QTableWidget() - self.layout.addWidget(self.user_label) - self.layout.addWidget(self.refresh_button) - self.layout.addWidget(self.sort_button) + self.layout.addLayout(top_layout) self.layout.addWidget(self.table) - self.layout.addWidget(self.logout_button) - self.setLayout(self.layout) - self.setFixedSize(860, 500) + self.filter_age_combo.currentTextChanged.connect(self.apply_filters) + self.filter_supplier_combo.currentTextChanged.connect(self.apply_filters) - def load_data(self, toys: list): + self.all_toys = [] + + def load_data(self, toys): + self.all_toys = toys + self.apply_filters() + + def apply_filters(self): + filtered = self.all_toys + age_filter = self.filter_age_combo.currentText() + supplier_filter = self.filter_supplier_combo.currentText() + + if self.user_role in ("Покупатель", "Сотрудник", "Администратор"): + if age_filter != "Все возрастные категории": + filtered = [t for t in filtered if age_filter in t["ages"].split(", ")] + + if self.user_role in ("Сотрудник", "Администратор"): + if supplier_filter != "Все поставщики": + filtered = [t for t in filtered if supplier_filter in t["suppliers"].split(", ")] + + self._populate_table(filtered) + + def _populate_table(self, toys): headers = [ - "Название", - "Категория", - "Производитель", - "Возраст", - "Поставщик", - "Цена", - "Скидка", - "Остаток", + "Название", "Категория", "Производитель", + "Возраст", "Поставщик", "Цена", "Скидка", "Остаток" ] - self.table.setColumnCount(len(headers)) self.table.setHorizontalHeaderLabels(headers) self.table.setRowCount(len(toys)) for row, toy in enumerate(toys): values = [ - toy["toy_name"], - toy["category_name"], - toy["manufacturer_name"], - toy["ages"], - toy["suppliers"], - str(toy["price"]), - str(toy["discount"]), - str(toy["quantity"]), + toy["toy_name"], toy["category_name"], toy["manufacturer_name"], + toy["ages"], toy["suppliers"], str(toy["price"]), + str(toy["discount"]), str(toy["quantity"]) ] - for col, value in enumerate(values): - item = QTableWidgetItem(value) - self.table.setItem(row, col, item) + self.table.setItem(row, col, QTableWidgetItem(value)) if toy["discount"] >= 25: for col in range(len(headers)): - self.table.item(row, col).setBackground( - QColor(DISCOUNT_COLOR) - ) - + self.table.item(row, col).setBackground(QColor(DISCOUNT_COLOR)) if toy["quantity"] == 0: for col in range(len(headers)): - self.table.item(row, col).setBackground( - QColor(OUT_OF_STOCK_COLOR) - ) + self.table.item(row, col).setBackground(QColor(OUT_OF_STOCK_COLOR))