Cookbook

This section covers practical use cases for the django-content-settings module that might be useful in your projects.


Grouping Multiple Settings by the Same Rule

Suppose you have a group of settings with the same permission and want to append a note to the help text for those settings. While you can configure each setting individually, grouping them simplifies the process.

from content_settings.types.basic import SimpleString
from content_settings.permissions import superuser
from content_settings.defaults.context import defaults
from content_settings.defaults.modifiers import help_suffix

with defaults(help_suffix("Only superuser can change that"), update_permission=superuser):
    SITE_TITLE = SimpleString("Book Store", help="title for the site.")
    SITE_KEYWORDS = SimpleString("books, store, popular", help="head keywords.")

The above code can be replaced with individual configurations as follows:

# same imports

SITE_TITLE = SimpleString(
    "Book Store", 
    update_permission=superuser,
    help="title for the site.<br>Only superuser can change that",
)
SITE_KEYWORDS = SimpleString(
    "books, store, popular",
    update_permission=superuser,
    help="head keywords.<br>Only superuser can change that",
)

Setting as a Class Attribute (Lazy Settings)

Consider the following content_settings.py:

from content_settings.types.basic import SimpleInt

POSTS_PER_PAGE = SimpleInt(10, help="How many blog posts will be shown per page")

In a views.py:

from django.views.generic import ListView
from blog.models import Post
from content_settings.conf import content_settings


class PostListView(ListView):
    model = Post
    paginate_by = content_settings.POSTS_PER_PAGE

The above will work until you update POSTS_PER_PAGE in the Django admin, at which point the change won’t reflect. Instead, use a lazy value:

# same imports

class PostListView(ListView):
    model = Post
    paginate_by = content_settings.lazy__POSTS_PER_PAGE  # <-- update

How to Test Setting Changes

Use content_settings_context from content_settings.context_managers to test setting changes.

As a Decorator:

@content_settings_context(TITLE="New Book Store")
def test_get_simple_text_updated():
    assert content_settings.TITLE == "New Book Store"

As a Context Manager:

def test_get_simple_text_updated_twice():
    client = get_anonymous_client()
    with content_settings_context(TITLE="New Book Store"):
        assert content_settings.TITLE == "New Book Store"

    with content_settings_context(TITLE="SUPER New Book Store"):
        assert content_settings.TITLE == "SUPER New Book Store"

Handling Endless Running Commands

If you have an endless running command and want to keep settings updated, manually check updates inside the loop. Use check_update from content_settings.caching.

from django.core.management.base import BaseCommand
from content_settings.caching import check_update

class Command(BaseCommand):
    def handle(self, *args, **options):
        while True:
            check_update()

            # your logic

Triggering a Procedure When a Variable Changes

To trigger an action, such as data synchronization, when a setting changes, add a post_save signal handler for models.ContentSetting.

Case #1: Manually Convert Raw Data

from django.db.models.signals import post_save
from django.dispatch import receiver
from content_settings.models import ContentSetting

@receiver(post_save, sender=ContentSetting)
def process_variable_update(instance, created, **kwargs):
    if instance.name != 'VARIABLE':
        return
    val = content_settings.type__VARIABLE.give_python(instance.value)

    # process value

Case #2: Use content_settings_context

# same imports
from content_settings.context_managers import content_settings_context

@receiver(post_save, sender=ContentSetting)
def process_variable_update(instance, created, **kwargs):
    if instance.name != 'VARIABLE':
        return

    with content_settings_context(VARIABLE=instance.value):
        val = content_settings.VARIABLE

    # process value

Upgrading a Variable from SimpleText to Template

If you previously used a SimpleText variable and later need a template, you don’t have to update all references from VARNAME to VARNAME().

Use GiveCallMixin or NoArgs types such as DjangoTemplateNoArgs or SimpleEvalNoArgs. For the opposite scenario, use MakeCallMixin.


Using DjangoModelTemplate Without Directly Importing a Model

If you cannot import a model to assign a query to template_model_queryset, use DjangoTemplate with gen_args_call_validator.

def getting_first_profile():
    from accounts.models import Profile

    return Profile.objects.first()

NEW_SETTING = DjangoTemplate(
    "{{object.name}}",
    validators=[gen_args_call_validator(getting_first_profile)],
    template_args_default={'object': require}
)

Stand With Ukraine