diff --git a/wagtail/contrib/settings/context_processors.py b/wagtail/contrib/settings/context_processors.py index 3a9516a523..ff4ec3045f 100644 --- a/wagtail/contrib/settings/context_processors.py +++ b/wagtail/contrib/settings/context_processors.py @@ -9,24 +9,26 @@ class SettingsProxy(dict): """ Get a SettingModuleProxy for an app using proxy['app_label'] """ - def __init__(self, site): - self.site = site + + def __init__(self, request_or_site): + self.request_or_site = request_or_site def __missing__(self, app_label): - self[app_label] = value = SettingModuleProxy(self.site, app_label) + self[app_label] = value = SettingModuleProxy(self.request_or_site, app_label) return value def __str__(self): - return 'SettingsProxy' + return "SettingsProxy" class SettingModuleProxy(dict): """ Get a setting instance using proxy['modelname'] """ - def __init__(self, site, app_label): - self.site = site + + def __init__(self, request_or_site, app_label): self.app_label = app_label + self.request_or_site = request_or_site def __getitem__(self, model_name): """ Get a setting instance for a model """ @@ -46,19 +48,14 @@ class SettingModuleProxy(dict): if Model is None: return None - return Model.for_site(self.site) + if isinstance(self.request_or_site, Site): + return Model.for_site(self.request_or_site) + # Utilises cached value on request if set + return Model.for_request(self.request_or_site) def __str__(self): return 'SettingsModuleProxy({0})'.format(self.app_label) def settings(request): - def _inner(request): - site = Site.find_for_request(request) - if site is None: - # find_for_request() can't determine the site - return {} - else: - return SettingsProxy(site) - - return {'settings': SimpleLazyObject(lambda: _inner(request))} + return {"settings": SettingsProxy(request)} diff --git a/wagtail/contrib/settings/models.py b/wagtail/contrib/settings/models.py index 2666260484..e809abaf9c 100644 --- a/wagtail/contrib/settings/models.py +++ b/wagtail/contrib/settings/models.py @@ -22,7 +22,31 @@ class BaseSetting(models.Model): @classmethod def for_site(cls, site): """ - Get an instance of this setting for the site. + Get or create an instance of this setting for the site. """ instance, created = cls.objects.get_or_create(site=site) return instance + + @classmethod + def for_request(cls, request): + """ + Get or create an instance of this model for the request, + and cache the result on the request for faster repeat access. + """ + attr_name = cls.get_cache_attr_name() + if hasattr(request, attr_name): + return getattr(request, attr_name) + site = Site.find_for_request(request) + site_settings = cls.for_site(site) + setattr(request, attr_name, site_settings) + return site_settings + + @classmethod + def get_cache_attr_name(cls): + """ + Returns the name of the attribute that should be used to store + a reference to the fetched/created object on a request. + """ + return "_{}.{}".format( + cls._meta.app_label, cls._meta.model_name + ).lower()