architect/_archive/2025-11-cleanup/templates/by-task/crud/streamlit-crud-v1/README.md

Template: Streamlit CRUD Page v1

ID: streamlit-crud-v1
Категория: crud
Фреймворк: Streamlit
Сложность: Medium-High
Время адаптации: 30-40 минут


ЧТО ЭТО?

Полноценная CRUD (Create, Read, Update, Delete) страница для Streamlit приложений.

Функции:
- ✅ Create: Форма создания новых записей
- 📖 Read: Список всех записей с поиском
- ✏️ Update: Редактирование существующих записей
- 🗑️ Delete: Удаление с подтверждением
- 🔍 Поиск и фильтрация
- ✅ Валидация данных
- ⚠️ Обработка ошибок


УСТАНОВКА

1. Скопировать в проект

cp templates/by-task/crud/streamlit-crud-v1/crud_page.py \
   projects/myproject/pages/Users.py

2. Адаптировать под свою модель

Открыть Users.py и заменить переменные:

# Названия
ENTITY_NAME = "User"
ENTITY_NAME_PLURAL = "Users"
ENTITY_NAME_RU = "Пользователь"
ENTITY_NAME_RU_PLURAL = "Пользователи"

# Импорт модели
from database.models import User

# Поля для формы
FIELDS = {
    'email': 'email',
    'full_name': 'text',
    'role': 'select',
    'active': 'checkbox'
}

# Опции для select полей
SELECT_OPTIONS = {
    'role': ['admin', 'manager', 'user', 'viewer']
}

# Раскомментировать функции get_all_items, create_item и т.д.
# и адаптировать под свою модель

3. Запустить

streamlit run app.py

ТИПЫ ПОЛЕЙ

Поддерживаемые типы полей:

Тип Описание Пример
text Текстовое поле Имя, название
email Email поле Email адрес
number Числовое поле Возраст, количество
select Выпадающий список Роль, статус
checkbox Флаг (да/нет) Активен, подтверждён
textarea Многострочный текст Описание, комментарий
date Дата Дата создания, день рождения

ПРИМЕРЫ

Пример 1: Управление пользователями

ENTITY_NAME = "User"
ENTITY_NAME_PLURAL = "Users"
ENTITY_NAME_RU = "Пользователь"
ENTITY_NAME_RU_PLURAL = "Пользователи"

from database.models import User

FIELDS = {
    'email': 'email',
    'full_name': 'text',
    'role': 'select',
    'active': 'checkbox',
    'created_at': 'date'
}

SELECT_OPTIONS = {
    'role': ['admin', 'manager', 'user', 'viewer']
}

def get_all_items():
    session = get_session()
    try:
        return session.query(User).all()
    finally:
        session.close()

def create_item(data):
    session = get_session()
    try:
        new_user = User(**data)
        session.add(new_user)
        session.commit()
        return new_user
    except Exception as e:
        session.rollback()
        raise e
    finally:
        session.close()

# ... и т.д. для update_item, delete_item

Пример 2: Справочник товаров

ENTITY_NAME = "Product"
ENTITY_NAME_PLURAL = "Products"
ENTITY_NAME_RU = "Товар"
ENTITY_NAME_RU_PLURAL = "Товары"

from database.models import Product

FIELDS = {
    'name': 'text',
    'sku': 'text',
    'price': 'number',
    'category': 'select',
    'description': 'textarea',
    'in_stock': 'checkbox'
}

SELECT_OPTIONS = {
    'category': ['Электроника', 'Одежда', 'Книги', 'Продукты']
}

Пример 3: Управление клиентами

ENTITY_NAME = "Customer"
ENTITY_NAME_PLURAL = "Customers"
ENTITY_NAME_RU = "Клиент"
ENTITY_NAME_RU_PLURAL = "Клиенты"

FIELDS = {
    'name': 'text',
    'email': 'email',
    'phone': 'text',
    'company': 'text',
    'vip': 'checkbox',
    'notes': 'textarea'
}

СТРУКТУРА

templates/by-task/crud/streamlit-crud-v1/
├── README.md              # Этот файл
├── crud_page.py           # Основной шаблон CRUD страницы
└── template.yaml          # Метаданные

WORKFLOW

