Социальная сеть для людей, которые устали смотреть одинаковые рекомендации и хотят видеть принципиально новый контент в своей ленте
Создана за 48 часов на хакатоне командой из 4 человек.
| Роль | Стек |
|---|---|
| Backend | Python, Django REST Framework, JWT |
| Frontend | JavaScript / React |
| Frontend | JavaScript / React |
| Design | Figma |
Этот README описывает backend-часть проекта, разработанную мной.
«Всё Сложно» — полноценная социальная сеть с лентой, сообществами, личными сообщениями и системой дружбы. Дружба определяется автоматически через взаимную подписку: если ты подписался на человека, а он — на тебя, вы друзья. Всё как в жизни.
- Регистрация и авторизация через JWT-токены
- Профили пользователей с аватаркой, статусом и датой рождения
- Публикация постов — в личную ленту или в сообщество
- Умная лента: посты друзей + рекомендации по тематикам + случайные посты
- Лайки на постах (toggle: поставил/убрал)
- Комментарии к постам
- Сообщества с тематиками и системой предмодерации
- Личные сообщения (диалоги, inbox, пометка "прочитано")
- Уведомления (новый подписчик, появление взаимной дружбы)
- Кастомные права доступа (только автор может редактировать свой пост/профиль)
- Management-команда для наполнения БД тестовыми данными
| Технология | Назначение |
|---|---|
| Python 3.12 | Основной язык |
| Django 5.2 | Web-фреймворк |
| Django REST Framework | Построение REST API |
| Djoser | Регистрация, авторизация, управление пользователями |
| SimpleJWT | JWT-токены (Access 1 день / Refresh 7 дней) |
| django-cors-headers | CORS для работы с фронтендом |
| django-filter | Фильтрация queryset'ов |
| Faker | Генерация тестовых данных |
| SQLite | База данных (для разработки) |
backend/
├── api/
│ ├── models.py # Все модели: Profile, Post, Community, Like, Message...
│ ├── serializers.py # Сериализаторы + бизнес-логика полей
│ ├── views.py # ViewSet'ы для всех ресурсов
│ ├── urls.py # Маршруты (DefaultRouter)
│ ├── permissions.py # Кастомные права доступа
│ ├── admin.py # Регистрация моделей в Django Admin
│ └── management/
│ └── commands/
│ └── fill_db.py # Команда для наполнения БД тестовыми данными
├── socialNetworkLLM/
│ ├── settings.py # Настройки проекта
│ ├── urls.py # Корневые маршруты
│ ├── wsgi.py
│ └── asgi.py
└── manage.py
# Frontend
cd frontend
npm install
npm start
# Backend (в отдельном терминале)
cd backend
pip install -r requirements.txt
python manage.py migrate
python manage.py runserverpython manage.py fill_dbСоздаст: 15 пользователей, 8 сообществ, 100 постов, 200 лайков.
Пароль всех тестовых пользователей: password123
User (Django built-in)
├── Profile (OneToOne) — никнейм, аватар, статус, дата рождения
├── Post (ForeignKey) — текст, изображение, флаг публикации
├── Subscription (ForeignKey) — подписки (subscriber → target_user)
├── Like (ManyToMany) — лайки на постах
├── Comment (ForeignKey) — комментарии к постам
├── Message (ForeignKey) — личные сообщения
└── Notification (ForeignKey) — уведомления
Community
├── creator (ForeignKey → User)
├── members (ManyToMany → User)
├── topic (ForeignKey → Topic)
└── needs_moderation (Boolean) — предмодерация постов
Дружба — это взаимная подписка. Специальная модель Friend не нужна.
При создании подписки срабатывает Django Signal, который:
- Отправляет уведомление целевому пользователю: «X подписался на вас»
- Проверяет взаимность — если да, отправляет обоим: «Вы теперь друзья с Y»
# models.py — сигнал на создание подписки
@receiver(post_save, sender=Subscription)
def create_subscription_notification(sender, instance, created, **kwargs):
if created:
Notification.objects.create(recipient=instance.target_user, ...)
is_mutual = Subscription.objects.filter(...).exists()
if is_mutual:
# Уведомления обоимКаждое сообщество имеет флаг needs_moderation. Если он включён — пост уходит на проверку (is_published=False). Создатель сообщества публикует без ограничений.
# views.py — логика при создании поста
if community.needs_moderation and community.creator != request.user:
is_published = False # Ждёт модерации
else:
is_published = True # Публикуется сразуВсе защищённые эндпоинты требуют заголовок:
Authorization: Bearer <access_token>
| Метод | URL | Описание |
|---|---|---|
POST |
/auth/users/ |
Регистрация |
POST |
/auth/jwt/create/ |
Получить токен |
POST |
/auth/jwt/refresh/ |
Обновить токен |
GET |
/auth/users/me/ |
Данные текущего пользователя |
PATCH |
/auth/users/me/ |
Редактировать профиль |
Пример регистрации:
POST /auth/users/
{
"username": "john_doe",
"email": "john@example.com",
"password": "securepass123",
"nickname": "Джон",
"birth_date": "13.05.2000"
}Дата рождения принимается в двух форматах: ДД.ММ.ГГГГ и ГГГГ-ММ-ДД.
| Метод | URL | Описание |
|---|---|---|
GET |
/api/profiles/ |
Список всех профилей |
GET |
/api/profiles/{id}/ |
Профиль пользователя |
PATCH |
/api/profiles/{id}/ |
Редактировать (только владелец) |
Профиль содержит: nickname, bio, avatar, status, birth_date, posts_count, friends_count, friends[], is_subscribed, is_friend.
Поиск: GET /api/profiles/?search=john — поиск по username и nickname.
| Метод | URL | Описание |
|---|---|---|
GET |
/api/posts/ |
Все опубликованные посты |
POST |
/api/posts/ |
Создать пост |
PATCH |
/api/posts/{id}/ |
Редактировать (только автор) |
DELETE |
/api/posts/{id}/ |
Удалить (только автор) |
POST |
/api/posts/{id}/like/ |
Поставить / убрать лайк |
GET |
/api/posts/feed/ |
Персональная лента |
GET |
/api/posts/random/ |
Случайный пост |
Фильтрация: ?author=1, ?community=2
Поиск: ?search=текст
Сортировка: ?ordering=-created_at
Алгоритм ленты (/feed/):
1. Посты от подписок + посты из сообществ пользователя (до 10)
2. Рекомендации по тематикам сообществ пользователя (до 5)
3. Если лента < 10 постов — добиваем случайными
| Метод | URL | Описание |
|---|---|---|
GET |
/api/communities/ |
Все сообщества (случайный порядок) |
POST |
/api/communities/ |
Создать сообщество |
GET |
/api/communities/my/ |
Мои сообщества |
POST |
/api/communities/{id}/join/ |
Вступить |
POST |
/api/communities/{id}/leave/ |
Выйти |
| Метод | URL | Описание |
|---|---|---|
POST |
/api/subscriptions/ |
Подписаться (target_user_id) |
POST |
/api/subscriptions/unfollow/ |
Отписаться (target_user_id) |
GET |
/api/subscriptions/?subscriber=1 |
Подписки пользователя |
GET |
/api/subscriptions/?target_user=1 |
Подписчики пользователя |
| Метод | URL | Описание |
|---|---|---|
POST |
/api/messages/ |
Отправить сообщение |
GET |
/api/messages/conversation/?with=5 |
Переписка с пользователем по ID |
GET |
/api/messages/conversation/?handle=john |
Переписка по username |
GET |
/api/messages/inbox/ |
Список всех диалогов |
При открытии переписки все непрочитанные сообщения автоматически помечаются как прочитанные.
| Метод | URL | Описание |
|---|---|---|
GET |
/api/notifications/ |
Мои уведомления |
GET |
/api/notifications/auto_read/ |
Получить и пометить прочитанными |
POST |
/api/notifications/mark_all_read/ |
Пометить все прочитанными |
| Метод | URL | Описание |
|---|---|---|
GET |
/api/comments/?post=1 |
Комментарии к посту |
POST |
/api/comments/ |
Оставить комментарий |
DELETE |
/api/comments/{id}/ |
Удалить (только автор) |
| Класс | Описание |
|---|---|
IsAuthorOrReadOnly |
Читать может любой, редактировать — только автор поста/комментария |
IsProfileOwnerOrReadOnly |
Читать профиль может любой, менять — только владелец |
IsCommunityCreatorOrReadOnly |
Изменять сообщество — только создатель |
Кастомный сериализатор CustomUserCreateSerializer проверяет:
nickname— обязательное полеbirth_date— принимает два формата, не может быть в будущем, минимальный возраст — 12 лет
if parsed_date.year < datetime.now().date().year - 12:
raise ValidationError("Для регистрации вам должно быть больше 12 лет!")django
djangorestframework
djoser
djangorestframework-simplejwt
django-cors-headers
django-filter
Pillow
Faker
Сделано за 48 часов на хакатоне «Всё Сложно». Бэкенд — с нуля, без магии.