from django.conf import settings as dj_settings from django.core.signals import setting_changed from django.utils.translation import gettext_lazy as _ from .utils import deprecate DEFAULTS = { "DISABLE_HELP_TEXT": False, "DEFAULT_LOOKUP_EXPR": "exact", # empty/null choices "EMPTY_CHOICE_LABEL": "---------", "NULL_CHOICE_LABEL": None, "NULL_CHOICE_VALUE": "null", "VERBOSE_LOOKUPS": { # transforms don't need to be verbose, since their expressions are chained "date": _("date"), "year": _("year"), "month": _("month"), "day": _("day"), "week_day": _("week day"), "hour": _("hour"), "minute": _("minute"), "second": _("second"), # standard lookups "exact": "", "iexact": "", "contains": _("contains"), "icontains": _("contains"), "in": _("is in"), "gt": _("is greater than"), "gte": _("is greater than or equal to"), "lt": _("is less than"), "lte": _("is less than or equal to"), "startswith": _("starts with"), "istartswith": _("starts with"), "endswith": _("ends with"), "iendswith": _("ends with"), "range": _("is in range"), "isnull": _("is null"), "regex": _("matches regex"), "iregex": _("matches regex"), "search": _("search"), # postgres lookups "contained_by": _("is contained by"), "overlap": _("overlaps"), "has_key": _("has key"), "has_keys": _("has keys"), "has_any_keys": _("has any keys"), "trigram_similar": _("search"), }, } DEPRECATED_SETTINGS = [] def is_callable(value): # check for callables, except types return callable(value) and not isinstance(value, type) class Settings: def __getattr__(self, name): if name not in DEFAULTS: msg = "'%s' object has no attribute '%s'" raise AttributeError(msg % (self.__class__.__name__, name)) value = self.get_setting(name) if is_callable(value): value = value() # Cache the result setattr(self, name, value) return value def get_setting(self, setting): django_setting = "FILTERS_%s" % setting if setting in DEPRECATED_SETTINGS and hasattr(dj_settings, django_setting): deprecate("The '%s' setting has been deprecated." % django_setting) return getattr(dj_settings, django_setting, DEFAULTS[setting]) def change_setting(self, setting, value, enter, **kwargs): if not setting.startswith("FILTERS_"): return setting = setting[8:] # strip 'FILTERS_' # ensure a valid app setting is being overridden if setting not in DEFAULTS: return # if exiting, delete value to repopulate if enter: setattr(self, setting, value) else: delattr(self, setting) settings = Settings() setting_changed.connect(settings.change_setting)