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

Twitter-clone на FastAPI. Пишем твит. Сохраняем картинки. POST-запрос. Часть 5

Итак, продолжаем развивать проект "Твиттер-клона", в прошлой статье я описал как получить твиты для текущего пользователя, от тех пользователей на которых он подписан (кого читает). Я было возрадовался что смог сдвинуться с мёртвой точки, смог отсортировать твиты по их популярности (самые "отлайканные" вверху). Но оказался маааааленький косяк - не публикуются твиты у которых вообще лайков нет! С этим придется так же что-то делать. Для начала мы сделаем новый роут для отправки POST-запроса на запись нового твита в базу данных в файле /src/api/routes_tweets.py: Где получаем из фронта данные нашего твита, сессию и текущего пользователя и всё это дело отправляем crud_tweets.create_tweet для записи в базу данных: После чего можно попробовать написать какой-нибудь твит и попытаться отправить его в базу данных: Обновим базу данных и увидим текст данного твита в таблице tweets: Как я и писал выше - твиты без лайков не отображаются, тем более что фильтрация по условиям задачи настроена таким
Оглавление
Просто красивая картинка село Черевково май 2024. Фото автора
Просто красивая картинка село Черевково май 2024. Фото автора

Итак, продолжаем развивать проект "Твиттер-клона", в прошлой статье я описал как получить твиты для текущего пользователя, от тех пользователей на которых он подписан (кого читает).

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

Запись нового твита в базу данных

Для начала мы сделаем новый роут для отправки POST-запроса на запись нового твита в базу данных в файле /src/api/routes_tweets.py:

-2

Где получаем из фронта данные нашего твита, сессию и текущего пользователя и всё это дело отправляем crud_tweets.create_tweet для записи в базу данных:

-3

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

-4
Успешная отправка
Успешная отправка

Обновим базу данных и увидим текст данного твита в таблице tweets:

-6

Как я и писал выше - твиты без лайков не отображаются, тем более что фильтрация по условиям задачи настроена таким образом, что твиты может видеть только тот кто подписан на автора твита (сам автор твита не может увидеть в своей ленте свои твиты). На меня подписан "Михаил Лермонтов" и он не увидит этот твит, пока я ему (твиту) в базе данных не "закину" хотя бы один лайк. Пока просто переключу пользователя, на М.Лермонтова:

-7

Как видим, есть один твит, с одним лайком. Сейчас залезу в БД и подправлю там данные о лайках, и только тогда тут появится второй твит, который я писал выше:

-8

Обновляем страницу М.Лермонтова:

-9

Ну вот, работает. Усложним задачу. Теперь нужно к этому же CRUD добавить скачивание, сохранение картинок и запись в БД информации о том где эта картинка лежит и к какому твиту относится.

Сохраняем картинки

За основу берется тот же самый код что и выше, только коммит сессии делаем не сразу после добавления нового твита (session.add(new_tweet)), а позже. В этот разрыв вставляем проверку наличия информации о картинке и если она была загружена - какой то код на сохранение этой картинки на компьютере и записи в БД.

Для начала попробую просто вставить картинку, написать твит и посмотреть что происходит:

-10

Написал твит, загрузил на сайт картинку, нажал "Твитнуть" и ожидаемо прозошла ошибка:

-11

Хоть тут и написано что ошибка, в логах все нормально, верней ошибка 404, ведь я еще не писал POST-роут /api/medias. Следовательно двигаемся туда и создаем соответствующий роут.

Создаём endpoint /api/medias

Начал сразу с добавления в main.py соответствующих путей:

-12

Затем в src.api создал соответствующий файл routes_medias.py, где на коленке сообразил нечто минимально рабочее:

-13

Ну, понятно, чуда не произошло и при загрузке картинки:

говорит мол необрабатываемый контент...
говорит мол необрабатываемый контент...

Не сразу разглядел, ругается не мой свежесозданный роут, а роут с твитами! Ему не нравится мой ответ ("path_to_image"), там должен быть json с ключом media_id и целым числом.

-15

После этого произошла "отправка" твита, и я смог посмотреть что же там у меня в tweet_media_ids:

-16

Ну вот, вроде бы разобрался что дальше делать. Надо вместо "заглушки" ответа на эндпойнт сделать сохранение картинки. Для этого понадобятся сессия (используем session_getter) и загруженный файл (загружается из фронта):

-17

Для валидации входных данных напишем ImageResponseSchema:

-18

Всё это богатство отправляем в функцию по сохранению картинки image_save(). Тут сразу две фукнции, сохранение картинки и её обновление (чтобы чуть позже картинку связать с конкретным твитом):

-19

В функции сохранения картинки используется еще одна дополнительная функция, которая записывает картинку непосредственно на жесткий диск компьютера:

-20

Тут появляются еще несколько дополнительных функций. Во первых надо проверить а что там вообще за файл нам прилетел, картинка или нет!?

-21

Так же появляются дополнительные константы, которые я буду хранить в файле /src/core/config.py

Само сообой это пока только черновик, релиз будет переписан практически заново
Само сообой это пока только черновик, релиз будет переписан практически заново

И еще две функции, назначение которых в комментариях:

-23

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

остальные картинки это тестовые варианты, которые загружаются каждый раз при изменении приложения или перезапуске, всё остальное успешно удаляется
остальные картинки это тестовые варианты, которые загружаются каждый раз при изменении приложения или перезапуске, всё остальное успешно удаляется

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

-25

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

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

Ссылки на предыдущие статьи по этому проекту:

Не поскупитесь на:

-26