from pytoolbox.django.core.constants import DEFFERED_REGEX
__all__ = ['FieldsToValuesLookupDict']
[docs]class FieldsToValuesLookupDict(object):
"""
Global registry for mapping X class fields to W values.
* X can be a Model, a (Model)Form, a REST Framework Serializer, ...
* Y can be the fields help texts or verbose names, or the number 42.
Strange idea? Isn't it?
Here is a short example as an appetizer. Suppose you want to define your application's help
texts into a centralized registry, for keeping your wording DRY. And suppose you have some
models like this:
>> class Media(models.Model):
.. url = models.URLField()
>> class File(models.Model):
.. url = models.URLField()
And you instantiate this class with:
>> help_texts = FieldsLookupDict({'Media.url': 'The media asset ingest URL', 'url': 'An URL'})
Then, you can lookup for the help text of a field like this:
>> help_texts[(Media, 'url')]
The media asset ingest URL
>> help_texts[(File, 'url')]
An URL
The value returned will be the first matching to the following keys:
1. '<cls.__name__>.<field_name>'
2. '<field_name>'
If given class have a _meta or Meta ("meta") attribute with a model attribute, then the
following keys are tried:
1. '<cls.__name__>.<field_name>'
2. '<cls._meta.model>.<field_name>'
3. '<field_name>'
"""
[docs] def __init__(self, name, translations=None):
self.name = name
self.translations = translations or {}
def __getitem__(self, key):
if isinstance(key, str):
keys = [key]
else:
cls, field_name = key
keys = [f'{cls.__name__}.{field_name}', field_name]
meta = getattr(cls, '_meta', None) or getattr(cls, 'Meta', None)
if meta and hasattr(meta, 'model'):
# cleanup model name when some fields are deferred (Media vs Media_Deffered_...)
keys.insert(1, f"{DEFFERED_REGEX.sub('', meta.model.__name__)}.{field_name}")
for key in keys:
value = self.translations.get(key)
if value:
return value
raise KeyError(f'Entry for keys {keys} not found in {self.name}.')
def __setitem__(self, key, value):
self.translations[key] = value