1. Create (Создание)

  1. Нажать кнопку "➕ Создать"
  2. Заполнить форму
  3. Нажать "✅ Создать"
  4. Запись добавляется в БД
  5. Список обновляется

2. Read (Чтение)

  1. Список всех записей отображается автоматически
  2. Можно использовать поиск для фильтрации
  3. Данные показываются в таблице

3. Update (Обновление)

  1. Выбрать запись из списка
  2. Нажать "✏️ Редактировать"
  3. Изменить поля
  4. Нажать "✅ Сохранить"
  5. Изменения применяются

4. Delete (Удаление)

  1. Выбрать запись из списка
  2. Нажать "🗑️ Удалить"
  3. Подтвердить удаление
  4. Запись удаляется из БД

ВАЛИДАЦИЯ

Встроенная валидация

Streamlit автоматически валидирует:
- Email поля (формат email)
- Числовые поля (только числа)
- Даты (корректная дата)

Кастомная валидация

Добавь валидацию в функции create_item и update_item:

def create_item(data):
    # Валидация
    if not data.get('email'):
        raise ValueError("Email обязателен")

    if len(data.get('full_name', '')) < 3:
        raise ValueError("Имя должно быть минимум 3 символа")

    # Создание
    session = get_session()
    try:
        new_user = User(**data)
        session.add(new_user)
        session.commit()
        return new_user
    except Exception as e:
        session.rollback()
        raise e
    finally:
        session.close()

БЕЗОПАСНОСТЬ

⚠️ ВАЖНО:

  1. Авторизация
    python # Добавить в начало страницы from utils.auth_utils import require_auth require_auth()

  2. Права доступа
    python # Проверка прав перед удалением user = get_current_user() if user['role'] != 'admin': st.error("❌ Недостаточно прав") st.stop()

  3. SQL Injection
    - SQLAlchemy автоматически защищает от SQL injection
    - Используй параметризованные запросы

  4. XSS
    - Streamlit автоматически экранирует HTML
    - Не используй unsafe_allow_html без необходимости


ОПТИМИЗАЦИЯ

Пагинация

Для больших таблиц добавь пагинацию:

# После получения items
items_per_page = 50
page = st.number_input("Страница", min_value=1, value=1)
start = (page - 1) * items_per_page
end = start + items_per_page

items_page = items[start:end]
st.write(f"Показано {start+1}-{min(end, len(items))} из {len(items)}")

Кэширование

Используй @st.cache_data для частых запросов:

@st.cache_data(ttl=60)  # Кэш на 60 секунд
def get_all_items_cached():
    return get_all_items()

ЭКОНОМИЯ ТОКЕНОВ

Генерация с нуля: ~5000 tokens
Адаптация шаблона: ~700 tokens
Экономия: 86%


TROUBLESHOOTING

Ошибка "list index out of range"

Проверь что items не пустой перед доступом к элементам.

Форма не сбрасывается после submit

Используй st.rerun() после успешного создания/обновления.

Дублирование key в Streamlit

Используй уникальные key для каждого поля. В шаблоне используется key_suffix для этого.

Изменения не сохраняются

Проверь:
1. Функция update_item вызывается
2. session.commit() выполняется
3. Нет исключений (проверь логи)


СВЯЗАННЫЕ ШАБЛОНЫ


ДОПОЛНИТЕЛЬНЫЕ ВОЗМОЖНОСТИ

Экспорт данных

# В разделе "Быстрые действия"
with col3:
    if st.button("📥 Экспорт в Excel", use_container_width=True):
        df = pd.DataFrame([vars(item) for item in items])
        buffer = BytesIO()
        with pd.ExcelWriter(buffer, engine='openpyxl') as writer:
            df.to_excel(writer, index=False)
        buffer.seek(0)

        st.download_button(
            label="⬇️ Скачать Excel",
            data=buffer,
            file_name=f"{ENTITY_NAME_PLURAL}_{datetime.now().strftime('%Y%m%d')}.xlsx",
            mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        )

Bulk операции

# Массовое удаление
selected_ids = st.multiselect("Выбрать несколько", item_ids)
if st.button("🗑️ Удалить выбранные"):
    for item_id in selected_ids:
        delete_item(item_id)
    st.success(f"Удалено {len(selected_ids)} записей")
    st.rerun()

Версия: 1.0
Дата: 2025-11-10
Статус: Production ready