<<<<<<< HEAD [S1] Создать GitHub-репозиторий chatty. Настроить базовую структуру: chatty/, users/, templates/, .gitignore, README.md.
Acceptance Criteria:
Django-проект и базовая структура каталогов добавлены. .gitignore исключает временные и служебные файлы. README.md содержит название проекта и инструкции по запуску.
mkdir Chatty_green cd Chatty_green
python -m venv venv
venv\Scripts\activate
source venv/bin/activate
pip install django
django-admin startproject chatty .
python manage.py runserver
открываем в браузере http://127.0.0.1:8000 и видим приветственную страницу Django.
The install worked successfully! Congratulations!
View release notes for Django 5.2
You are seeing this page because DEBUG=True is in your settings file and you have not configured any URLs.
Django"...
Обновленная и упрощенная схема проекта
Chatty_green/
├── chatty/ # Django-проект
│ ├── __init__.py
│ ├── settings.py # Настройки (будет разделение на base/dev/prod)
│ ├── urls.py # Корневой роутинг
│ ├── asgi.py
│ └── wsgi.py
│
├── core/ # Общие компоненты
│ ├── templates/ # Базовые шаблоны (base.html, 404.html и др.)
│ ├── static/ # Общие CSS, JS, изображения
│ ├── utils.py # Вспомогательные функции
│ └── views.py # Статические страницы (о проекте, ошибки)
│
├── users/ # Пользователи
│ ├── models.py # Модель профиля
│ ├── forms.py # Регистрация, логин, редактирование
│ ├── views.py # Регистрация, логин, профиль
│ ├── urls.py
│ ├── templates/users/ # Шаблоны профиля, формы и т.д.
│ └── admin.py
│
├── posts/ # Посты и комментарии
│ ├── models.py # Post, Comment, Like
│ ├── forms.py # Форма создания поста, комментария
│ ├── views.py # CRUD-представления
│ ├── urls.py
│ ├── templates/posts/ # Шаблоны для постов и ленты
│ └── admin.py
│
├── subscriptions/ # Подписки
│ ├── models.py # Subscription
│ ├── views.py # Подписка/отписка
│ ├── urls.py
│ └── templates/subscriptions/ # Шаблоны подписок
│
├── templates/ # Глобальные шаблоны (если не в app)
│ └── base.html
│
├── manage.py
├── venv/
├── requirements.txt # Зависимости
├── .env # Переменные окружения
└── docker/ # Docker конфигурации
├── Dockerfile
├── docker-compose.yml
└── nginx/
└── default.conf
users.UserProfile связан с posts.Post и subscriptions.Subscription posts.Post связан с users, subscriptions, posts.Comment, posts.Like subscriptions.Subscription — связь "пользователь → подписки"
В корне проекта Chatty_green (где находится manage.py) выполняем:
python manage.py startapp users
python manage.py startapp posts
python manage.py startapp subscriptions
python manage.py startapp core
INSTALLED_APPS = [
# Системные
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Наши приложения которые мы добавили
'users',
'posts',
'subscriptions',
'core',
]
- Корневая папка проекта Chatty_green/
Содержит:
venv/ — виртуальное окружение Python
manage.py — точка входа в Django
requirements.txt — список зависимостей
.env — переменные окружения (секреты, БД, отладка)
docker/ — контейнеризация (Dockerfile, nginx, gunicorn)
chatty/ — Django-конфигурация проекта
- Папка проекта chatty/
Содержит:
settings.py — конфигурация проекта (будет разбита на base, dev, prod)
urls.py — глобальные маршруты
wsgi.py, asgi.py — интерфейсы для запуска сервера
__init__.py — инициализация Python-пакета
- Приложение users/ — Пользователи
Назначение:
Регистрация, вход, выход, редактирование профиля
Хранение пользовательских данных (аватар, биография)
Расширение модели пользователя (OneToOne)
Содержит:
models.py — UserProfile (OneToOne с User)
forms.py — формы регистрации, входа, редактирования
views.py — логика отображения и обработки профиля
urls.py — маршруты пользователей
templates/users/ — шаблоны регистрации, входа, профиля
admin.py — настройка отображения профилей в админке
- Приложение posts/ — Публикации
Назначение:
CRUD-посты с изображениями
Комментарии и лайки
Содержит:
models.py: Post, Comment, Like
forms.py: форма создания поста, комментария
views.py: отображение ленты, деталки, добавление/редактирование постов
urls.py: маршруты постов и комментариев
templates/posts/: шаблоны ленты, комментариев, публикаций
admin.py: управление постами в админке
- Приложение subscriptions/ — Подписки
Назначение:
Система подписок между пользователями
Возможность следить за постами подписанных людей
Содержит:
models.py: Subscription (ManyToMany через модель)
views.py: подписка/отписка, список подписчиков
urls.py
templates/subscriptions/: шаблоны отображения подписок
admin.py: отображение подписок в админке
- Приложение core/ — Общие компоненты
Назначение:
Базовые шаблоны, общие утилиты, обработка ошибок, страницы "О проекте", 404/500 и т.д.
Содержит:
views.py: страницы вроде "О нас", 404/500
utils.py: вспомогательные функции (например, сокращение текста, генерация имени файла)
templates/core/: base.html, 404.html, 500.html, about.html
static/: общие CSS/JS (например, Bootstrap, кастомные стили)
- Связи между моделями
User ←→ UserProfile (1 к 1)
UserProfile ←→ Post (1 ко многим)
Post ←→ Comment, Like (1 ко многим)
User ←→ Subscription ←→ User (модель подписки через ManyToMany)
Post.image — изображение с обработкой загрузки
- Навигация/маршруты (urls)
/ — Главная лента постов
/users/register/, /users/login/, /users/logout/, /users/<username>/ — вход, выход, регистрация, профиль
/posts/create/, /posts/<id>/edit/, /posts/<id>/delete/ — управление постами
/posts/<id>/ — детальный просмотр поста
/subscriptions/, /subscribe/<id>/ — управление подписками
/about/ — информация о проекте
/admin/ — панель администратора
- Технологический стек
Backend: Django 4+
Frontend: HTML, Bootstrap (возможно Tailwind)
БД: SQLite на dev, PostgreSQL на prod
Auth: Стандартная + расширение профиля
DevOps: Docker, docker-compose, Nginx, Gunicorn
Media: Django media storage для аватарок и изображений постов
Создаем базовую модель users/models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from PIL import Image
import os
def avatar_upload_path(instance, filename):
return f'avatars/user_{instance.user.id}/{filename}'
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')
bio = models.TextField(max_length=500, blank=True, verbose_name='О себе')
avatar = models.ImageField(upload_to=avatar_upload_path, default='avatars/default.jpg', verbose_name='Аватар')
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return f'Профиль пользователя {self.user.username}'
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
# Уменьшаем размер аватара при сохранении
if self.avatar:
img_path = self.avatar.path
img = Image.open(img_path)
if img.height > 300 or img.width > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(img_path)
Создадим сигнал, чтобы при создании User автоматически создавался UserProfile.
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User
from .models import UserProfile
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
def ready(self):
import users.signals
python manage.py makemigrations users
python manage.py migrate
from django.contrib import admin
from .models import UserProfile
@admin.register(UserProfile)
class UserProfileAdmin(admin.ModelAdmin):
list_display = ('user', 'created_at')
Cоздадаем:
Главный маршрут (chatty/urls.py)
Подключение приложения users
Базовый шаблон с навигацией (layout)
# Шаг 2. Связь моделей — в apps.py и сигналах
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('users/', include('users.urls')), # маршруты пользователей
]
# Подключение медиафайлов (аватары)
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
from django.urls import path
from . import views
from django.contrib.auth import views as auth_views
urlpatterns = [
path('register/', views.register, name='register'),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
path('profile/', views.profile, name='profile'),
]
Структура папок шаблонов:
chatty_green/
│
├── templates/
│ ├── users/
│ │ ├── login.html
│ │ ├── logout.html
│ │ ├── register.html
│ │ └── profile.html
│ └── base.html
Шаблон templates/base.html (OlgaFaruk)
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}Chatty{% endblock %}</title>
<!-- Подключение Bootstrap через CDN -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<!-- Дополнительные стили -->
<style>
body {
font-family: Arial, sans-serif;
padding-top: 56px; /* Добавьте если используете fixed navbar */
}
</style>
</head>
<body>
<!-- Включение навигационной панели (ТОЛЬКО ЗДЕСЬ) -->
{% include "include/navbar.html" %}
<main class="container mt-4">
{% block content %}
<!-- Здесь будет контент страниц -->
{% endblock %}
</main>
<!-- Включение футера -->
{% include "include/footer.html" %}
</body>
</html>
# users/urls.py
templates/users/register.html
{% extends "base.html" %}
{% block content %}
<h2>Регистрация</h2>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Зарегистрироваться</button>
</form>
{% endblock %}
Финальные настройки в settings.py
settings.py
... другие настройки ...
#Authentication settings
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
]
AUTH_USER_MODEL = 'your_app.CustomUser' # <-- вот здесь
STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles' # для collectstatic
STATICFILES_DIRS = [BASE_DIR / 'static'] # дополнительные папки со статикой
... остальные настройки ...
P.S. заменили ALLOWED_HOSTS = [] на ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'web'] # 'web' - имя сервиса в docker-compose
Улучшенная версия:
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings
from .models import UserProfile
User = settings.AUTH_USER_MODEL # Используем кастомную модель пользователя
@receiver(post_save, sender=User)
def create_or_update_user_profile(sender, instance, created, **kwargs):
"""
Создает или обновляет профиль пользователя при сохранении модели User.
"""
if created:
UserProfile.objects.get_or_create(user=instance)
else:
# Безопасное обновление без рекурсии
if hasattr(instance, 'profile'):
instance.profile.save()
Добавлена строка в class UsersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
- Использует кастомную модель пользователя
- Избегает рекурсии
- Обрабатывает случаи, когда профиль уже существует
- Более безопасна и соответствует современным стандартам Django
Проект представляет собой платформу для ведения блогов с возможностью создания, редактирования и удаления постов. Для управления постами используется функциональность с подтверждением действий, что улучшает взаимодействие с пользователями.
- Пользователь может создать новый пост.
- При создании поста автоматически сохраняется автор (пользователь, который авторизован в системе).
- При успешном создании поста пользователь перенаправляется на страницу подробного просмотра этого поста.
- Пользователь может редактировать свои посты, изменяя заголовок и текст.
- В случае успешного редактирования, пост сохраняется, и пользователь возвращается на страницу детального просмотра.
- При удалении поста пользователю показывается страница с подтверждением удаления.
- После подтверждения пост удаляется, и пользователь перенаправляется на список постов.
В модели `Post` определены следующие поля:
- `author`: связь с пользователем (через внешний ключ `ForeignKey`).
- `title`: заголовок поста (обязательное поле).
- `text`: текст поста (обязательное поле).
- `image`: изображение, связанное с постом (необязательное поле).
- `publication_date`: дата публикации (автоматически устанавливается при создании поста).
- `slug`: уникальный идентификатор для поста, генерируемый из заголовка.
Метод save генерирует slug, если он не был установлен, и сохраняет пост в базе данных.
Метод get_absolute_url возвращает ссылку на подробную страницу поста.
В файле `urls.py` определены маршруты для работы с постами:
- `/posts/`: список всех постов (`PostListView`).
- `/posts/create/`: форма для создания нового поста (`PostCreateView`).
- `/posts/<slug:slug>/`: страница с деталями поста (`PostDetailView`).
- `/posts/<slug:slug>/edit/`: форма для редактирования поста (`PostUpdateView`).
- `/posts/<slug:slug>/delete/`: страница с подтверждением удаления поста (`PostDeleteView`).
Используются классы представлений для обработки запросов:
PostCreateView: обрабатывает создание поста, сохраняет автора и перенаправляет на страницу поста.PostUpdateView: обрабатывает редактирование поста.PostDeleteView: позволяет удалить пост с подтверждением.
Для защиты от неавторизованных пользователей используется LoginRequiredMixin.
Файл Dockerfile используется для создания контейнера с приложением:
- Используется официальный образ Python 3.12.
- Устанавливаются зависимости из
requirements.txt. - Копируются файлы проекта в контейнер.
- Устанавливается рабочая директория и запуск проекта через
CMD.
В файле docker-compose.yml настроены два сервиса:
- web: для запуска приложения Django.
- db: для запуска базы данных (PostgreSQL).
version: "3.8"
services:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/app
ports:
- "8000:8000"
depends_on:
- db
db:
image: postgres:13
environment:
POSTGRES_DB: chatty_db
POSTGRES_USER: user
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:В файле entrypoint.sh выполняются следующие действия при запуске контейнера:
- Выполняются миграции базы данных.
- Собираются статические файлы.
- Запускается сервер Django.
#!/bin/sh
python manage.py migrate
python manage.py collectstatic --noinput
exec "$@"
Для работы с базой данных используется PostgreSQL. Конфигурация для подключения настроена в settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('PG_NAME'),
'USER': os.getenv('PG_USER'),
'PASSWORD': os.getenv('PG_PASSWORD'),
'HOST': os.getenv('PG_HOST'),
'PORT': os.getenv('PG_PORT'),
}
}
Статические файлы и медиа-файлы для загрузки изображений постов обрабатываются через Django:
-
Статические файлы собираются с помощью команды collectstatic.
-
Медиа-файлы (например, изображения для постов) хранятся в папке media/.
- Запуск контейнеров:
- docker-compose down /остановка контейнера/
- docker-compose build /запуск сборки контейнера/
- docker-compose up -d /запуск контенера/
- docker restart web /перезапуск контенера - web/
или все вместе
- docker-compose down && docker-compose build && docker-compose up -d
- Выполнение миграций:
docker exec -it web python manage.py makemigrations
docker exec -it web python manage.py migrate
В проекте реализована базовая функциональность для создания, редактирования и удаления постов. Все действия требуют подтверждения и работы с пользователем. Проект настроен с использованием Docker для удобства развертывания и миграций.
Проект использует Django для построения веб-приложения, PostgreSQL для хранения данных и Docker для контейнеризации.
$ docker-compose exec db pg_dump -U postgres -d postgres --data-only > data.sql
- Альтернативный вариант-создание скрипта:
echo "🚀 Запуск автоматического развертывания Chatty..."
# ✅ Остановка контейнеров
echo "🛑 Остановка контейнеров..."
docker-compose down
# ✅ Перезапуск с пересборкой
echo "🔄 Запуск контейнеров..."
docker-compose up --build -d
# ✅ Ожидание запуска (даем контейнерам время стартовать)
echo "⏳ Ожидание 10 секунд..."
sleep 10
# ✅ Применение миграций
echo "⚙️ Выполнение миграций..."
docker exec -it web python manage.py migrate
# ✅ Импорт данных, если `backup.json` существует
if [ -f "backup.json" ]; then
echo "📥 Импорт данных из backup.json..."
docker exec -it web python manage.py loaddata backup.json
else
echo "⚠️ Файл backup.json отсутствует! Пропускаем импорт..."
fi
# ✅ Настройка прав на медиафайлы
echo "🛠️ Настройка доступа к изображениям..."
docker exec -it web chmod -R 777 /app/media/
# ✅ Проверка количества статей
echo "📂 Проверка базы данных..."
docker exec -it web python manage.py shell <<EOF
from posts.models import Post
print(f"📝 Всего статей: {Post.objects.count()}")
EOF
echo "✅ Развертывание завершено! Проверьте проект 🚀"
Сохранение файла deploy.sh в корне проекта и предоставление права на исполнение
chmod +x deploy.sh
Запуск
./deploy.sh
Созданы тесты для тестирования создания и редактирования постов (post_create, post_update ) и Интеграционные тесты: регистрация → пост → комментарий в одном файле тестируется цепочка действий: регистрация пользователя, создание поста, добавление комментария, отображение поста. Тесты добавлен в docker-compose как service tests. После обновления проекта нужно вначале сделать docker-compose build а затем запустить тесты docker-compose run --rm tests. После прохождения тестов контейнер с тестами удалится и можно работать с проектом.
'Изменил содержание папки media/upload_files, удалил все видео файлы'
Проверка на обновление базовой ветки merge_dev
Данный проект является копией оригинального проекта AFZhuk63/chatty_green,
разработанного Anatoliy Zhuk. Нарушены авторские права, удалены коммиты и метаданные других участников.
Проект защищён лицензией: LICENSE
Требуется восстановление истории и указание авторства. Подробности — см. публичную претензию.