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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
|
import hashlib
import json
from rest_framework_extensions.key_constructor import bits
from rest_framework_extensions.settings import extensions_api_settings
class KeyConstructor:
def __init__(self, memoize_for_request=None, params=None):
if memoize_for_request is None:
self.memoize_for_request = extensions_api_settings.DEFAULT_KEY_CONSTRUCTOR_MEMOIZE_FOR_REQUEST
else:
self.memoize_for_request = memoize_for_request
if params is None:
self.params = {}
else:
self.params = params
self.bits = self.get_bits()
def get_bits(self):
_bits = {}
for attr in dir(self.__class__):
attr_value = getattr(self.__class__, attr)
if isinstance(attr_value, bits.KeyBitBase):
_bits[attr] = attr_value
return _bits
def __call__(self, **kwargs):
return self.get_key(**kwargs)
def get_key(self, view_instance, view_method, request, args, kwargs):
if self.memoize_for_request:
memoization_key = self._get_memoization_key(
view_instance=view_instance,
view_method=view_method,
args=args,
kwargs=kwargs
)
if not hasattr(request, '_key_constructor_cache'):
request._key_constructor_cache = {}
if self.memoize_for_request and memoization_key in request._key_constructor_cache:
return request._key_constructor_cache.get(memoization_key)
else:
value = self._get_key(
view_instance=view_instance,
view_method=view_method,
request=request,
args=args,
kwargs=kwargs
)
if self.memoize_for_request:
request._key_constructor_cache[memoization_key] = value
return value
def _get_memoization_key(self, view_instance, view_method, args, kwargs):
from rest_framework_extensions.utils import get_unique_method_id
return json.dumps({
'unique_method_id': get_unique_method_id(view_instance=view_instance, view_method=view_method),
'args': args,
'kwargs': kwargs,
'instance_id': id(self)
})
def _get_key(self, view_instance, view_method, request, args, kwargs):
_kwargs = {
'view_instance': view_instance,
'view_method': view_method,
'request': request,
'args': args,
'kwargs': kwargs,
}
return self.prepare_key(
self.get_data_from_bits(**_kwargs)
)
def prepare_key(self, key_dict):
return hashlib.md5(json.dumps(key_dict, sort_keys=True).encode('utf-8')).hexdigest()
def get_data_from_bits(self, **kwargs):
result_dict = {}
for bit_name, bit_instance in self.bits.items():
if bit_name in self.params:
params = self.params[bit_name]
else:
try:
params = bit_instance.params
except AttributeError:
params = None
result_dict[bit_name] = bit_instance.get_data(
params=params, **kwargs)
return result_dict
class DefaultKeyConstructor(KeyConstructor):
unique_method_id = bits.UniqueMethodIdKeyBit()
format = bits.FormatKeyBit()
language = bits.LanguageKeyBit()
class DefaultObjectKeyConstructor(DefaultKeyConstructor):
retrieve_sql_query = bits.RetrieveSqlQueryKeyBit()
class DefaultListKeyConstructor(DefaultKeyConstructor):
list_sql_query = bits.ListSqlQueryKeyBit()
pagination = bits.PaginationKeyBit()
class DefaultAPIModelInstanceKeyConstructor(KeyConstructor):
"""
Use this constructor when the values of the model instance are required
to identify the resource.
"""
retrieve_model_values = bits.RetrieveModelKeyBit()
class DefaultAPIModelListKeyConstructor(KeyConstructor):
"""
Use this constructor when the values of the model instance are required
to identify many resources.
"""
list_model_values = bits.ListModelKeyBit()
|