1from django.core import checks
2from django.utils.functional import cached_property
3
4NOT_PROVIDED = object()
5
6
7class FieldCacheMixin:
8 """
9 An API for working with the model's fields value cache.
10
11 Subclasses must set self.cache_name to a unique entry for the cache -
12 typically the field’s name.
13 """
14
15 @cached_property
16 def cache_name(self):
17 raise NotImplementedError
18
19 def get_cached_value(self, instance, default=NOT_PROVIDED):
20 try:
21 return instance._state.fields_cache[self.cache_name]
22 except KeyError:
23 if default is NOT_PROVIDED:
24 raise
25 return default
26
27 def is_cached(self, instance):
28 return self.cache_name in instance._state.fields_cache
29
30 def set_cached_value(self, instance, value):
31 instance._state.fields_cache[self.cache_name] = value
32
33 def delete_cached_value(self, instance):
34 del instance._state.fields_cache[self.cache_name]
35
36
37class CheckFieldDefaultMixin:
38 _default_hint = ("<valid default>", "<invalid default>")
39
40 def _check_default(self):
41 if (
42 self.has_default()
43 and self.default is not None
44 and not callable(self.default)
45 ):
46 return [
47 checks.Warning(
48 "%s default should be a callable instead of an instance "
49 "so that it's not shared between all field instances."
50 % (self.__class__.__name__,),
51 hint=(
52 "Use a callable instead, e.g., use `%s` instead of "
53 "`%s`." % self._default_hint
54 ),
55 obj=self,
56 id="fields.E010",
57 )
58 ]
59 else:
60 return []
61
62 def check(self, **kwargs):
63 errors = super().check(**kwargs)
64 errors.extend(self._check_default())
65 return errors