From 71059bdae68a6180d25622820a0b19f9d88bbba4 Mon Sep 17 00:00:00 2001 From: erjemin Date: Mon, 18 May 2026 15:17:35 +0300 Subject: [PATCH] =?UTF-8?q?mod:=20=D0=92=D1=81=D0=B5=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=BA=D0=BE=D0=BD=D1=82=D0=B5=D0=B9=D0=BD=D0=B5=D1=80=D0=B0?= =?UTF-8?q?=20=D0=B2=20dev-=D1=80=D0=B5=D0=B6=D0=B8=D0=BC=D0=B5.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 4 + .env.sample | 4 +- .gitignore | 4 + Dockerfile | 88 ++++++++ SETUP.md | 407 +++++++++++----------------------- docker-compose.local.yml | 64 ++++++ oknardia/oknardia/settings.py | 58 ++++- poetry.lock | 48 +++- pyproject.toml | 2 + 9 files changed, 400 insertions(+), 279 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.local.yml diff --git a/.dockerignore b/.dockerignore index ea187b6..faba60e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -78,6 +78,10 @@ public/static/**/*.map *.temp *.bak +# Шрифты +*.ttf +*.otf + # Системные файлы macOS .AppleDouble .LSOverride diff --git a/.env.sample b/.env.sample index 2d19ba7..f206662 100644 --- a/.env.sample +++ b/.env.sample @@ -25,6 +25,8 @@ ADMINS=Admin:admin@example.com # URL для доступа к админке Django (можно сменить для безопасности, чтобы боты не могли её найти) ADMIN_URL=admin/ +DJANGO_CSRF_TRUSTED_ORIGINS=http://127.0.0.1:8000,http://localhost:8000,https://oknardia.ru,https://tmp.oknardia.ru + # ============================================================================ # DATABASE # ============================================================================ @@ -35,7 +37,7 @@ DATABASE_ENGINE=django.db.backends.sqlite3 # Имя/путь базы данных: # - для SQLite: только имя файла (полный путь соберется в settings.py через PROJECT_ROOT/database) # - для MySQL/MariaDB: имя базы -DATABASE_NAME=oknadria.sqlite3 +DATABASE_NAME=oknardia.sqlite3 # Для MySQL/MariaDB (используются, если DATABASE_ENGINE=django.db.backends.mysql) # DATABASE_HOST=localhost diff --git a/.gitignore b/.gitignore index 70518bb..a455915 100755 --- a/.gitignore +++ b/.gitignore @@ -164,3 +164,7 @@ db.json.zip .log/ .logs/ sitemap*.xml + +# Django static files (собранная статика, пересоздается при деплое) +public/static_collected/ + diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..dacb662 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,88 @@ +# ================================================= +# STAGE 1: Builder - Установка зависимостей +# ================================================= +FROM python:3.12-slim AS builder + +# Устанавливаем переменные окружения +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV PIP_DEFAULT_TIMEOUT=100 + +# Устанавливаем Poetry +RUN pip install --no-cache-dir --default-timeout=100 --retries 10 poetry poetry-plugin-export + +# Создаем рабочую директорию +WORKDIR /app + +# Копируем только файлы зависимостей для кэширования этого слоя +COPY pyproject.toml poetry.lock /app/ + +# Экспортируем lock-файл в requirements.txt и ставим зависимости через pip. +# Это обычно быстрее и проще для Docker, чем полноценная установка через Poetry. +RUN poetry export --format requirements.txt --without-hashes --with dev --output /tmp/requirements.txt \ + && pip install --no-cache-dir --default-timeout=100 --retries 10 -r /tmp/requirements.txt + + +# ================================================= +# STAGE 2: Final - Создание чистого и безопасного образа +# ================================================= +FROM python:3.12-slim AS stage-final + +# Устанавливаем переменные окружения +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 +ENV DJANGO_SETTINGS_MODULE=oknardia.settings + + +# Удалить: Для DEV окружения отключены создание непривилегированного пользователя +# и все связанные с ним операции chown — контейнер запускается от root, +# что избегает проблем с доступом к смонтированным томам (база, статика). +# RUN addgroup --system app && adduser --system --ingroup app app + +# Создаем рабочую директорию (где находится manage.py) +WORKDIR /home/app/oknardia + +# Копируем установленные Python-пакеты из builder-стадии +COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages + +# Удалить для dev: Копируем исходный код проекта. В DEV хозяин files не критичен (root). +# COPY --chown=1000:1000 . . +# Копируем весь проект в /home/app (корень проекта) +COPY . /home/app/ + +# Удалить для dev: Создание директорий и установка прав +# RUN mkdir -p /nginx_configs_host/nginx && chown -R 1000:1000 /nginx_configs_host +# RUN mkdir -p /home/app/web/public/staticfiles && chown -R 1000:1000 /home/app/web/public +# RUN mkdir -p /home/app/web/public/media/_error && chown -R 1000:1000 /home/app/web/public/media +# RUN mkdir -p /home/app/web/database && chown -R 1000:1000 /home/app/web/database + +# Удалить для dev: USER 1000 — для DEV запускаем от root +# USER 1000 + + +# Собираем статику +# Используем dummy ключ, так как .env файла нет на этапе сборки +# ВАЖНО: В DEV режиме collectstatic запускается в docker-compose command, а не при сборке, +# чтобы избежать ошибок с недоступными файлами. +# RUN SECRET_KEY=dummy python oknardia/manage.py collectstatic --noinput --clear + +# Открываем порт +EXPOSE 8000 + +# Проверка здоровья контейнера +# Docker будет периодически проверять, жив ли контейнер, отправляя GET запрос к главной странице. +# Параметры: +# --interval=30s - проверка каждые 30 секунд +# --timeout=3s - ожидаем ответ максимум 3 секунды +# --start-period=10s - даем контейнеру 10 секунд на запуск перед первой проверкой +# --retries=3 - объявляем контейнер unhealthy после 3 неудачных попыток +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/').read()" || exit 1 + +# Переходим в директорию с manage.py для корректного запуска Django +WORKDIR /home/app/oknardia + +# Команда запуска по умолчанию (для продакшена). +# В DEV режиме используется runserver через docker-compose.local.yml, +# который автоматически отдаёт статику и имеет auto-reload. +CMD ["python", "-m", "gunicorn", "--workers", "2", "--bind", "0.0.0.0:8000", "oknardia.wsgi:application"] diff --git a/SETUP.md b/SETUP.md index ee01922..3c9d0ae 100644 --- a/SETUP.md +++ b/SETUP.md @@ -1,330 +1,187 @@ # 🚀 SETUP.md — Первичная настройка Окнардии -**Версия**: 0.2.0 | **Дата**: 16.04.2026 +**Версия**: 0.2.0 | **Дата**: 18.05.2026 | **Docker**: ✅ Поддерживается Этот документ описывает пошаговую настройку проекта для разработки и деплоя. -## 📋 Предварительные требования +--- -- **Python**: 3.12+ -- **Django**: 6.0+ -- **MariaDB/MySQL**: 5.7+ или 8.0+ -- **Redis** (опционально, для кеширования): 6.0+ -- **Poetry** (для управления зависимостями) +## 🐳 Быстрый старт: Docker Dev Environment -### На macOS: +### 1️⃣ Запуск контейнера ```bash -# Установка зависимостей (если не установлены) -brew install mariadb-connector-c -brew install redis # опционально +cd /Users/e-serg/PRJ/2022-oknardia +docker compose -f docker-compose.local.yml up --build ``` -## 🔑 Шаг 1: Конфигурация секретов +Сайт будет доступен на **http://localhost:8060** -### 1.1 Создайте файл `my_secret.py` +### 2️⃣ Основные команды ```bash -cd oknardia/oknardia -cp my_secret.py.template my_secret.py -nano my_secret.py # отредактируйте значения +# Просмотр логов в реальном времени +docker compose -f docker-compose.local.yml logs web -f + +# Зайти в контейнер (bash) +docker compose -f docker-compose.local.yml exec web bash + +# Перезагрузить контейнер +docker compose -f docker-compose.local.yml restart web + +# Остановить контейнер +docker compose -f docker-compose.local.yml down ``` -**Что нужно заполнить:** -- IP адреса и хосты (MY_HOST_HOME2, MY_DATABASE_HOST_DEV2) -- Пароль БД (MY_DATABASE_PASSWORD_DEV) -- Email credentials (MY_EMAIL_HOST_USER_DEV, MY_EMAIL_HOST_PASSWORD_DEV) -- Пути к файлам (MY_MEDIA_ROOT_DEV2, MY_STATIC_ROOT_DEV2) -- SECRET_KEY (сгенерируйте новый!) +**✨ Особенности:** +- ✅ **Live reload** — при изменении кода автоматически перезагружается +- ✅ **Синхронизция файлов** — база, медиа, статика синхронизированы с хостом +- ✅ **Миграции автоматические** — применяются при каждом старте +- ✅ **DEBUG режим** — подробные ошибки и админка -### 1.2 (Опционально) Создайте файл `.env.local` +👁️ **Подробнее про Docker разработку** → см. раздел **"🐳 Docker Development"** ниже. -```bash -cd /path/to/project -cp .env.example .env.local -nano .env.local # отредактируйте значения +--- + +## 🐳 Docker Development + +### Структура контейнера + +``` +/home/app/ # PROJECT_ROOT +├── oknardia/ # основная папка Django +│ ├── manage.py # точка входа +│ ├── oknardia/ # конфиг Django +│ ├── web/ # приложение +│ └── templates/ # шаблоны +├── database/ # SQLite БД (синхронизирована) +├── public/ +│ ├── static/ # исходная статика +│ ├── static_collected/ # собранная статика +│ └── media/ # загруженные файлы +└── ... ``` -**Примечание**: либо используйте `my_secret.py`, либо `.env.local`, выбирайте удобный способ. +### Volume mounts (синхронизация) -## 🗄️ Шаг 2: Настройка БД - -### 2.1 Создайте БД и пользователя - -```bash -# Подключитесь к MySQL -mysql -u root -p - -# В MySQL консоли: -CREATE DATABASE django_oknardia_dev; -CREATE USER 'web'@'localhost' IDENTIFIED BY 'your-password'; -GRANT ALL PRIVILEGES ON django_oknardia_dev.* TO 'web'@'localhost'; -FLUSH PRIVILEGES; -EXIT; +```yaml +volumes: + - .:/home/app ``` -### 2.2 Выполните миграции +Это монтирует весь проект (`/Users/e-serg/PRJ/2022-oknardia`) в `/home/app` контейнера. + +**Синхронизация:** +- Изменения на хосте сразу видны в контейнере +- Разные между хостом и контейнером сохраняются на диск +- БД и медиа-файлы персистент (не теряются при рестарте контейнера) + +### Миграции в Docker ```bash -cd /path/to/project/oknardia +# Автоматические при запуске (через docker-compose command): +python manage.py migrate --noinput + +# Или вручную внутри контейнера: +docker compose -f docker-compose.local.yml exec web bash +python manage.py makemigrations python manage.py migrate + +# Или непосредственно внутри контейнера: +docker compose -f docker-compose.local.yml exec web python manage.py migrate ``` -### 2.3 Создайте суперпользователя +### Установка новых пакетов ```bash -python manage.py createsuperuser +# 1. На хосте добавьте в pyproject.toml: +poetry add some_package + +# 2. Пересоберите контейнер: +docker compose -f docker-compose.local.yml up --build + +# 3. Зависимости переустановят при старте контейнера ``` -## 📦 Шаг 3: Установка зависимостей - -### Вариант 1: Poetry (рекомендуется) +### Создание суперюзера (админ) ```bash -# Установите poetry (если не установлен) -curl -sSL https://install.python-poetry.org | python3 - - -# Установите зависимости -poetry install - -# Активируйте виртуальное окружение -poetry shell +docker compose -f docker-compose.local.yml exec web python manage.py createsuperuser ``` -### Вариант 2: pip (классический способ) +### Очистка кеша и статики ```bash -python -m venv venv -source venv/bin/activate # На Windows: venv\Scripts\activate -pip install -r requirements.txt +# Пересоберите статику: +docker compose -f docker-compose.local.yml exec web python manage.py collectstatic --clear --noinput + +# Или удалите и пересоздайте: +rm -rf ./public/static_collected/* +docker compose -f docker-compose.local.yml restart web ``` -## 🏃 Шаг 4: Запуск разработки - -### 4.1 Запустите локальный сервер +### DEBUG и логирование ```bash -cd oknardia -python manage.py runserver +# DEBUG=True включен по умолчанию +# Смотрите подробные логи: +docker compose -f docker-compose.local.yml logs web -f --tail=50 + +# Или с фильтром (только ошибки): +docker compose -f docker-compose.local.yml logs web --tail=100 | grep -i error ``` -Откройте браузер: **http://127.0.0.1:8000** +### Типичные проблемы Docker -### 4.2 Запустите задачи Celery (опционально) +**"unable to open database file"** +```bash +# Проверьте что БД существует: +ls -la ./database/oknardia.sqlite3 + +# Если нет: +cp ./database/oknadria_backup-2026-05-12.sqlite3 ./database/oknardia.sqlite3 +docker compose -f docker-compose.local.yml restart web +``` + +**"404 Not Found" для статики** +```bash +# Пересоберите статику: +docker compose -f docker-compose.local.yml exec web python manage.py collectstatic --noinput +docker compose -f docker-compose.local.yml restart web +``` + +**Контейнер падает** +```bash +# Смотрите полные логи: +docker compose -f docker-compose.local.yml logs web --tail=200 + +# Часто ошибка в settings.py или import'ах +``` + +**"Connection refused" при обращении в БД** +```bash +# Проверьте что контейнер запущен: +docker compose -f docker-compose.local.yml ps + +# Перезагрузитесь: +docker compose -f docker-compose.local.yml down && docker compose -f docker-compose.local.yml up +``` + +### Очистка Docker ```bash -celery -A oknardia worker -l info +# Удалить контейнер и образ: +docker compose -f docker-compose.local.yml down -v + +# Удалить весь Docker мусор: +docker system prune -a --volumes ``` -## 📁 Шаг 5: Создание необходимых директорий - -```bash -# Статика и медиа файлы -mkdir -p public/media -mkdir -p public/static -mkdir -p public/static/img/_flap.cfg -mkdir -p public/static/img/_miniflap.cfg - -# Логи -mkdir -p logs - -# Сгенерируйте статику -python manage.py collectstatic --noinput -``` - -## 🧪 Шаг 6: Тестирование - -```bash -# Запустите тесты -python manage.py test - -# С покрытием (если установлен coverage) -coverage run --source='.' manage.py test -coverage report -``` - -## 🔐 Шаг 7: Проверка безопасности - -### 7.1 Django встроенная проверка - -```bash -python manage.py check --deploy -``` - -### 7.2 Проверка на утечки секретов - -```bash -# Установите инструмент -pip install truffleHog - -# Проверьте репозиторий -truffleHog filesystem . --json -``` - -## ✅ Проверка готовности - -Убедитесь, что все работает: - -```bash -# 1. Статус БД -python manage.py dbshell < /dev/null && echo "✓ Database OK" - -# 2. Статус приложений Django -python manage.py check && echo "✓ Django OK" - -# 3. Статус файлов -test -d public/media && test -d public/static && echo "✓ Directories OK" - -# 4. Тесты -python manage.py test 2>&1 | tail -5 -``` - -## 🚀 Развертывание на продакшене - -### Для разных хостов - -**Masterhost VDS:** -```bash -# Установка окружения -export DJANGO_SECRET_KEY="your-production-key" -export DATABASE_PASSWORD="production-db-password" -export DATABASE_HOST="localhost" -export DEBUG="False" - -# Запуск через uWSGI + Nginx -uwsgi --ini config/oknardia.ini -``` - -**Docker (рекомендуется):** -```bash -docker build -t oknardia:latest . -docker run -d \ - -e DJANGO_SECRET_KEY="..." \ - -e DATABASE_PASSWORD="..." \ - -p 8000:8000 \ - oknardia:latest -``` - -## 🛠️ Полезные команды - -```bash -# Управление миграциями -python manage.py makemigrations # Создать миграцию -python manage.py migrate # Применить миграции -python manage.py migrate --fake-initial # Подделать первую миграцию - -# Управление данными -python manage.py shell # Интерпретатор Python с контекстом Django -python manage.py dumpdata > backup.json # Резервная копия данных -python manage.py loaddata backup.json # Восстановление данных - -# Статика и медиа -python manage.py collectstatic # Собрать статику для продакшена -python manage.py findstatic # Найти файлы статики - -# Администрирование -python manage.py createsuperuser # Создать администратора -python manage.py changepassword username # Изменить пароль - -# Очистка -python manage.py clearsessions # Удалить старые сессии -python manage.py remove_stale_contenttypes # Удалить устаревшие типы контента - -# Служебные -python manage.py check # Проверить конфигурацию -python manage.py check --deploy # Проверка для продакшена -python manage.py generate_sitemaps # Оффлайн генерация sitemap XML -python manage.py regenerate_seria_prerender --dry-run # Проверка пересборки pre-render шаблонов серий -python manage.py regenerate_seria_prerender --force # Принудительная пересборка pre-render шаблонов серий -``` - -### Пересборка pre-render шаблонов серий (рекомендуемый сценарий) - -Шаблоны для `catalog_seria_info` пересобираются оффлайн management-командой, без reload из кода Django. - -```bash -cd /path/to/project -poetry run python oknardia/manage.py regenerate_seria_prerender --force -# затем (опционально) один внешний reload процесса приложения, если это требуется вашей конфигурацией -# sudo systemctl reload gunicorn -``` - -Для выборочной пересборки используйте `--seria-id` несколько раз: - -```bash -poetry run python oknardia/manage.py regenerate_seria_prerender --seria-id 843 --seria-id 2100 --force -``` - -## 📚 Дополнительные ресурсы +--- +## Дополнительные ресурсы - [Django документация](https://docs.djangoproject.com/en/stable/) - [AGENTS.md](./AGENTS.md) — архитектура и конвенции проекта - [README.md](./README.md) — основная информация о проекте -## ❓ Решение проблем - -### Проблема: `mysqlclient` не устанавливается на macOS - -**Решение:** -```bash -brew install mariadb-connector-c -pip install mysqlclient -# или -brew unlink mariadb-connector-c # после установки -``` - -### Проблема: `ModuleNotFoundError: No module named 'oknardia'` - -**Решение:** -```bash -# Убедитесь, что находитесь в правильной директории -cd /path/to/project/oknardia -python manage.py runserver -``` - -### Проблема: `OperationalError: (2002, "Can't connect to local MySQL server")` - -**Решение:** -```bash -# Проверьте, что MySQL запущен -# macOS: -brew services start mariadb - -# Linux: -sudo systemctl start mysql - -# Проверьте credentials в my_secret.py или .env -``` - -### Проблема: миграции не применяются - -**Решение:** -```bash -# Проверьте статус миграций -python manage.py showmigrations - -# Примените все миграции -python manage.py migrate --run-syncdb - -# Если проблема в конкретной миграции -python manage.py migrate app_name 0001 --fake -python manage.py migrate app_name -``` - -## 🤝 Общие вопросы - -**Q: Где хранятся секреты?** -A: В `my_secret.py` (в .gitignore) или переменных окружения (.env) - -**Q: Как запустить проект без интернета?** -A: Установите все зависимости заранее, используйте локальное хранилище медиа - -**Q: Как работает система рейтинга?** -A: Смотрите [AGENTS.md](./AGENTS.md), раздел "Система рейтинга и ранжирования" - ---- - -**Версия документа**: 1.0 -**Последнее обновление**: 16.04.2026 -**Автор**: GitHub Copilot diff --git a/docker-compose.local.yml b/docker-compose.local.yml new file mode 100644 index 0000000..0bd8f94 --- /dev/null +++ b/docker-compose.local.yml @@ -0,0 +1,64 @@ +# ============================================================================== +# Docker Compose для РАЗРАБОТКИ (Local Development) +# Этот файл содержит настройки для локальной работы (live reload, debug). +# Запуск: docker compose -f docker-compose.local up --build +# ============================================================================== + +services: + web: + # Имя контейнера для удобства + container_name: oknardia-backend-dev + + # Сборка из текущей директории + build: . + + # Пробрасывание портов (чтобы сайт был доступен на localhost:8060) + # Занятые порты можно посмотреть через `sudo ss -tulpn` + ports: + - "8060:8000" + + # 1. КОМАНДА ЗАПУСКА (Dev режим) + # Используем Django runserver для разработки: + # - Автоматически отдаёт статику без WhiteNoise + # - Имеет встроенный auto-reload при изменении кода + # - Безопаснее и проще для dev, чем Gunicorn + # - Миграции применяются автоматически при каждом старте + command: > + sh -c "python manage.py migrate --noinput && + python manage.py collectstatic --noinput && + python manage.py runserver 0.0.0.0:8000" + + # 2. МОНТИРОВАНИЕ КОДА (Live Reload) + # Подключаем весь проект целиком в /home/app для правильного вычисления путей PROJECT_ROOT. + # При изменении кода runserver автоматически перезагружается (auto-reload). + # + # Структура монтирования: + # Host: /Users/e-serg/PRJ/2022-oknardia (.) + # Container: /home/app + # ├── oknardia/ <- исходный код (manage.py находится здесь) + # ├── database/ <- SQLite БД для синхронизации между хостом и контейнером + # ├── public/ <- статика и медиа-файлы + # └── templates/ <- Django шаблоны + volumes: + - .:/home/app + + # 3. ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ + env_file: + # файл с переменными окружения для разработки + - .env + environment: + # На всякий случай принудительно включаем DEBUG и DEBUG-уровень логов (вдруг в .env что-то не так) + # Эти настройки более приоритетные, чем в .env (если дублируются). + - DEBUG=True + - DJANGO_LOG_LEVEL=DEBUG + # В dev нам не нужно ограничивать буферизацию так строго, но не помешает. + + # 4. РЕСУРСЫ (Без лимитов для разработки) + # Удаляем секцию ограничений, чтобы локально использовать все доступные ресурсы хоста. + # deploy: + # resources: + # limits: + # cpus: ... + # memory: ... + # mem_limit: ... + diff --git a/oknardia/oknardia/settings.py b/oknardia/oknardia/settings.py index 6125e9f..26403b8 100644 --- a/oknardia/oknardia/settings.py +++ b/oknardia/oknardia/settings.py @@ -34,6 +34,8 @@ STATIC_SOURCE_ROOT = PUBLIC_ROOT / 'static' env = environ.Env() environ.Env.read_env(str(PROJECT_ROOT / '.env')) +CSRF_TRUSTED_ORIGINS = env.list('DJANGO_CSRF_TRUSTED_ORIGINS', default=[]) + # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ @@ -139,7 +141,6 @@ DATETIME_FORMAT = 'Y-m-d H:i:s' STATIC_URL = '/static/' MEDIA_URL = '/media/' - MEDIA_ROOT = str(PUBLIC_ROOT / 'media') # STATIC_ROOT отделен от исходной статики, чтобы избежать staticfiles.E002. STATIC_ROOT = str(PUBLIC_ROOT / 'static_collected') @@ -157,13 +158,30 @@ STATICFILES_DIRS = [ str(STATIC_SOURCE_ROOT) ] if STATIC_SOURCE_ROOT.is_dir() else [] +# Django 5 требует явное описание хранилищ. +# `default` нужен для загружаемых файлов (FileField, ImageField, filer и подобное) и смотрит в `MEDIA_ROOT`. +# `staticfiles` остаётся отдельно: в dev используется обычная статика Django, в prod — WhiteNoise. +STORAGES = { + 'default': { + 'BACKEND': 'django.core.files.storage.FileSystemStorage', + 'OPTIONS': { + 'location': MEDIA_ROOT, + }, + }, + 'staticfiles': { + 'BACKEND': 'django.contrib.staticfiles.storage.StaticFilesStorage', + }, +} + # Путь к каталогу static для генерации кэш-файлов и служебных JS. STATIC_BASE_PATH = str(STATIC_SOURCE_ROOT) +# Определяем движок БД из переменной окружения (по умолчанию SQLite) database_engine = env('DATABASE_ENGINE', default='django.db.backends.sqlite3') + if database_engine == 'django.db.backends.sqlite3': # Для SQLite принимаем только имя файла из env и кладем БД в PROJECT_ROOT/database. - sqlite_db_filename = Path(env('DATABASE_NAME', default='oknadria.sqlite3')).name + sqlite_db_filename = Path(env('DATABASE_NAME', default='oknardia.sqlite3')).name sqlite_db_path = PROJECT_ROOT / 'database' / sqlite_db_filename DATABASES = { 'default': { @@ -172,6 +190,7 @@ if database_engine == 'django.db.backends.sqlite3': } } else: + # База не SQLite (mariaDB, например): читаем все параметры подключения из env. DATABASES = { 'default': { 'ENGINE': database_engine, @@ -314,3 +333,38 @@ CATALOG_SORTER_MAGIC_NUMBER_TIZER = 1 MAX_LEN_RING_LOG_BUFFER = 250 # МАКСИМАЛЬНЫЙ РАЗМЕР КОЛЬЦЕВОГО БУФЕРА YANDEX_MAPS_API_KEY = env('YANDEX_MAPS_API_KEY', default='') + +# ============================================================================ +# Конфигурация в зависимости от режима разработки (DEBUG) vs. production +# ============================================================================ + +if DEBUG: + # В dev: стандартная отдача статики Django (без WhiteNoise/кэширования). + # Медиа-файлы отдаются через Django. + pass + +else: + # В prod: WhiteNoise + CompressedManifestStaticFilesStorage для оптимизации. + # Статика собирается с хешем в имени и кэшируется. + + # 1. Добавляем WhiteNoise в начало MIDDLEWARE (после SecurityMiddleware) для отдачи статики + MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware') + + # 2. Переводим staticfiles на WhiteNoise со сжатием + STORAGES['staticfiles'] = { + 'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage', # noqa: F821 + } + + # 3. WhiteNoise конфиг: обслуживание корневых файлов из public/ (robots.txt, favicon.*, sitemap.xml и т.д.) + # Параметр WHITENOISE_LOCATION указывает WhiteNoise, где искать файлы помимо STATIC_ROOT + WHITENOISE_LOCATION = str(PUBLIC_ROOT) + + # 4. MIME-типы для шрифтов (иначе браузер может не загрузить) + WHITENOISE_MIMETYPES = { + '.woff': 'font/woff', + '.woff2': 'font/woff2', + } + + # 5. Кэширование неизменяемых файлов (с хешем в имени) на 1 год в браузере + WHITENOISE_IMMUTABLE_FILE_TEST = lambda path: 'CACHE' in path + diff --git a/poetry.lock b/poetry.lock index 2d67210..68f0694 100644 --- a/poetry.lock +++ b/poetry.lock @@ -214,6 +214,27 @@ develop = ["coverage[toml] (>=5.0a4)", "furo (>=2021.8.17b43,<2021.9.dev0)", "py docs = ["furo (>=2021.8.17b43,<2021.9.dev0)", "sphinx (>=3.5.0)", "sphinx-notfound-page"] testing = ["coverage[toml] (>=5.0a4)", "pytest (>=4.6.11)"] +[[package]] +name = "gunicorn" +version = "23.0.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, + {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +eventlet = ["eventlet (>=0.24.1,!=0.36.0)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"] +tornado = ["tornado (>=0.2)"] + [[package]] name = "idna" version = "3.11" @@ -228,6 +249,17 @@ files = [ [package.extras] all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +[[package]] +name = "packaging" +version = "26.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, + {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, +] + [[package]] name = "pillow" version = "11.3.0" @@ -507,7 +539,21 @@ h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["backports-zstd (>=1.0.0)"] +[[package]] +name = "whitenoise" +version = "6.12.0" +description = "Radically simplified static file serving for WSGI applications" +optional = false +python-versions = ">=3.10" +files = [ + {file = "whitenoise-6.12.0-py3-none-any.whl", hash = "sha256:fc5e8c572e33ebf24795b47b6a7da8da3c00cff2349f5b04c02f28d0cc5a3cc2"}, + {file = "whitenoise-6.12.0.tar.gz", hash = "sha256:f723ebb76a112e98816ff80fcea0a6c9b8ecde835f8ddda25df7a30a3c2db6ad"}, +] + +[package.extras] +brotli = ["brotli"] + [metadata] lock-version = "2.0" python-versions = ">=3.12,<3.13" -content-hash = "5fdba0321d441277f8b911d178c048c672533761e93443473897572f4ed16ebf" +content-hash = "151e463bb47b6a3e0307c77b6032da97f414908c2775be9ea3c6ccfdee19e1a5" diff --git a/pyproject.toml b/pyproject.toml index 9064618..41a032e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,8 @@ Pillow = "^11.2.1" requests = "^2.32.3" pytils = "^0.4.4" rjsmin = "^1.2.0" +gunicorn = "^23.0.0" +whitenoise = "^6.8.2" [tool.poetry.group.dev.dependencies] django-debug-toolbar = "^6.3"