DevGang
Авторизоваться

Python: работа с Redis в Django

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

Существует довольно много известных решений для хранения данных, в том числе реляционные системы управления базами данных (RDBMS), такие как MySQL и PostgreSQL, которые хранят данные в структурированном формате с использованием строк и столбцов и связей внутри данных.

Помимо СУБД, существуют key/value хранилища, в которых хранятся данные на основе уникальных ключей и значений, например словарь. Базы данных ключ-значение относятся к семейству баз данных NoSQL, которые не соответствуют реляционной природе СУБД.

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

Что такое Redis и зачем его использовать?

Redis (REmote DIctionary Server) - это хранилище структуры данных в памяти, которое можно использовать в качестве базы данных, кэша или брокера сообщений.

Данные хранятся в Redis в форме ключ/значение, где ключи используются для поиска и извлечения данных, хранящихся в экземпляре Redis.

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

Это причина, почему Redis известен своей исключительной высокой производительностью.

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

Написанный на ANSI C, Redis легок и не имеет внешних зависимостей. Он также довольно дружественен для разработчиков, поскольку поддерживает большинство языков высокого уровня, таких как Python, JavaScript, Java, C/C ++ и PHP.

Когда следует использовать Redis?

Типичные случаи использования Redis:

  1. Кэширование . Учитывая его скорость по сравнению с традиционными базами данных, с точки зрения операций чтения и записи, Redis стал идеальным решением для временного хранения данных в кэш-памяти для ускорения доступа к данным в будущем.
  2. Очередь сообщений. Благодаря возможности реализации парадигмы обмена сообщениями «публикация / подписка» Redis стал посредником в системах очередей сообщений.
  3. Хранение данных: Redis может использоваться для хранения данных значения ключа в качестве базы данных NoSQL.

Такие компании, как Twitter, Pinterest, Github, Snapchat и StackOverflow, используют Redis для хранения и обеспечения высокой доступности данных для своих пользователей.

Например, Twitter хранит самые последние входящие твиты для пользователя в Redis, чтобы ускорить доставку твитов в клиентские приложения.

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

Установка Redis

Для дальнейшего изучения Redis нам необходимо скачать и установить сервер Redis, используя инструкции с официальной веб-страницы. Redis также доступен в виде образа Docker на Docker Hub.

Он также поставляется с инструментом Redis-CLI, который мы можем использовать для взаимодействия с данными на нашем сервере Redis и управления ими.

Redis также доступен для установки через Homebrew (для MacOS) и через репозиторий apt по умолчанию для Debian Linux и его вариантов, таких как Ubuntu.

Чтобы установить Redis на MacOS, просто запустите:

brew install redis

В Debian Linux:

sudo apt-get install redis-server

Чтобы проверить нашу установку Redis, введите команду redis-cli, а затем введите запрос ping:

$ redis-cli -v
redis-cli 5.0.6
$ redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>

Мы видим, что наш сервер Redis готов с ответом и вернет в ответ PONG.

Redis Commands

Redis через Redis-CLI предоставляет некоторые удобные команды, которые мы можем использовать для взаимодействия с сервером Redis и манипулирования данными, хранящимися там. По умолчанию серверы Redis работают на порту 6379, и это будет видно в нашем приветственно сообщении при старте сервера.

Команды, доступные в Redis-CLI, включают в себя:

SET: Эта команда используется для установки ключа и его значения, с дополнительными необязательными параметрами для указания срока действия записи значения ключа. Давайте установим ключ hello со значением world с истечением через 10 секунд:

127.0.0.1:6379> SET hello "world" EX 10
OK

GET: Эта команда используется для получения значения, связанного с ключом. Если запись значения ключа превысила срок действия, будет возвращено nil:

127.0.0.1:6379> GET hello
“world”

# After expiry
127.0.0.1:6379> GET hello
(nil)

DELETE: Эта команда удаляет ключ и соответствующее значение:

127.0.0.1:6379> DEL hello
(integer) 1

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

127.0.0.1:6379> SET foo "bar" EX 100     # 100 is the number of seconds
OK

127.0.0.1:6379> TTL foo
(integer) 97      # Number of seconds remaining till expiry

127.0.0.1:6379> TTL foo
(integer) 95

127.0.0.1:6379> TTL foo
(integer) 93

PERSIST: Если мы передумаем об истечении срока действия ключа, мы можем использовать эту команду, чтобы удалить период истечения:

127.0.0.1:6379> PERSIST foo
(integer) 1

