The wagtail.contrib.settings
module allows you to define models that hold
settings which are either common across all site records or specific to each site.
Settings are editable by administrators within the Wagtail admin and can be accessed in code as well as in templates.
Add wagtail.contrib.settings
to your INSTALLED_APPS
:
INSTALLED_APPS += [
'wagtail.contrib.settings',
]
Note: If you are using settings
within templates, you will also need to
update your TEMPLATES
settings (discussed later in this page).
Create a model that inherits from either:
BaseGenericSetting
for generic settings across all sitesBaseSiteSetting
for site-specific settingsand register it using the register_setting
decorator:
from django.db import models
from wagtail.contrib.settings.models import (
BaseGenericSetting,
BaseSiteSetting,
register_setting,
)
@register_setting
class GenericSocialMediaSettings(BaseGenericSetting):
facebook = models.URLField()
@register_setting
class SiteSpecificSocialMediaSettings(BaseSiteSetting):
facebook = models.URLField()
Links to your settings will appear in the Wagtail admin 'Settings' menu.
(edit_handlers_settings)=
Settings use edit handlers much like the rest of Wagtail.
Add a panels
setting to your model defining all the edit handlers required:
@register_setting
class GenericImportantPages(BaseGenericSetting):
donate_page = models.ForeignKey(
'wagtailcore.Page', null=True, on_delete=models.SET_NULL, related_name='+'
)
sign_up_page = models.ForeignKey(
'wagtailcore.Page', null=True, on_delete=models.SET_NULL, related_name='+'
)
panels = [
FieldPanel('donate_page'),
FieldPanel('sign_up_page'),
]
@register_setting
class SiteSpecificImportantPages(BaseSiteSetting):
donate_page = models.ForeignKey(
'wagtailcore.Page', null=True, on_delete=models.SET_NULL, related_name='+'
)
sign_up_page = models.ForeignKey(
'wagtailcore.Page', null=True, on_delete=models.SET_NULL, related_name='+'
)
panels = [
FieldPanel('donate_page'),
FieldPanel('sign_up_page'),
]
You can also customize the edit handlers like you would do for Page
model with a custom edit_handler
attribute:
from wagtail.admin.panels import TabbedInterface, ObjectList
@register_setting
class MySettings(BaseGenericSetting):
# ...
first_tab_panels = [
FieldPanel('field_1'),
]
second_tab_panels = [
FieldPanel('field_2'),
]
edit_handler = TabbedInterface([
ObjectList(first_tab_panels, heading='First tab'),
ObjectList(second_tab_panels, heading='Second tab'),
])
You can change the label used in the menu by changing the
verbose_name
of your model.
You can add an icon to the menu by passing an icon
argument to the
register_setting
decorator:
@register_setting(icon='placeholder')
class GenericSocialMediaSettings(BaseGenericSetting):
...
class Meta:
verbose_name = "Social media settings for all sites"
@register_setting(icon='placeholder')
class SiteSpecificSocialMediaSettings(BaseSiteSetting):
...
class Meta:
verbose_name = "Site-specific social media settings"
Wagtail’s default icon set can be seen in our icons overview. All icons available in a given project are displayed in the styleguide.
Settings can be used in both Python code and in templates.
If you require access to a generic setting in a view, the
BaseGenericSetting.load()
method allows you to retrieve the generic
settings:
def view(request):
social_media_settings = GenericSocialMediaSettings.load(request_or_site=request)
...
(site_settings)=
If you require access to a site-specific setting in a view, the
BaseSiteSetting.for_request()
method allows you to retrieve the site-specific
settings for the current request:
def view(request):
social_media_settings = SiteSpecificSocialMediaSettings.for_request(request=request)
...
In places where the request is unavailable, but you know the Site
you wish to
retrieve settings for, you can use
BaseSiteSetting.for_site
instead:
def view(request):
social_media_settings = SiteSpecificSocialMediaSettings.for_site(site=user.origin_site)
...
Add the wagtail.contrib.settings.context_processors.settings
context processor to your settings:
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
...
'wagtail.contrib.settings.context_processors.settings',
]
}
}
]
Then access the generic settings through {{ settings }}
:
{{ settings.app_label.GenericSocialMediaSettings.facebook }}
{{ settings.app_label.SiteSpecificSocialMediaSettings.facebook }}
Note: Replace app_label
with the label of the app containing your
settings model.
If you are not in a RequestContext
, then context processors will not have
run, and the settings
variable will not be available. To get the
settings
, use the provided {% get_settings %}
template tag.
{% load wagtailsettings_tags %}
{% get_settings %}
{{ settings.app_label.GenericSocialMediaSettings.facebook }}
{{ settings.app_label.SiteSpecificSocialMediaSettings.facebook }}
By default, the tag will create or update a settings
variable in the
context. If you want to assign to a different context variable instead, use
{% get_settings as other_variable_name %}
:
{% load wagtailsettings_tags %}
{% get_settings as wagtail_settings %}
{{ wagtail_settings.app_label.GenericSocialMediaSettings.facebook }}
{{ wagtail_settings.app_label.SiteSpecificSocialMediaSettings.facebook }}
Add wagtail.contrib.settings.jinja2tags.settings
extension to your
Jinja2 settings:
TEMPLATES = [
...
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'APP_DIRS': True,
'OPTIONS': {
'extensions': [
...
'wagtail.contrib.settings.jinja2tags.settings',
],
},
}
]
Then access the settings through the settings()
template function:
{{ settings("app_label.GenericSocialMediaSettings").facebook }}
{{ settings("app_label.SiteSpecificSocialMediaSettings").facebook }}
Note: Replace app_label
with the label of the app containing your
settings model.
If there is no request
available in the template at all, you can use the
settings for the default site instead:
{{ settings("app_label.GenericSocialMediaSettings", use_default_site=True).facebook }}
{{ settings("app_label.SiteSpecificSocialMediaSettings", use_default_site=True).facebook }}
Note: You can not reliably get the correct settings instance for the current site from this template tag if the request object is not available. This is only relevant for multi-site instances of Wagtail.
You can store the settings instance in a variable to save some typing, if you have to use multiple values from one model:
{% with generic_social_settings=settings("app_label.GenericSocialMediaSettings") %}
Follow us on Facebook at {{ generic_social_settings.facebook }},
or Instagram at @{{ generic_social_settings.instagram }}.
{% endwith %}
{% with site_social_settings=settings("app_label.SiteSpecificSocialMediaSettings") %}
Follow us on Facebook at {{ site_social_settings.facebook }},
or Instagram at {{ site_social_settings.instagram }}.
{% endwith %}
Or, alternately, using the set
tag:
{% set generic_social_settings=settings("app_label.GenericSocialMediaSettings") %}
{% set site_social_settings=settings("app_label.SiteSpecificSocialMediaSettings") %}
select_related
to improve efficiencyFor models with foreign key relationships to other objects (for example pages),
which are very often needed to output values in templates, you can set
the select_related
attribute on your model to have Wagtail utilize
Django's QuerySet.select_related()
method to fetch the settings object and related objects in a single query.
With this, the initial query is more complex, but you will be able to
freely access the foreign key values without any additional queries,
making things more efficient overall.
Building on the GenericImportantPages
example from the previous section, the
following shows how select_related
can be set to improve efficiency:
@register_setting
class GenericImportantPages(BaseGenericSetting):
# Fetch these pages when looking up GenericImportantPages for or a site
select_related = ["donate_page", "sign_up_page"]
donate_page = models.ForeignKey(
'wagtailcore.Page', null=True, on_delete=models.SET_NULL, related_name='+'
)
sign_up_page = models.ForeignKey(
'wagtailcore.Page', null=True, on_delete=models.SET_NULL, related_name='+'
)
panels = [
FieldPanel('donate_page'),
FieldPanel('sign_up_page'),
]
With these additions, the following template code will now trigger a single database query instead of three (one to fetch the settings, and two more to fetch each page):
{% load wagtailcore_tags %}
{% pageurl settings.app_label.GenericImportantPages.donate_page %}
{% pageurl settings.app_label.GenericImportantPages.sign_up_page %}
page_url
setting shortcutIf, like in the previous section, your settings model references pages,
and you often need to output the URLs of those pages in your project,
you can likely use the setting model's page_url
shortcut to do that more
cleanly. For example, instead of doing the following:
{% load wagtailcore_tags %}
{% pageurl settings.app_label.GenericImportantPages.donate_page %}
{% pageurl settings.app_label.GenericImportantPages.sign_up_page %}
You could write:
{{ settings.app_label.GenericImportantPages.page_url.donate_page }}
{{ settings.app_label.GenericImportantPages.page_url.sign_up_page }}
Using the page_url
shortcut has a few of advantages over using the tag:
page_url
shortcut will be more efficient.When using the page_url
shortcut, there are a couple of points worth noting:
{% pageurl %}
tag apply to the
shortcut: If the settings are accessed from a template context where the
current request is not available, all URLs returned will include the
site's scheme/domain, and URL generation will not be quite as efficient.AttributeError
if the attribute you request from page_url
is not an attribute on the settings object.None
(or something that is not a Page
), the shortcut
will return an empty string.