Найти в Дзене
Computer Pro

Twitter-clone на FastAPI. Финал

Понедельник вчера (03.02.25) оказался на редкость плодотворным. Я закончил дипломный проект по курсу Python advanced и сдал его на проверку. Утром смотрю в телефон - сообщение от куратора: Ну и чудненько. Итак, оглядываясь на проделанную работу: Так же еще несколько публикаций на эту тему, не стал вставлять ссылки на них. Сколько бы работ я ни делал, всегда новая работа очень трудно сдвигается с мертвой точки. Скачал архив с фронтендом, распаковал, запустил файл index.html в надежде чего-нибудь увидеть - а там пусто, белый экран! Фигасе! И чего тут делать?! Примерно представляю что делать, а с чего начать - тупняк! Спустя пару дней я разобрался что надо делать: кратко - архив распаковать в какую нибудь созданную директорию (например - static) и указать к ней путь в конфигурации nginx.conf: А так же указать prox_pass с указанием на FasAPI приложение, которое и будет реагировать на эндпойнты. Чтобы приложение минимально заработало нужен эндпойнт /api/users/me, который ничего не будет о
Оглавление
Фоточка для карточки. Северодвинск май 2021 года. Фото автора
Фоточка для карточки. Северодвинск май 2021 года. Фото автора

Понедельник вчера (03.02.25) оказался на редкость плодотворным. Я закончил дипломный проект по курсу Python advanced и сдал его на проверку. Утром смотрю в телефон - сообщение от куратора:

-2

Ну и чудненько.

Итак, оглядываясь на проделанную работу:

Так же еще несколько публикаций на эту тему, не стал вставлять ссылки на них.

Самое сложное - начало

Сколько бы работ я ни делал, всегда новая работа очень трудно сдвигается с мертвой точки. Скачал архив с фронтендом, распаковал, запустил файл index.html в надежде чего-нибудь увидеть - а там пусто, белый экран! Фигасе! И чего тут делать?!

архив с фронтендом
архив с фронтендом

Примерно представляю что делать, а с чего начать - тупняк!

Спустя пару дней я разобрался что надо делать: кратко - архив распаковать в какую нибудь созданную директорию (например - static) и указать к ней путь в конфигурации nginx.conf:

моя конфигурация при использовании установленного на компьютер nginx
моя конфигурация при использовании установленного на компьютер nginx

А так же указать prox_pass с указанием на FasAPI приложение, которое и будет реагировать на эндпойнты.

Чтобы приложение минимально заработало нужен эндпойнт /api/users/me, который ничего не будет отрабатывать а только возвращать JSON определенного вида, скажем такого:

-5

Это приложение уже сможет что-то вывести на странице браузера:

-6

Но тут не будет твитов... Для этого нужен еще один эндпойнт /api/tweets. Тут так же можно вставить что-то типа JSON заглушки, как в коде выше, вот такого типа (написано в описании к проекту):

-7

Если создать что-то типа этого JSON'a то в ленте твитов что-то появится...

Создание базы данных и планирование таблиц

Первым делом нужны .env файлы, один в корне проекта (для docker-compose.yaml файла), второй в src (для проекта), третий с добавленным именем test: .test.env (для выполнения тестов).

В самом начале проекта я использовал .env файл вот такого вида:

-8

В конце проекта понял, что такой вариант .env файла не годится. Ведь при написании docker-compose.yaml файла указываются имя пользователя, пароль и имя базы данных, которые будет храниться в общем доступе. А надо их привести к такому виду чтобы эти данные брались из .env файла а не были как у меня, вот в таком виде, всем доступны из docker-compose.yaml:

-9

Поэтому переделал .env в такой вид:

-10

Теперь эта часть docker-compose.yaml выглядит так:

-11

А затем уже в файле src/core/config.py из этих кусочков собирал URL для подключения к базе данных:

-12

Пришлось избавиться от отдельного файла .test.env. Потому что выяснилось - при тестах, этот файл не подгружается, в отличии от версии этого приложения без использования докер-контейнеров.

И ни какие танцы с бубном мне не помогли сделать так, чтобы использовалась тестовая база данных и тестовый пользователь БД. В итоге я забил на это дело и вставил такую конструкцию в conftest.py:

-13

Лишь имя докер-контейнера базы данных берется из .env файла.

Проектирование базы данных. Таблицы

Модели начинаются с "помощника баз данных (db_helper)" , задачей которого - создать движок, создать сессию исходя из параметров полученых в src/core/config.py

Структурная схема таблицы users и ее код, которая имеет связь один ко многим (один пользователь может иметь множество твитов, лайков, подписчиков и сам быть подписчиком):

Структурная схема таблицы tweets и ее код, которая так же имеет связи один к одному (у одного твита может быть только один автор, у одного твита может быть только одно изображение) и один ко многим (у одного твита может быть множество лайков)

Структурная схема таблицы likes и ее код, которая имеет связь один к одному (возможно ошибаюсь), так как один лайк может быть только от одного пользователя в отношении одного твита.

Структурная схема таблицы images и её код. Таблица имеет связь один к одному (только одна картинка может быть только у одного твита)

Структурная схема таблицы followers_tbl и её код. Таблица имеет связь многие ко многим и описана она в модели users:

Роуты

В данном приложении фактически только три роута: users, tweets, medias. Которые работают через префикс /api и далее каждый (кроме medias) дополняеется дополнительными постфиксами, необходимыми для конкретных ситуаций. Я так и поделил всю логику приложения на три файла:

routes_users.py

routes_tweets.py

routes_medias.py

Так как линтер flake8 сильно ругался на различные числа и переменные, то пришлось добавить несколько констант в файле src/core/config.py которые использовались в роутах:

-23

Далее вся логика приложения переходит выполнению запросов к базе данных. Где так же как и роуты запросы к базе данных поделены на три типа: запрос картинок, пользователей, твитов:

crud_users.py

Самый сложный запрос - получить список твитов отсортированный по количеству лайков и только тех, кого читает текущий пользователь. А так же, от себя, добавил - видеть свои собственные твиты.
crud_tweets.py

Загрузка картинок работает не только с базой данных но и с жестким диском, куда эта картинка сохраняется. Появляется дополнительные функции оперирующие записью и удалением файлов с жесткого диска, а так же различными проверками, созданием директорий.
crud_images.py + utils/image_files.py

Схемы валидации

Вот мы написали роуты, роуты обратились к CRUD базе данных, получили какой-либо ответ, теперь этот ответ нужно прогнать через схемы валидации. Либо это правильный ответ, либо пришла ошибка и то и другое валидируем через pydantic.

  • Базовая схема и схемы обработки ошибок:
  • Схема обработки пользовательских данных
-28
  • Схема вывода твитов:
  • Схема обработки лайков
-30
  • Схема обработки изображений:
-31

Запуск FastAPI приложения

Понимая как это всё работает нужно объединить в одном main.py файле. Чтобы все таблицы создались при первом запуске приложенения, затем можно просто закомментировать несколько строк кода, выполняющих удаление, создание и наполнение некими данными для демонстрации работы приложения.

Вот уже хотел вставить скриншот своего main.py, и что-то мне показался он слишком избыточным в плане импортов и включения разных функций, в итоге вынес лишнее "под капот"

-32

Конечено, наверняка можно и инклюды объединить в один, но сходу у меня не получилось, так что путь остается как есть. Было до модернизации так:

-33

Под "капотом", куда вынес лишний код, стало так:

Ну вот осталось написать Dockerfile в котором будет прописана сборка докер-контейнера приложения:

-35

А так же docker-compose.yaml файл где будут соединены FastAPI приложение, контейнер с postgresql и nginx:

Можно делать запуск:

-37
-38

Работа приложения в браузере

Посмотрим что у нас появилось в браузере по адресу http://0.0.0.0 (можно указать 127.0.0.1 кому как нравится):

-39
-40

И увидеть его в самом низу:

-41

Если мы его лайкнем, то он переместится сразу же после твита с двумя лайками:

-42

Если нажать на пользователя (иконку) то можно войти в его профиль и отписаться, если отпишешься, сразу появится кнопка подписаться:

-43
-44

Можно попытаться удалить чужой твит, только у нас этого не получится:

-45

Свой же твит мы можем безпрепятственно удалить, твит с картинкой, который я вначале создан - удален, удалена и сама картинка с жесткого диска:

-46

Можно поубирать все свои лайки (сердечки станут белыми и -1)

-47

Можно открыть "свой" профиль:

-48

Тестирование эндпойнтов pytest

Чуть не забыл про тестироание... Это очень важная часть работы. Первым делом - conftest.py который создает движок, сессию, наполняет базу какой-то тестовой информацией, тестовый клиент.

Вставка данных в таблицы:

Тесты разбиты на три файла, сравнение происходит с данными из тех данных что должны быть на выходе, файл good_response.py:

-51

Ну и сами тесты:

Сорян... остальные тесты опубликовать не могу. ДЗЕН не позволяет много картинок постить...

Чтобы запустить тесты нужно запустить приложение командой:

docker compose up --build

Затем войти в контейнер Fastapi приложения:

docker exec -it clone_twitter_app_container /bin/bash

-53

Ну вот вроде бы и всё, что знал - рассказал, может быть чего-то упустил, забыл, не заметил, спрашивайте - отвечу. Куратор, после того как принял работу, предложил добавить в проект Selery, Sentry, Prometehus + Grafana. А смысл?! Данный проект изначально мёртво-рожденный, кроме как для отработки полученных навыков, нигде использоваться не будет, смысла допиливать его не вижу, разве что чисто из "спортивного интереса". Может быть и допилю...

Кто осилил мою писанину - вот ссылка на версию без докер-контейнеров, и вторая ссылка на версию с докером.

На этом у меня всё. Всем здоровья и счастья и всего самого наилучшего.

Слава Богу!