Кэширование на основе динамических данных
Нередко приходится кэшировать что-то, основанное на динамических данных. В этих случаях необходимо создавать динамические ключи, содержащие всю информацию, необходимую для уникальной идентификации кэшированных данных.
Отредактируйте файл views.py приложения books, видоизменив представление book_list_sort(), приведя его к следующему виду:
@require_http_methods(['GET'])
def book_list_sort(request, filter, direction):
filter_dict = {_('id'): 'pk',
_('title'): 'title',
_('author'): 'author',
_('price'): 'price',
_('read'): 'read'}
if filter in filter_dict:
sort_str = ('-', '')[direction == _('ascend')] + filter_dict[filter]
cache_key = 'cached_book_list_sorted_' + sort_str
book_list = cache.get_or_set(cache_key, Book.objects.order_by(sort_str))
else:
book_list = cache.get_or_set('cached_book_list', Book.objects.all())
return render(request, 'partial_book_list.html', {'book_list': book_list})
В данном примере мы кэшируем выбранный вариант сортировки списка книг, создав для него имя ключа из параметров сортировки.
Теперь понажимаем на кнопки-стрелки сортировки:
В панели инструментов видно как при первом нажатии на кнопку сортировки есть запрос к базе данных, а при повторном уже нет. Так-же виден ключ с созданным, из параметров сортировки, именем cached_book_list_sorted_author.
В данном примере может быть создано максимум 11ть ключей кэша, и при любом изменении в списке книг данные в них будут не актуальные, рассмотрим способы удаления их.
Для этого создадим в начале файла views.py функцию удаления ключей delete_cache_keys():
def delete_cache_keys():
cache.delete('cached_book_list')
for col in ('pk', 'title', 'author', 'price', 'read'):
cache.delete('cached_book_list_sorted_' + col)
cache.delete('cached_book_list_sorted_-' + col)
И заменим в представлениях строку cache.delete('cached_book_list') на вызов данной функции delete_cache_keys():
@require_http_methods(['POST'])
def create_book(request):
form = BookCreateForm(request.POST)
if form.is_valid:
book = form.save()
delete_cache_keys()
return render(request, 'partial_book_detail.html', {'book': book})
def update_book_details(request, pk):
book = Book.objects.get(pk=pk)
if request.method == 'POST':
form = BookEditForm(request.POST, instance=book)
if form.is_valid():
book = form.save()
delete_cache_keys()
return render(request, 'partial_book_detail.html', {'book': book})
else:
form = BookEditForm(instance=book)
return render(request, 'partial_book_update_form.html', {'book': book, 'form': form})
@require_http_methods(['DELETE'])
def delete_book(request, pk):
book = get_object_or_404(Book, pk=pk)
book.delete()
delete_cache_keys()
return HttpResponse()
@require_http_methods(['PUT'])
def update_book_status(request, pk):
book = get_object_or_404(Book, pk=pk)
if book.read:
book.read = False
else:
book.read = True
book.save()
delete_cache_keys()
return render(request, 'partial_book_detail.html', {'book': book})
Проверим как это работает, после нажатий на кнопки сортировки нажмём кнопку изменить статус любой книги, и после этого увидим 11ть команд delete:
Можно уменьшить количество обращений к кэшу, при удалении, с 11ти до одного, для этого воспользуемся методом delete_many(), перепишем функцию delete_cache_keys():
def delete_cache_keys():
key_list = ['cached_book_list']
for col in ('pk', 'title', 'author', 'price', 'read'):
key_list += ['cached_book_list_sorted_' + col]
key_list += ['cached_book_list_sorted_-' + col]
cache.delete_many(key_list)
Теперь видим что выполнилась только одна команда delete_many вместо 11ти команд delete:
Время выполнения обращения к кэшу уменьшилось с 2,4мс до 1,2мс, то-есть в два раза.
Для полной очистки кэша можно воспользоваться методом clear(), он удалит все ключи из кэша.