Работа с Redis в Django

В современную эпоху технологий данные становятся все более ценным товаром, и это требует оптимизации хранения и доступа к этим данным. Существует довольно много известных решений для хранения данных, включая системы управления реляционными базами данных (RDBMS), такие как MySQL и PostgreSQL, которые хранят данные в структурированном формате, используя строки и столбцы, а также взаимосвязи внутри данных. Помимо СУБД, существуют хранилища ключей и значений, которые хранят данные на основе уникальных ключей и значений, таких как словарь. Базы данных ключ-значение относятся к семейству баз данных NoSQL, которые не соответствуют реляционной природе СУБД. В этой статье мы рассмотрим Redis как хранилище ключей и значений и используем его в проекте для изучения его функциональности.

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

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

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

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

Именно по этой причине Redis известен своей исключительной производительностью.

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

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

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

Распространенные варианты использования Redis включают де:

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

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

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

Pinterest использует 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.

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

# Create the project
$ django-admin startproject django_redis_demo
$ cd django_redis_demo

# Create the app
$ django-admin startapp api

# Migrate
$ python manage.py migrate

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

$ python manage.py runserver

Когда мы переходим к http:127. 0. 0. 1:8000 , нас приветствуют.

Следующим шагом является добавление нашего api-приложения и Django REST в наш проект путем обновления списка INSTALLED_APPS, найденного в 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 путем добавления:

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('<slug:key>', manage_item, name="single_item")
}
urlpatterns = format_suffix_patterns(urlpatterns)

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

У нас будет два представления на основе функций: 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 и порт, как было сконфигурировано ранее. красный в нашем r 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-адресе.

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

С помощью метода 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:

get all items

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

{
"mighty": "mug"
}

Давайте отправим другой запрос GET в ту же конечную точку:

get all items after update

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

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

get single item

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

{
"new_value": "stackabuse.com"
}

Когда мы достанем ключ, еще раз здравствуйте:

update single item

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

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

post deletion single item

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

Вывод

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

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