12 KiB
Руководство по новым моделям контента
Обзор
В проект добавлены новые модели для управления контентом через админ-панель Django:
1. BlogPost (Расширенная модель блога)
Местоположение: smartsoltech/web/models.py
Админ-панель: /admin/web/blogpost/
Поля:
title- Заголовок постаslug- URL-адрес (автоматически генерируется из заголовка)author- Автор поста (связь с User)excerpt- Краткое описание (макс. 400 символов)content- Полное содержимоеimage- Изображение для постаstatus- Статус: "Черновик" или "Опубликовано"published_date- Дата публикацииviews- Количество просмотров (автоматически увеличивается)
Использование:
# Создание нового поста
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- Дата публикации
Использование:
# Получение опубликованных новостей
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- Активно
Использование:
# Избранные проекты
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- Активна
Использование:
# Активные вакансии
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 автоматически генерируют его из заголовка при сохранении:
# В админ-панели достаточно заполнить 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
Использование в шаблонах
В шаблонах ссылки формируются автоматически:
{% 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 %}
Различия между схемами
-
- Открывается в браузере
- Работает на любых устройствах
- Если приложение установлено, браузер может предложить открыть в нем
-
tg://resolve?domain=username
- Напрямую открывает приложение Telegram
- Требует установленного приложения
- Может не работать в некоторых браузерах
Рекомендация: Используйте https://t.me/ для публичных страниц.
Быстрый старт
1. Создание контента через админ-панель
- Войдите в админ-панель:
http://localhost:8000/admin/ - Найдите нужный раздел (BlogPost, NewsArticle, и т.д.)
- Нажмите "Добавить"
- Заполните поля (slug создастся автоматически)
- Сохраните
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 для добавления ссылок на новые разделы:
<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
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()
Обслуживание
Миграции
После изменения моделей всегда запускайте:
docker exec django_app python smartsoltech/manage.py makemigrations web
docker exec django_app python smartsoltech/manage.py migrate web
Резервное копирование
Регулярно создавайте резервные копии БД:
docker exec postgres_db pg_dump -U $POSTGRES_USER $POSTGRES_DB > backup_$(date +%Y%m%d).sql
Поддержка
При возникновении вопросов или проблем:
- Проверьте логи Django:
docker logs django_app - Проверьте миграции:
docker exec django_app python smartsoltech/manage.py showmigrations - Убедитесь, что контейнеры запущены:
docker ps
Дата создания: 24 ноября 2025
Версия документа: 1.0