Redis в web-приложении на Python и Starlette

programming

Опубликован:
2025-01-26T02:48:01.238725Z
Отредактирован:
2025-01-26T02:48:01.238725Z
Статус:
публичный
33
0
0

Redis — это noSQL база данных. В рамках web-приложения на Python и Starlette, процесс разработки которого мы детально изучаем в этом цикле статей, будет необходимо временно хранить некоторые данные с заданным периодом автоматического удаления этих данных, и именно эту задачу я намерен решать с помощью Redis и его инструментов. В этом выпуске цикла я покажу процесс подключения к Redis в коде ASGI-приложения и получения из базы порции данных при обработке стартовой страницы.

Установка Redis

Redis — это клиент-серверное приложение. Сервер Redis получает данные от клиента и упорядоченно хранит их. Клиент даёт возможность получить доступ к серверу по сети. В Debian и deb-основанных операционных системах установить всё это великолепие можно с помощью пакетного менеджера apt, если он подключен к сетевому хранилищу пакетов.

$ sudo apt install redis

В рамках этой и последующих демонстраций я буду использовать Redis для разработки, отладки и тестирования своего web приложения, и доступ к базе данных будет осуществляться только с localhost. В этом случае начальные настройки программы в состоянии из коробки меня полностью устроят.

В своём начальном состоянии Redis предлагает абсолютно пустую базу данных. Подключиться к ней можно с помощью команды redis-cli — это и есть штатный клиент Redis.

$ redis-cli

Управлять базой данных Redis в клиенте достаточно не сложно, для этого предлагается набор команд для всех предусмотренных программой действий с данными. С помощью команды keys можно посмотреть текущий состав базы данных, на снимке экрана далее видно, что в базе хранится пустой массив.

ixBM0BdXxe.png

Redis хранит данные в виде хешей ключ:значение. На снимке экрана выше я показал, что в ключе с именем message в базе на данный момент хранится самая обычная строка приветствия — Hello there!. Задача web-разработчика на текущем этапе разработки — получить доступ к этим данным в рамках разрабатываемого на Python приложения.

Подключаем Redis в приложение

Управлять данными Redis в программе на Python мне поможет специализированная библиотека — redis. Её необходимо установить в виртуальное окружение.

$ pip install redis

06xKhlhNs9.png

На снимке экрана выше следует обратить внимание, что предложенную выше команду я исполнил в терминале, находясь в корневом каталоге приложения и с его активным виртуальным окружением.

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

$ vim .env

В самый конец этого файла дописываю следующую строчку.

REDI='redis://localhost:6379/0'

Здесь я указал протокол (redis), адрес сервера Redis в сети (localhost), порт (6379) и имя базы данных (0), к которой подключаюсь. Сохраняю изменения в файл.

Конфигурация ASGI-приложения хранится в "ините" базового каталога приложения. Открываю этот файл в командном режиме Vim.

:edit webapp/__init__.py

Только что установленную библиотеку redis, а именно, её реализацию с асинхронным вводом-выводом следует подключить соответствующей процедурой импорта.

import redis.asyncio as redis

Классу StApp, в его метод __call__ дописываю ещё одно свойство.

        self.rp = redis.ConnectionPool.from_url(
            settings.get('REDI'),
            health_check_interval=30,
            socket_connect_timeout=15,
            socket_keepalive=True,
            retry_on_timeout=True,
            decode_responses=True)

Здесь в переменной self.rp с помощью библиотечных инструментов redis я создал пул подключений к базе данных, используя соответствующее поле файла настроек в качестве url и указанные параметры. Обращаю внимание на параметр decode_responses, в созданных с помощью этого пула подключениях все ответы базы данных будут декодированы.

DJiTJVLfa6.png

Как видно из представленного кода, доступ к пулу подключений Redis в рамках web приложения можно будет получить через запрос — request.app.rp. Сохраняю изменения в файл.

Имея пул подключений Redis, можно создать подключение в любом обработчике любого url-адреса приложения. Удобно завернуть этот функционал в ещё одну вспомогательную функцию. Открываю в текстовом редакторе ещё один файл.

:edit webapp/common/redi.py

И в этом файле пишу следующий код.

import redis.asyncio as redis


async def get_rc(request):
    return redis.Redis.from_pool(request.app.rp)

Код достаточно элементарный, дополнительных объяснений, я думаю, не требуется. Сохраняю изменения в файл.

Получаем данные из базы Redis

В web-приложении на текущий момент есть url-адрес стартовой страницы, и для этого адреса в модуле views.py каталога главной подпрограммы main определён обработчик — функция представления show_index. В рамках этого обработчика я и собираюсь продемонстрировать доступ к данным в базе Redis. Открываю указанный модуль в текстовом редакторе.

:tabnew webapp/main/views.py

Нахожу в коде этого модуля функцию представления show_index и дописываю в тело этой функции следующий код.

    from ..common.redi import get_rc
    ##Создаю соединение с базой данных
    rc = await get_rc(request)
    ##Получаю хранящуюся в ключе message базы данных
    ##строку и сохраняю её в одноимённой переменной
    message = await rc.get('message')
    ##закрываю соединение с базой данных
    await rc.close()

Чтобы иметь доступ к полученному в результате обработки этого кода значению переменной message, нужно передать это значение в словарь шаблона одноимённым ключом. Внимание на следующий снимок экрана.

YK0AmuFuzk.png

Сохраняю изменения в файл.

В результате всех проделанных действий, шаблону передана полученная из базы данных Redis строка, этими данными достаточно просто воспользоваться в логике шаблона на Jinja2. Открываю файл шаблона в текстовом редакторе.

:tabnew webapp/templates/main/index.html

Нахожу в коде этого шаблона элемент с классом empty-message и модифицирую его содержимое следующим кодом.

     <div class="empty-message">
      {% if message %}
        {{ message }}
      {% else %}
        Сайт в стадии разработки, попробуйте зайти позже.
      {% endif %}
     </div>

lrGaC9ssnr.png

Здесь всё просто... Если в словаре шаблона имеется ключ с именем message, то в блоке помещаем хранящуюся в этом ключе строку. В ином случае в блоке будет размещена строка из шаблона.

Сохраняю изменения в файл.

Тестируем в браузере

Подтвердить только что разработанный функционал можно самым простым тестом.

Первое, чего я ожидаю, это штатный запуск отладочного сервера без отчётов об ошибках и предупреждений в его выводе в терминал. Запускаю, внимание на следующий снимок экрана.

uVnMUDYRUS.png

Второе, чего я ожидаю, в блоке с информационным сообщением о стадии разработки сайта должна появиться хранящаяся в базе данных Redis, в соответствующем её ключе строка. Запускаю браузер и стучусь по адресу стартовой страницы приложения... Внимание на следующий снимок экрана.

NNd2wphEY7.png

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

Можно инициировать ещё один простой тест, удалить из базы данных Redis ключ message и обновить страницу в браузере. Как вы думаете, что покажет браузер в этом случае? Напишите в комментариях.

Подводим промежуточный итог

В web-приложении на Python и Starlette в результате всех предпринятых на текущем этапе разработки действий появилась база данных Redis и возможность хранить в ней данные, получать их, когда это необходимо, и модифицировать в соответствии с замыслом разработки и техническим заданием на проект. Текущую версию кода, как всегда, можно увидеть в моём профиле на github.com по этой короткой ссылке. Все цели этой демонстрации полностью достигнуты. О продолжении разработки этого web-приложения я расскажу в следующих выпусках этого блога. Stay tunned!