diff --git a/src/character/models/character.py b/src/character/models/character.py index 6eeceee..21fa0e8 100644 --- a/src/character/models/character.py +++ b/src/character/models/character.py @@ -14,6 +14,7 @@ from django_extensions.db.models import TimeStampedModel from character.models import Capability, Path from character.models.dice import Dice from character.models.equipment import Weapon +from character.models.utils import cache_on_instance from common.models import DocumentedModel, UniquelyNamedModel @@ -471,12 +472,15 @@ class Character(models.Model): pk__in=self.states.all().values_list("pk", flat=True), ) + @cache_on_instance() def managed_by(self, user): return self in Character.objects.managed_by(user) + @cache_on_instance() def mastered_by(self, user): return self in Character.objects.mastered_by(user) + @cache_on_instance() def owned_by(self, user): return self in Character.objects.owned_by(user) diff --git a/src/character/models/utils.py b/src/character/models/utils.py new file mode 100644 index 0000000..426f5f3 --- /dev/null +++ b/src/character/models/utils.py @@ -0,0 +1,38 @@ +import functools + + +def cache_on_instance(): + def wrapper(func): + @functools.wraps(func) + def inner(self, arg): + cache_name = func.__name__ + if (cached := _get_cache_value(self, cache_name, arg)) is not None: + return cached + res = func(self, arg) + _set_cache_value(self, cache_name, arg, res) + return res + + return inner + + return wrapper + + +def _get_cache_value(obj, cache_name: str, key: str) -> any: + cache_name += "_cache" + cache = getattr(obj, cache_name, None) + if cache is None: + cache = {} + setattr(obj, cache_name, cache) + return None + + return cache.get(key) + + +def _set_cache_value(obj, cache_name: str, key: str, value: any): + cache_name += "_cache" + cache = getattr(obj, cache_name) + if cache is None: + cache = {} + setattr(obj, cache_name, cache) + + cache[key] = value