Удалить README.md
This commit is contained in:
parent
50138b1406
commit
e8756998ac
1 changed files with 0 additions and 241 deletions
241
README.md
241
README.md
|
|
@ -1,241 +0,0 @@
|
||||||
# Шпаргалка — экзамен (pyqt6 + QtSql)
|
|
||||||
Коротко, по делу. Храни в `README.md` и читай в метро.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Цель на экзамене
|
|
||||||
- Сделать минимальное рабочее приложение: **логин → ролевое окно (админ/менеджер/клиент)**.
|
|
||||||
- Главное: видно, работает, объясняешь. Не идеальная архитектура — рабочий код.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Минимальная структура проекта (рабочая)
|
|
||||||
|
|
||||||
```
|
|
||||||
project/
|
|
||||||
├─ main.py # вызывает Composer.run()
|
|
||||||
├─ composer.py # composition root: создаёт QApplication, LoginWindow, (после логина) MainWindow/Screen
|
|
||||||
├─ ui/
|
|
||||||
│ ├─ base.py # BaseWindow, BaseScreen
|
|
||||||
│ ├─ windows.py # LoginWindow, MainWindow
|
|
||||||
│ └─ screens.py # LoginScreen, AdminScreen (QTabWidget / TableTab)
|
|
||||||
├─ utils/
|
|
||||||
│ ├─ ui.py # TableTab (QTableView + кнопки)
|
|
||||||
│ ├─ drivers.py # LoginDriver, AdminDriver (логика кнопок)
|
|
||||||
│ └─ dialogs.py
|
|
||||||
├─ db/
|
|
||||||
│ ├─ core.py # get_connection(), DB wrappers
|
|
||||||
│ └─ objects.py # User, Rights
|
|
||||||
└─ requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Быстрая идея архитектуры (экзамен)
|
|
||||||
- **UI** — только виджеты (без бизнес-логики).
|
|
||||||
- **Driver** — логика виджета (обработчики кнопок), вызывает callback/сигналы.
|
|
||||||
- **Composer** — создаёт окна/драйверы и подписывается на сигналы (переходы экранов).
|
|
||||||
|
|
||||||
**Почему callback:** не импортируем Composer в UI (избегаем циклических импортов). Передаём `on_event` в драйвер — драйвер вызывает его.
|
|
||||||
|
|
||||||
Пример передачи callback:
|
|
||||||
```python
|
|
||||||
# в Composer
|
|
||||||
driver = LoginDriver(login_screen, on_success=self._on_login_success)
|
|
||||||
|
|
||||||
# в LoginDriver
|
|
||||||
self.on_success(user) # вместо `composer.do(...)`
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Минимум кода для переключения экранов
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Composer._login_fabric()
|
|
||||||
self.wlogin = LoginWindow()
|
|
||||||
self.slogin = LoginScreen()
|
|
||||||
self.wlogin.setCentralWidget(self.slogin)
|
|
||||||
self.dlogin = LoginDriver(self.slogin, on_success=self._on_login_success)
|
|
||||||
|
|
||||||
def _on_login_success(self, user):
|
|
||||||
if user.rights == Rights.ADMIN:
|
|
||||||
self._admin_fabric()
|
|
||||||
self.main.show()
|
|
||||||
```
|
|
||||||
|
|
||||||
5. AdminScreen / TableTab — разметка
|
|
||||||
|
|
||||||
QTabWidget с вкладками: bookings, payments, rooms, guests, users, staff.
|
|
||||||
|
|
||||||
Вкладка содержит:
|
|
||||||
|
|
||||||
(опционально) область фильтра сверху (QDateEdit/QDateTimeEdit + кнопки Фильтровать / Показать все)
|
|
||||||
|
|
||||||
QTableView (центр)
|
|
||||||
|
|
||||||
кнопки Добавить, Удалить, Экспорт CSV (внизу)
|
|
||||||
|
|
||||||
TableTab должен создавать QSqlTableModel и устанавливать view.setModel(model).
|
|
||||||
|
|
||||||
6. QSqlTableModel — основные операции
|
|
||||||
```python
|
|
||||||
model = QSqlTableModel(db=db)
|
|
||||||
model.setTable("bookings")
|
|
||||||
model.setEditStrategy(QSqlTableModel.EditStrategy.OnManualSubmit) # удобно для админки
|
|
||||||
model.select()
|
|
||||||
view.setModel(model)
|
|
||||||
|
|
||||||
# Добавить
|
|
||||||
model.insertRow(model.rowCount())
|
|
||||||
model.submitAll() # если OnManualSubmit - вызвать для сохранения
|
|
||||||
|
|
||||||
# Удалить (с подтверждением)
|
|
||||||
model.removeRow(row)
|
|
||||||
model.submitAll()
|
|
||||||
|
|
||||||
# Фильтр (bookings: checkin / checkout)
|
|
||||||
model.setFilter("DATE(checkin) >= '2025-01-01' AND DATE(checkout) <= '2025-01-10'")
|
|
||||||
model.select()
|
|
||||||
```
|
|
||||||
7. Частые ошибки (и их исправления)
|
|
||||||
|
|
||||||
```
|
|
||||||
QSqlDatabase.drivers(): QSqlDatabase requires a QCoreApplication
|
|
||||||
— вызовите QApplication([]) (или QCoreApplication) до использования QSqlDatabase.
|
|
||||||
|
|
||||||
Lambda в цикле захватывает переменную → все слоты привязаны к последнему tab.
|
|
||||||
Используйте lambda _, t=tab: handler(t) или functools.partial(handler, tab).
|
|
||||||
|
|
||||||
Опечатки: self_current → self._current. QMesssageBox → QMessageBox. StandartButton → StandardButton.
|
|
||||||
|
|
||||||
QMessageBox: QMessageBox.information(parent, title, text); QMessageBox.question(...) возвращает StandardButton.
|
|
||||||
|
|
||||||
SQL сравнения: используйте >=, <=, не =>.
|
|
||||||
|
|
||||||
Если модель не отображает изменения — вызовите model.select() или view.repaint().
|
|
||||||
|
|
||||||
Не дублировать подключение DB: создавайте QSqlDatabase.addDatabase(...) один раз, передавайте объект db в TableTab или делайте это в BaseScreen._setup_qsql().
|
|
||||||
```
|
|
||||||
|
|
||||||
8. Экспорт CSV (быстро)
|
|
||||||
|
|
||||||
```python
|
|
||||||
with open("bookings.csv", "w", newline="", encoding="utf-8") as f:
|
|
||||||
writer = csv.writer(f)
|
|
||||||
headers = [model.headerData(i, Qt.Orientation.Horizontal) for i in range(model.columnCount())]
|
|
||||||
writer.writerow(headers)
|
|
||||||
for r in range(model.rowCount()):
|
|
||||||
row = [model.data(model.index(r,c)) for c in range(model.columnCount())]
|
|
||||||
writer.writerow(row)
|
|
||||||
```
|
|
||||||
|
|
||||||
Показываем QMessageBox.information(...) по завершении.
|
|
||||||
|
|
||||||
9. Загрузка тестовых xlsx → DB (Windows, быстро, <10 строчек)
|
|
||||||
|
|
||||||
Вариант GUI (рекомендуемый на экзамене):
|
|
||||||
|
|
||||||
Открыть xlsx в Excel.
|
|
||||||
|
|
||||||
File -> Save As → CSV для каждого листа.
|
|
||||||
|
|
||||||
В pgAdmin открыть таблицу → Import/Export → выбрать CSV и импортировать.
|
|
||||||
|
|
||||||
Вариант psql:
|
|
||||||
|
|
||||||
\copy guests(name, surname, patronym, passport_seria, passport_number, phone) FROM 'guests.csv' DELIMITER ',' CSV HEADER;
|
|
||||||
|
|
||||||
|
|
||||||
(исполнить в psql)
|
|
||||||
|
|
||||||
10. Если MySQL (pymysql) вместо PostgreSQL
|
|
||||||
|
|
||||||
db.core: замените psycopg2 на pymysql:
|
|
||||||
|
|
||||||
```python
|
|
||||||
import pymysql
|
|
||||||
def get_connection():
|
|
||||||
return pymysql.connect(host='localhost', port=3306, user='user', password='pw', db='dbname', charset='utf8mb4', cursorclass=pymysql.cursors.Cursor)
|
|
||||||
```
|
|
||||||
|
|
||||||
Важно: QSqlTableModel использует Qt SQL драйверы (QPSQL, QMYSQL).
|
|
||||||
|
|
||||||
Если вы хотите, чтобы QSqlTableModel работал с MySQL, нужен Qt-плагин qsqlmysql (в комплекте с Qt).
|
|
||||||
|
|
||||||
Если плагина нет, либо используйте QSqlDatabase.addDatabase("QMYSQL") (и установите/расположите плагин), либо не используйте QSqlTableModel: читайте данные через pymysql и реализуйте QAbstractTableModel вручную (сложнее).
|
|
||||||
|
|
||||||
Если вы только используете pymysql в db.core и все UI модели по-прежнему QSqlTableModel с QSqlDatabase("QPSQL"), это НЕ прокатит — нужно согласовать.
|
|
||||||
|
|
||||||
11. Ошибка QSqlDatabase.drivers() — решение
|
|
||||||
|
|
||||||
Создайте QApplication([]) перед вызовом. Пример:
|
|
||||||
|
|
||||||
from PyQt6.QtWidgets import QApplication
|
|
||||||
from PyQt6.QtSql import QSqlDatabase
|
|
||||||
|
|
||||||
app = QApplication([])
|
|
||||||
print(QSqlDatabase.drivers()) # OK
|
|
||||||
|
|
||||||
12. Полезные сниппеты (на экзамене — запомнить)
|
|
||||||
|
|
||||||
```
|
|
||||||
lambda capture
|
|
||||||
|
|
||||||
for tab in tabs:
|
|
||||||
tab.btn.clicked.connect(lambda _, t=tab: do_something(t))
|
|
||||||
|
|
||||||
|
|
||||||
submitAll
|
|
||||||
|
|
||||||
if not model.submitAll():
|
|
||||||
print(model.lastError().text())
|
|
||||||
|
|
||||||
|
|
||||||
open DB in BaseScreen
|
|
||||||
|
|
||||||
db = QSqlDatabase.addDatabase("QPSQL")
|
|
||||||
db.setHostName(...)
|
|
||||||
db.open()
|
|
||||||
```
|
|
||||||
|
|
||||||
13. Тайм-менеджмент (чек-лист перед экзаменом)
|
|
||||||
|
|
||||||
0–5 мин: открыть проект, убедиться, что main.py запускается.
|
|
||||||
|
|
||||||
5–25 мин: реализовать/проверить LoginWindow + LoginDriver + DB authenticate.
|
|
||||||
|
|
||||||
25–55 мин: реализовать AdminScreen (TableTab) и подключить QSqlTableModel (bookings/payments first).
|
|
||||||
|
|
||||||
55–75 мин: добавить кнопки Add/Delete/Export CSV для текущей вкладки.
|
|
||||||
|
|
||||||
75–90 мин: протестировать фильтр по датам (bookings/payments).
|
|
||||||
|
|
||||||
90–120 мин: мелкие фиксы, подготовка к демонстрации (порядок запуска, что сказать).
|
|
||||||
|
|
||||||
14. Что говорить на защите (30–60 сек)
|
|
||||||
|
|
||||||
"Архитектура: UI — presentation, драйверы — логика виджетов, Composer — собирает приложение и управляет переходами."
|
|
||||||
|
|
||||||
"DB: использую PostgreSQL, таблицы: guests, rooms, bookings, payments, staff, users. QSqlTableModel для отображения и редактирования."
|
|
||||||
|
|
||||||
"Вкладки: bookings/payments — фильтр по дате; остальные — интерактивный редактор и экспорт CSV."
|
|
||||||
|
|
||||||
"Безопасность: подтверждение удаления; ошибки DB показываются через диалоги."
|
|
||||||
|
|
||||||
15. Быстрые исправления при баге
|
|
||||||
|
|
||||||
nothing happens on click → проверь: (1) слот подключён? (2) метод _setup_db не перезаписывает модель? (3) lambda closure bug?
|
|
||||||
|
|
||||||
QSqlDatabase.drivers() error → убедись, что QApplication создан.
|
|
||||||
|
|
||||||
filter не срабатывает → проверь SQL-условие и формат даты (YYYY-MM-DD).
|
|
||||||
|
|
||||||
16. Последние советы (психология)
|
|
||||||
|
|
||||||
Если устал — 20–30 мин сна/отдыха дадут больше, чем бессонная борьба.
|
|
||||||
|
|
||||||
На экзамене — работая стабильно и объясняя логику, можно получить высокий балл даже без всех «крутых» фич.
|
|
||||||
|
|
||||||
Делай минимально рабочую вещь первым, потом дополняй.
|
|
||||||
|
|
||||||
Удачи на экзамене — ты уже сделал огромную работу.
|
|
||||||
Если хочешь, могу за 10–15 минут сжато подготовить короткую шпаргалку именно по запуску проекта (команды, быстрые проверки).
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue