Как сопоставить шаблоны ключей Redis, используя собственный кеш django?

У меня есть серия кешей, которые следуют этому шаблону:

key_x_y = value

Нравиться:

  'key_1_3' = 'foo'
  'key_2_5' = 'bar'
  'key_1_7' = 'baz'

Теперь мне интересно, как я могу перебрать все ключи, чтобы они соответствовали шаблону, например key_1_*, чтобы получить foo и baz, используя собственный django cache.get()?

(Я знаю, что есть способ, в частности для redis, который позволяет использовать более обширные API как iterate, но я бы хотел придерживаться ванильного кеша django, если это возможно)


person Jand    schedule 09.03.2016    source источник
comment
Доступны ли эти ключи в объекте cache? Является ли объект cache словарем?   -  person AKS    schedule 09.03.2016
comment
Да, объект кеша — это набор строк, сохраненных в кеше Redis, и я собираюсь найти все значения, соответствующие key_1_*.   -  person Jand    schedule 09.03.2016


Ответы (2)


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

Изменить: если вы уже используете django-redis, ты можешь сделать

from django.core.cache import cache
cache.keys("foo_*")

как описано здесь.

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

cache.get_many(cache.keys("key_1_*"))
person Muhammad Tahir    schedule 09.03.2016
comment
Не могли бы вы уточнить код, как это можно сделать в пользовательской оболочке? - person Jand; 09.03.2016
comment
Пользовательская оболочка — это вариант, когда серверная часть кеша поддерживает эту функцию, а оболочка кеша Django — нет. Если бэкэнд не поддерживает его, то пользовательская оболочка ничего не сделает. - person Muhammad Tahir; 09.03.2016
comment
Как вы сами предположили в вопросе, это можно сделать с помощью django-redis, поскольку Redis поддерживает эту функцию, а django-redis — это пользовательская оболочка, которая поддерживает все методы оболочки Django, а также некоторые дополнительные методы, доступные только для Redis. Вы можете посмотреть здесь niwinz.github.io/django-redis/latest/#_scan_delete_keys_in_bulk если вы хотите узнать, как получить ключи по шаблону с помощью django-redis. - person Muhammad Tahir; 09.03.2016
comment
Верно, Мухаммад, поэтому, пожалуйста, используйте наиболее эффективный способ, то есть cache.get_many(cache.keys("key_1_*")), и я приму ответ. - person Jand; 09.03.2016
comment
@MuhammadTahir, можете ли вы объяснить временную сложность. - person Manoj Jadhav; 14.03.2017
comment
@manojJadhav временная сложность поиска шаблонов ключей составляет O(N), где N — это общее количество ключей, хранящихся в базе данных Redis, как указано здесь redis .io/commands/keys. См. также раздел предупреждений на указанной странице, где указано should only be used in production environments with extreme care, it may ruin performance. - person Muhammad Tahir; 15.03.2017

Если cache имеет следующие записи:

cache = {'key_1_3': 'foo', 'key_2_5': 'bar', 'key_1_7': 'baz'}

Вы можете получить все записи с ключом key_1_*:

x = {k: v for k, v in cache.items() if k.startswith('key_1')}

На основе документации из django-redis

Вы можете перечислить все ключи с шаблоном:

>>> from django.core.cache import cache
>>> cache.keys("key_1_*")
# ["key_1_3", "key_1_7"]

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

>>> [cache.get(k) for k in cache.keys("key_1_*")]
# ['foo', 'baz']

Вы также можете использовать cache.iter_keys(pattern) для эффективной реализации.

Или, как предложил @Muhammad Tahir, вы можете использовать cache.get_many(cache.keys("key_1_*")), чтобы получить все значения за один раз.

person AKS    schedule 09.03.2016
comment
Хорошо, но словарь сохраняется в кеше Redis. Извините, я должен был упомянуть об этом. - person Jand; 09.03.2016
comment
Есть некоторые рекомендации о том, как использовать Redis в качестве бэкэнда кэширования. Вы установили кеш на Redis? - person AKS; 09.03.2016
comment
Да, и я уже использую Redis для сеансов. Вот почему я не хочу ломать кеш, внедряя сторонние модули. - person Jand; 09.03.2016
comment
@AKS cache.get_many(cache.keys(key_1_*)) здесь лучший вариант. Он извлечет все ключи за один вызов вместо «n» вызовов. - person Muhammad Tahir; 09.03.2016
comment
Я согласен, что это было бы лучше. :) Но я только что заметил, что OP не хочет отказываться от ванильного кеша django. - person AKS; 09.03.2016
comment
@AKS не прочь, но отойди от ванильного джанго! Спасибо вам, ребята! - person Jand; 09.03.2016