-
Notifications
You must be signed in to change notification settings - Fork 5
/
django_context_decorator.py
59 lines (45 loc) · 1.91 KB
/
django_context_decorator.py
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
class context:
"""
Use this class as a decorator around methods, properties, or cached
properties to add the wrapped value (or result for callables) to
the template context. Works for all Django View classes.
Requires Python 3.6+
"""
def __init__(self, func):
self.func = func
@staticmethod
def _initialize_context_fields(cls):
if getattr(cls, "_context_fields_owner", "") is cls:
return
cls._context_fields_owner = cls
cls._context_fields = set()
for parent in cls.mro()[1:]:
cls._context_fields.update(getattr(parent, "_context_fields", set()))
def __set_name__(self, owner, name):
if hasattr(self.func, "__set_name__"):
self.func.__set_name__(owner, name)
self._initialize_context_fields(owner)
owner._context_fields.add(name)
if not getattr(owner, "get_context_data", False):
def get_context_data(_self, **kwargs):
return super(owner, _self).get_context_data(**kwargs)
owner.get_context_data = get_context_data
if not getattr(owner, "_context_patched", False):
old_get_context_data = owner.get_context_data
def new_get_context_data(_self, **kwargs):
self._initialize_context_fields(type(_self))
result = old_get_context_data(_self, **kwargs)
for name in _self._context_fields:
attr = getattr(_self, name)
if callable(attr):
attr = attr()
result.setdefault(name, attr)
return result
owner.get_context_data = new_get_context_data
owner._context_patched = True
def __get__(self, instance, cls=None):
return (
self.func.__get__(instance, cls)
if hasattr(self.func, "__get__")
else self.func
)