File: models.py

package info (click to toggle)
python-django-solo 2.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 400 kB
  • sloc: python: 363; makefile: 8
file content (83 lines) | stat: -rw-r--r-- 2,661 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
from __future__ import annotations

import sys
import warnings
from typing import Any

from django.conf import settings
from django.core.cache import BaseCache, caches
from django.db import models

from django_solo import settings as solo_settings

if sys.version_info >= (3, 11):
    from typing import Self
else:
    from typing_extensions import Self


DEFAULT_SINGLETON_INSTANCE_ID = 1


def get_cache(cache_name: str) -> BaseCache:
    warnings.warn(
        "'get_cache' is deprecated and will be removed in django-solo 2.4.0. "
        "Instead, use 'caches' from 'django.core.cache'.",
        DeprecationWarning,
        stacklevel=2,
    )
    return caches[cache_name]


class SingletonModel(models.Model):
    singleton_instance_id = DEFAULT_SINGLETON_INSTANCE_ID

    class Meta:
        abstract = True

    def save(self, *args: Any, **kwargs: Any) -> None:
        self.pk = self.singleton_instance_id
        super().save(*args, **kwargs)
        self.set_to_cache()

    def delete(self, *args: Any, **kwargs: Any) -> tuple[int, dict[str, int]]:
        self.clear_cache()
        return super().delete(*args, **kwargs)

    @classmethod
    def clear_cache(cls) -> None:
        cache_name = getattr(settings, "SOLO_CACHE", solo_settings.SOLO_CACHE)
        if cache_name:
            cache = caches[cache_name]
            cache_key = cls.get_cache_key()
            cache.delete(cache_key)

    def set_to_cache(self) -> None:
        cache_name = getattr(settings, "SOLO_CACHE", solo_settings.SOLO_CACHE)
        if not cache_name:
            return None
        cache = caches[cache_name]
        cache_key = self.get_cache_key()
        timeout = getattr(settings, "SOLO_CACHE_TIMEOUT", solo_settings.SOLO_CACHE_TIMEOUT)
        cache.set(cache_key, self, timeout)

    @classmethod
    def get_cache_key(cls) -> str:
        prefix = getattr(settings, "SOLO_CACHE_PREFIX", solo_settings.SOLO_CACHE_PREFIX)
        # Include the model's module in the cache key so similarly named models from different
        # apps do not have the same cache key.
        return f"{prefix}:{cls.__module__.lower()}:{cls.__name__.lower()}"

    @classmethod
    def get_solo(cls) -> Self:
        cache_name = getattr(settings, "SOLO_CACHE", solo_settings.SOLO_CACHE)
        if not cache_name:
            obj, _ = cls.objects.get_or_create(pk=cls.singleton_instance_id)
            return obj
        cache = caches[cache_name]
        cache_key = cls.get_cache_key()
        obj = cache.get(cache_key)
        if not obj:
            obj, _ = cls.objects.get_or_create(pk=cls.singleton_instance_id)
            obj.set_to_cache()
        return obj