prod
This commit is contained in:
355
CONTENT_MODELS_GUIDE.md
Normal file
355
CONTENT_MODELS_GUIDE.md
Normal file
@@ -0,0 +1,355 @@
|
||||
# Руководство по новым моделям контента
|
||||
|
||||
## Обзор
|
||||
|
||||
В проект добавлены новые модели для управления контентом через админ-панель 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
|
||||
Reference in New Issue
Block a user