Files
smartsoltech_site/CONTENT_MODELS_GUIDE.md
2025-11-24 11:31:29 +09:00

356 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Руководство по новым моделям контента
## Обзор
В проект добавлены новые модели для управления контентом через админ-панель 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/<slug>/`
---
### 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/<slug>/`
---
### 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=<id>`
- Детальная страница: `/portfolio/<slug>/`
---
### 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/<slug>/`
---
### 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 %}
<!-- Веб-ссылка (открывается в браузере) -->
<a href="https://t.me/{{ member.telegram }}" target="_blank" rel="noopener">
<i class="fab fa-telegram"></i>
</a>
<!-- Или схема tg:// (открывает приложение) -->
<a href="tg://resolve?domain={{ member.telegram }}">
<i class="fab fa-telegram"></i>
</a>
{% 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
<nav>
<a href="{% url 'blog_list' %}">Блог</a>
<a href="{% url 'news_list' %}">Новости</a>
<a href="{% url 'portfolio_list' %}">Портфолио</a>
<a href="{% url 'career_list' %}">Вакансии</a>
</nav>
<footer>
<a href="{% url 'privacy_policy' %}">Политика конфиденциальности</a>
<a href="{% url 'terms_of_use' %}">Условия использования</a>
</footer>
```
---
## Примеры запросов в 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