127.0.0.1:6379> TTL foo
(integer) -1

127.0.0.1:6379> GET foo
"bar"

RENAME: Эта команда используется для переименования ключей на нашем сервере Redis:

127.0.0.1:6379> RENAME foo foo2
OK

127.0.0.1:6379> GET foo
(nil)

127.0.0.1:6379> GET foo2
"bar"

FLUSHALL: Эта команда используется для очистки всех записей значения ключа, которые мы установили в нашем текущем сеансе:

127.0.0.1:6379> RENAME foo foo2
OK

127.0.0.1:6379> GET foo
(nil)

127.0.0.1:6379> GET foo2
(nil)

127.0.0.1:6379> GET hello
(nil)

Более подробную информацию об этих и других командах Redis можно найти на официальном сайте.

Redis с Django

Чтобы продемонстрировать, как интегрировать Redis в веб-приложение, мы создадим API с использованием Django и Django REST, который сможет получать пару ключ-значение и сохранять ее на нашем сервере Redis.

Наш API также сможет получать значения для заданных ключей, извлекать все сохраненные пары ключ-значение и также удалять запись ключ-значение.

Давайте начнем с создания папки для размещения нашего проекта:

mkdir redis_demo && cd $_

Затем давайте создадим виртуальную среду и активируем ее:

virtualenv --python=python3 env --no-site-packages
source env/bin/activate

И наконец, давайте установим необходимые библиотеки:

pip install django djangorestframework redis

API нашего приложения будет получать запросы и взаимодействовать с нашим сервером Redis с помощью библиотеки Redis-py .

Давайте теперь создадим приложение:

django-admin startproject django_redis_demo
cd django_redis_demo

django-admin startapp api

python manage.py migrate

Чтобы убедиться, что наша установка Django прошла успешно, мы запускаем сервер:

python manage.py runserver

Когда мы перейдем по URL http:127.0.0.1:8000, нас приветствуют страница со следующим контентом:

Следующим шагом является добавление нашего api приложения и Django REST в наш проект путем обновления списка INSTALLED_APPS, найденного в django_redis_demo/settings.py:

django_redis_demo/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Add these two
    'rest_framework',
    'api',
]

Redis-py нужен работающий экземпляр Redis для взаимодействия. Нам нужно будет настроить его в файле django_redis_demo/settings.py, добавив:

django_redis_demo/settings.py
REDIS_HOST = 'localhost'
REDIS_PORT = 6379

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

Далее мы собираемся создать маршрут, который будет использоваться для доступа к нашему API и связать его с нашим основным приложением Django. Сначала мы создадим пустой файл api/urls.py, затем добавим наш путь в django_redis_demo/urls.py:

# Modify this import
from django.urls import path, include

urlpatterns = [
    ...
    # Add this entry
    path('api/', include('api.urls')),
]

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

Наши представления будут простыми представлениями на основе функций, которые позволят нам взаимодействовать с сервером Redis. Во-первых, давайте создадим URL-адреса, с которыми мы будем взаимодействовать в нашем api/urls.py:

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from .views import manage_items, manage_item

urlpatterns = {
    path('', manage_items, name="items"),
    path('', manage_item, name="single_item")
}
urlpatterns = format_suffix_patterns(urlpatterns)

Первый путь позволит нам создавать записи и просматривать все записи, а второй путь даст нам детальное управление отдельными записями.

Мы будем иметь два вида функции на основе: manage_items() и manage_item() что будут обрабатывать запросы и взаимодействовать с нашим экземпляром Redis. Они обе будут находиться в нашем файле api/views.py.

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

Мы начнем с импорта необходимых библиотек и подключения к нашему экземпляру Redis:

import json
from django.conf import settings
import redis
from rest_framework.decorators import api_view
from rest_framework import status
from rest_framework.response import Response

# Connect to our Redis instance
redis_instance = redis.StrictRedis(host=settings.REDIS_HOST,
                                  port=settings.REDIS_PORT, db=0)

Здесь мы создаем наш объект соединения, передавая хост и порт Redis, как ранее было настроено в нашем django_redis_demo/settings.py.

Затем мы создаем наше первое представление manage_items(), которое будет использоваться для получения всех элементов, которые в настоящее время установлены в нашем запущенном экземпляре Redis. Это представление также позволит нам создавать новые записи в нашем экземпляре Redis, передавая объект JSON:

