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

Twitter-clone на FastAPI. Наполняем таблицу данными и получаем твиты из БД. Часть 4

Продолжаем разрабатывать бэкенд клона твиттера для корпоративной локальной сети. Начало по ссылкам ниже: Дисклеймер: Данный цикл статей не инструкция к тому как нужно делать. Это больше похоже на лайвкодинг, с публикацией шагов, что и как я делал. Дабы в процессе написания статьи самому более глубоко проникнуться в тему, а так же помочь другим людям, которые, возможно, тупанули на каком-то моменте и не знают как сдвинуться с мёртвой точки. Я на этом шаге тупил месяц! Так как статья и код писалась очень долго, то случились некоторые изменения, которые могут не совпадать с предыдущими статьями. Итак, обработку пользователей я завершил, после успешной отработки запроса на эндпойнт /api/users/me, фронтэнд запрашивает следующий эндпойнт: /api/tweets (в логах именно такой порядок): Начну с главного файла, ибо в нем случились некоторые изменения. Появился "жизненный цикл" базы данных. Если перезапустить приложение то все данные удалятся и создадутся заново. Эндпойнты вынесены в отдельные фа
Оглавление
Фоточка для карточки. Фото автора. Северодвинск, Белое море, ноябрь 2024
Фоточка для карточки. Фото автора. Северодвинск, Белое море, ноябрь 2024

Продолжаем разрабатывать бэкенд клона твиттера для корпоративной локальной сети. Начало по ссылкам ниже:

Дисклеймер: Данный цикл статей не инструкция к тому как нужно делать. Это больше похоже на лайвкодинг, с публикацией шагов, что и как я делал. Дабы в процессе написания статьи самому более глубоко проникнуться в тему, а так же помочь другим людям, которые, возможно, тупанули на каком-то моменте и не знают как сдвинуться с мёртвой точки. Я на этом шаге тупил месяц!
Так как статья и код писалась очень долго, то случились некоторые изменения, которые могут не совпадать с предыдущими статьями.

Итак, обработку пользователей я завершил, после успешной отработки запроса на эндпойнт /api/users/me, фронтэнд запрашивает следующий эндпойнт: /api/tweets (в логах именно такой порядок):

-2

Начну с главного файла, ибо в нем случились некоторые изменения. Появился "жизненный цикл" базы данных. Если перезапустить приложение то все данные удалятся и создадутся заново. Эндпойнты вынесены в отдельные файлы из которых они импортируются. Nginx и postgres установлены на компьютер с операционной системой Manjaro Linux дома и Arch Linux - на работе. Ну и само приложение - решил делать без докер-контейнеров. Контейнеры буду подключать только тогда когда будет всё закончено.

Как я настраивал работу фронта без контейнеров:

Итак, main.py:

-3

Чтобы получить какие-то твиты, они у нас должны быть в базе данных, а для этого их туда надо поместить, вместе с данными каких-то пользователей. Для этого и служит "жизненный цикл приложения", пока приложение работает и не перезагружается - все изменения в базе данных сохраняются.

Модели, по которым создаются таблицы

Потому как для реализации конечной точки /api/tweets, нужны все модели (users, tweets, likes, images).

Все начинается с директории /src/core/models и файла __init__.py, где и объявляются все модели, чтобы заработало создание таблиц через Base.metadata.create_all:

-4

Затем базовая модель, от которой будут наследоваться все остальные модели:

заметьте, тут указано __abstract__ = True это для того чтобы в базе данных не появилась таблица bases
заметьте, тут указано __abstract__ = True это для того чтобы в базе данных не появилась таблица bases

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

-6
-7

Именно здесь указан атрибут backref="user" который будет использоваться для подгрузки данных пользователей:

-8

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

Далее идет модель твитов:

-9

Модель лайков:

-10

Модель картинок:

-11

И вот только после того как у нас появились все нужные модели, можно создать таблицы (Base.metadata.create_all). Наполнить их данными (await insert_data(conn) в файле main.py). Это отсылка к файлу /api/crud/insert_data_in_tables.py

В котором будет создано 5 пользователей, 5 твитов, какие-то твиты будут "пролайканы", какие-то пользователи будут подписаны на других пользователей:

-12
-13

После того как все таблицы созданы и данные в них имеются, в базе данных получается вот такая вот прелесть:

Структура базы данных
Структура базы данных
-15
-16
-17
-18
-19

Таблица с картинками у меня пока не используется, после того как закончу с получением твитов, буду пробовать подставить какие-нибудь картинки к этим твитам.

Ну чтож, база данных наполнена, сделаем GET-запрос на получение твитов, для пользователя с api_key = "test":

-20

Вот такой получается хитрый запрос. Попробую объяснить некоторые моменты:
response_model=TweetListSchema - pydantic schema, которая нужна для правильной подачи данных для фронтенда.

-21

Из схемы вывода твитов, видно что еще используются схемы вывода лайков и базовая, для пользователя.

-22
-23

Далее дело за аргументами асинхронной функции get_tweets_follow_user, где получается с помощью db_helper асинхронная сессия, из заголовка мы получаем текущего пользователя с помощью функции get_current_user, которая находится в файле src/api/crud/crud_users.py:

-24
-25

Строчка выделена серым цветом, что показывает - она как бы не используется, но это не совсем так. Если ее убрать, то исчезнет из Swagger заголовок в котором можно указать api_key:

-26

Без этой строчки будет так:

-27
-28

Поэтому строчка хоть как-бы и не используется, она всё-таки используется!

-29

Далее идет обращение к асинхронной функции get_all_tweets, в аргументах которой передаются сессия для соединения с базой данных и пользователь от имени которого посылается запрос. Название get_all_tweets пожалуй неправильное, ведь я не все твиты получаю а только те на кого подписан текущий пользователь (имя функции будет изменено).

-30

Вот та функция, которая мне никак не хотела даваться! Я довольно таки быстро сделал фильтрацию по пользователю, подтянул имена пользователей. Картинки пока не проверено. Но мне никак не давалась сортировка по количеству лайков. Я понимал что нужно сделать счетчик этих лайков, но куда вставить - х.з. Всё давало ошибку. Спросил совета у мудрецов в интернете, ответ получил примерно как фильме "О чем говорят мужчины" - "...зеленые тапочки!"

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

Незнаю насколько это правильно - не правильно, но это работает. Теперь все твиты на которых подписан пользователь с api_key = 'test' выведены и отсортированы по убыванию популярности (то есть которые больше всех были лайкнуты).

-31

Ну вот пожалуй на сегодня и всё. Я вчера был вне себя от счастья, что я таки смог дописать четыре строчки, чтобы всё правильно работало!

Всем здоровья, счастья и всего самого наилучшего в наступившем новом 2025 году!