0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Django Ninjaでキャッシュを使う

Last updated at Posted at 2024-07-20

初めに

Djangoには元々キャッシュ機能があり

from django.views.decorators.cache import cache_page

@cache_page(60 * 15)
def my_view(request): ...

こんな感じでデコレータを使うことでビューの結果をキャッシュできます
Django Ninjaと同じRESTフレームワークであるDjango REST Frameworkではこのcache_pageのデコレータが使えたのですがDjango Ninjaでは使えなかったので使えるデコレータを実装しました

コード

cache.py
from django.core.cache import cache
from typing import Any
from django.http import HttpRequest
from functools import wraps


class Cache:
    @classmethod
    def get(cls, key):
        return cache.get(key)

    @classmethod
    def set(cls, key, value, time_out = 60 * 60):
        cache.set(key, value, time_out)


def cache_request(timeout, *, cache_key = None):
    def wrapper(func):
        def inject(func):
            @wraps(func)
            def request(request: HttpRequest, **kwargs: Any) -> Any:
                key = cache_key
                if not key:
                    # パスとクエリをキャッシュキーにする
                    # クエリの並び順が変わっても同じキャッシュを使うためにソートしている
                    path_key = request.path
                    query_string_key = ""
                    if request.META.get("QUERY_STRING", ""):
                        query = {}
                        for query_string in request.META.get("QUERY_STRING", "").split('&'):
                            query_data = query_string.split('=')
                            query[query_data[0]] = query_data[1]
                        query = sorted(query.items())
                        query = dict((x, y) for x, y in query) 
                        for k, v in query.items():
                            if query_string_key:
                                query_string_key += "&"
                            query_string_key += f"{k}={v}"
                    key = f"{path_key}?{query_string_key}"
                if key:
                    cache = Cache.get(key)
                    if cache:
                        return cache
                res = func(request, **kwargs)
                if key:
                    Cache.set(key, res, timeout)
                return res
            return request
        return inject(func)
    return wrapper

使い方

前提としてDjangoのキャッシュが利用できる状態にしてください

その後こんな感じで利用できます

from ninja.pagination import paginate
from xxxx.cache import cache_request

router = Router()

@router.get("/")
@cache_request(60*60)
@paginate
def list(request): ...

一つ注意点としては@paginateがある場合@paginateよりも上に設定してください
下だとクエリにOFFSET、LIMITがつかない結果がキャッシュされます
キャッシュのキーはパスになっているので、何か他のものにしたい場合は、以下のように指定することもできます

@cache_request(60*60, cache_key='items')
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?