# Руководство по новым моделям контента ## Обзор В проект добавлены новые модели для управления контентом через админ-панель Django: ### 1. **BlogPost** (Расширенная модель блога) **Местоположение**: `smartsoltech/web/models.py` **Админ-панель**: `/admin/web/blogpost/` #### Поля: - `title` - Заголовок поста - `slug` - URL-адрес (автоматически генерируется из заголовка) - `author` - Автор поста (связь с User) - `excerpt` - Краткое описание (макс. 400 символов) - `content` - Полное содержимое - `image` - Изображение для поста - `status` - Статус: "Черновик" или "Опубликовано" - `published_date` - Дата публикации - `views` - Количество просмотров (автоматически увеличивается) #### Использование: ```python # Создание нового поста post = BlogPost.objects.create( title="Новая статья", content="Содержимое статьи...", status=BlogPost.PUBLISHED, author=request.user ) ``` #### URL-адреса: - Список постов: `/blog/` - Детальная страница: `/blog//` --- ### 2. **NewsArticle** (Новости) **Местоположение**: `smartsoltech/web/models.py` **Админ-панель**: `/admin/web/newsarticle/` #### Поля: - `title` - Заголовок новости - `slug` - URL-адрес (автогенерация) - `excerpt` - Краткое описание (макс. 300 символов) - `content` - Полный текст - `image` - Изображение - `is_published` - Опубликовано (True/False) - `published_date` - Дата публикации #### Использование: ```python # Получение опубликованных новостей news = NewsArticle.objects.filter(is_published=True).order_by('-published_date') ``` #### URL-адреса: - Список новостей: `/news/` - Детальная страница: `/news//` --- ### 3. **PortfolioItem** (Портфолио) **Местоположение**: `smartsoltech/web/models.py` **Админ-панель**: `/admin/web/portfolioitem/` #### Поля: - `title` - Название проекта - `slug` - URL-адрес - `description` - Описание проекта - `client_name` - Имя клиента - `completion_date` - Дата завершения - `image` - Изображение проекта - `featured` - Избранное (для выделения на главной) - `category` - Категория (связь с Category) - `is_active` - Активно #### Использование: ```python # Избранные проекты featured = PortfolioItem.objects.filter(featured=True, is_active=True) # Фильтрация по категории items = PortfolioItem.objects.filter(category_id=1, is_active=True) ``` #### URL-адреса: - Список портфолио: `/portfolio/` - С фильтром: `/portfolio/?category=` - Детальная страница: `/portfolio//` --- ### 4. **CareerVacancy** (Вакансии) **Местоположение**: `smartsoltech/web/models.py` **Админ-панель**: `/admin/web/careervacancy/` #### Поля: - `title` - Название должности - `slug` - URL-адрес - `location` - Местоположение - `employment_type` - Тип занятости: - `FT` - Полная занятость - `PT` - Частичная занятость - `CT` - Контракт - `IN` - Стажировка - `responsibilities` - Обязанности - `requirements` - Требования - `desirable` - Будет плюсом - `salary_min` / `salary_max` - Диапазон зарплаты - `is_active` - Активна #### Использование: ```python # Активные вакансии vacancies = CareerVacancy.objects.filter(is_active=True).order_by('-posted_at') # Только стажировки internships = CareerVacancy.objects.filter( employment_type=CareerVacancy.INTERN, is_active=True ) ``` #### URL-адреса: - Список вакансий: `/career/` - Детальная страница: `/career//` --- ### 5. **PrivacyPolicy** (Политика конфиденциальности) **Местоположение**: `smartsoltech/web/models.py` **Админ-панель**: `/admin/web/privacypolicy/` #### Поля: - `version` - Версия документа - `content` - Текст политики - `effective_date` - Дата вступления в силу - `is_active` - Активна (только одна может быть активной) #### Особенности: - При создании новой активной политики, все остальные автоматически деактивируются - Показывается только активная версия #### URL-адрес: - `/privacy/` --- ### 6. **TermsOfUse** (Условия использования) **Местоположение**: `smartsoltech/web/models.py` **Админ-панель**: `/admin/web/termsofuse/` #### Поля: - `version` - Версия документа - `content` - Текст условий - `effective_date` - Дата вступления в силу - `is_active` - Активно (singleton-подход) #### Особенности: - Аналогично PrivacyPolicy - только одна активная версия #### URL-адрес: - `/terms/` --- ## Автоматическая генерация Slug Все модели с полем `slug` автоматически генерируют его из заголовка при сохранении: ```python # В админ-панели достаточно заполнить title post = BlogPost(title="Новая статья о Django") post.save() # slug автоматически станет: "novaya-statya-o-django" # При дублировании добавляется счетчик post2 = BlogPost(title="Новая статья о Django") post2.save() # slug станет: "novaya-statya-o-django-1" ``` Вы также можете задать slug вручную в админ-панели через prepopulated fields. --- ## Работа с изображениями Все модели поддерживают загрузку изображений: - **BlogPost**: `static/img/blog/` - **NewsArticle**: `static/img/news/` - **PortfolioItem**: `static/img/portfolio/` - **TeamMember**: `static/img/team/` В шаблонах автоматически используется fallback (иконка-заглушка), если изображение не загружено. --- ## Формат Telegram Username ### В модели TeamMember **Поле**: `telegram` **Формат**: Только username без символа `@` #### Правильно ✅ ``` trevor1985 smartsoltech_bot ``` #### Неправильно ❌ ``` @trevor1985 https://t.me/trevor1985 ``` ### Использование в шаблонах В шаблонах ссылки формируются автоматически: ```django {% if member.telegram %} {% endif %} ``` ### Различия между схемами 1. **https://t.me/username** - Открывается в браузере - Работает на любых устройствах - Если приложение установлено, браузер может предложить открыть в нем 2. **tg://resolve?domain=username** - Напрямую открывает приложение Telegram - Требует установленного приложения - Может не работать в некоторых браузерах **Рекомендация**: Используйте `https://t.me/` для публичных страниц. --- ## Быстрый старт ### 1. Создание контента через админ-панель 1. Войдите в админ-панель: `http://localhost:8000/admin/` 2. Найдите нужный раздел (BlogPost, NewsArticle, и т.д.) 3. Нажмите "Добавить" 4. Заполните поля (slug создастся автоматически) 5. Сохраните ### 2. Проверка на фронтенде - Блог: `http://localhost:8000/blog/` - Новости: `http://localhost:8000/news/` - Портфолио: `http://localhost:8000/portfolio/` - Вакансии: `http://localhost:8000/career/` - Политика: `http://localhost:8000/privacy/` - Условия: `http://localhost:8000/terms/` ### 3. Добавление ссылок в меню Обновите шаблоны header/footer для добавления ссылок на новые разделы: ```django ``` --- ## Примеры запросов в views ```python from .models import BlogPost, NewsArticle, PortfolioItem, CareerVacancy # Последние 3 поста блога recent_posts = BlogPost.objects.filter( status=BlogPost.PUBLISHED ).order_by('-published_date')[:3] # Новости за последнюю неделю from django.utils import timezone from datetime import timedelta week_ago = timezone.now() - timedelta(days=7) recent_news = NewsArticle.objects.filter( is_published=True, published_date__gte=week_ago ) # Избранное портфолио для главной featured_portfolio = PortfolioItem.objects.filter( featured=True, is_active=True )[:6] # Количество открытых вакансий vacancy_count = CareerVacancy.objects.filter(is_active=True).count() ``` --- ## Обслуживание ### Миграции После изменения моделей всегда запускайте: ```bash docker exec django_app python smartsoltech/manage.py makemigrations web docker exec django_app python smartsoltech/manage.py migrate web ``` ### Резервное копирование Регулярно создавайте резервные копии БД: ```bash docker exec postgres_db pg_dump -U $POSTGRES_USER $POSTGRES_DB > backup_$(date +%Y%m%d).sql ``` --- ## Поддержка При возникновении вопросов или проблем: 1. Проверьте логи Django: `docker logs django_app` 2. Проверьте миграции: `docker exec django_app python smartsoltech/manage.py showmigrations` 3. Убедитесь, что контейнеры запущены: `docker ps` --- **Дата создания**: 24 ноября 2025 **Версия документа**: 1.0