@api_view(['GET', 'POST'])
def manage_items(request, *args, **kwargs):
    if request.method == 'GET':
        items = {}
        count = 0
        for key in redis_instance.keys("*"):
            items[key.decode("utf-8")] = redis_instance.get(key)
            count += 1
        response = {
            'count': count,
            'msg': f"Found {count} items.",
            'items': items
        }
        return Response(response, status=200)
    elif request.method == 'POST':
        item = json.loads(request.body)
        key = list(item.keys())[0]
        value = item[key]
        redis_instance.set(key, value)
        response = {
            'msg': f"{key} successfully set to {value}"
        }
        return Response(response, 201)

Теперь давайте создадим manage_item():

@api_view(['GET', 'PUT', 'DELETE'])
def manage_item(request, *args, **kwargs):
    if request.method == 'GET':
        if kwargs['key']:
            value = redis_instance.get(kwargs['key'])
            if value:
                response = {
                    'key': kwargs['key'],
                    'value': value,
                    'msg': 'success'
                }
                return Response(response, status=200)
            else:
                response = {
                    'key': kwargs['key'],
                    'value': None,
                    'msg': 'Not found'
                }
                return Response(response, status=404)
    elif request.method == 'PUT':
        if kwargs['key']:
            request_data = json.loads(request.body)
            new_value = request_data['new_value']
            value = redis_instance.get(kwargs['key'])
            if value:
                redis_instance.set(kwargs['key'], new_value)
                response = {
                    'key': kwargs['key'],
                    'value': value,
                    'msg': f"Successfully updated {kwargs['key']}"
                }
                return Response(response, status=200)
            else:
                response = {
                    'key': kwargs['key'],
                    'value': None,
                    'msg': 'Not found'
                }
                return Response(response, status=404)

    elif request.method == 'DELETE':
        if kwargs['key']:
            result = redis_instance.delete(kwargs['key'])
            if result == 1:
                response = {
                    'msg': f"{kwargs['key']} successfully deleted"
                }
                return Response(response, status=404)
            else:
                response = {
                    'key': kwargs['key'],
                    'value': None,
                    'msg': 'Not found'
                }
                return Response(response, status=404)

manage_item() дает нам доступ к отдельным записям в нашем экземпляре Redis. Это представление требует, чтобы вызывающая сторона передала ключ элемента, который нам нужен в URL.

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

С помощью метода DELETE мы можем удалить пару ключ-значение из нашего экземпляра Redis.

Чтобы увидеть наш API в действии, мы будем использовать Postman. Но сначала давайте создадим одну или две записи с помощью инструмента redis-cli:

$ redis-cli
127.0.0.1:6379> SET HELLO "WORLD"
OK
127.0.0.1:6379> SET REDIS "DEMO"
OK

После настройки данных отправим запрос GET по адресу localhost:8000/api/items:

Наш API способен извлекать все пары ключ-значение в нашем текущем экземпляре Redis. Теперь давайте отправим запрос POST со следующим содержимым на тот же URL:

{
"mighty": "mug"
}

Давайте отправим еще один запрос GET на тот же URL:

Мы видим, что ключ, который мы создали с помощью нашего API, сохраняется в нашем экземпляре Redis. Мы можем проверить его существование с помощью инструмента CLI.

Теперь давайте проверим второй URL, который возвращает значение одного ключа, отправив запрос GET по адресу http://localhost:8000/api/items/HELLO:

Все прошло хорошо. Давайте теперь обновим значение, связанное с ключом HELLO, отправив следующий JSON через запрос PUT на тот же URL:

{
"new_value": "stackabuse.com"
}

Когда мы снова получим ключ HELLO:

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

Когда мы пытаемся получить доступ к тому же элементу после его удаления:

Нам сообщили, что наш ключ был удален. Наш Django API успешно взаимодействовал с нашим экземпляром Redis с помощью библиотеки Redis-py.

Вывод

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

Мы смогли без проблем интегрировать наш Django API с локально работающим экземпляром Redis, что свидетельствует о его простоте использования с распространенными языками программирования высокого уровня.

Исходный код скрипта в этом проекте можно найти здесь, на GitHub .

Источник:

#Python #Django
Комментарии 1
Anri 16.01.2022 в 09:43

Чтобы запросы в Postman работали необходимо изменить urls.py:

urlpatterns = [
    ...
    # Add this entry
    path('api/items/', include('api.urls')),
]

либо в api/urls.py:

urlpatterns = {
    path('items/', manage_items, name="items"),
    path('items/<slug:key>', manage_item, name="single_item")
}
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу