Using Variables in Your Project

Introduction

This article describes how to use settings created with the django-content-settings module in various contexts, such as code, templates, and APIs.

Creating a Variable

Let's start by creating a MAX_PRICE variable, which we will use for price validation:

from content_settings.types.basic import SimpleDecimal

MAX_PRICE = SimpleDecimal("9.99", help="Maximum allowed price in the store")

By default, if not altered in the admin panel, MAX_PRICE will return Decimal("9.99").

Accessing Variables in Templates

Using variables in templates is straightforward. If you've added content_settings.context_processors.content_settings to your context_processors, you can access content_settings.conf.content_settings using {{ CONTENT_SETTINGS }}.

<b>Max Price:</b> {{ CONTENT_SETTINGS.MAX_PRICE }}

Accessing Variables Through API

The content settings app has built-in views you can use to provide access to your variables through the API.

Below is an example of how you can use it in your urls.py:

from django.urls import path
from content_settings.views import FetchSettingsView

urlpatterns = [
    path("fetch/main/", FetchSettingsView.as_view(names=[
        "TITLE",
        "DESCRIPTION",
    ]), name="fetch_main"),
]

In this way, you define an API that provides access to two variables, TITLE and DESCRIPTION. Read more about APIs here.

The next step is to define permissions for the setting, i.e., who is allowed to read it. The fetch_permission attribute is responsible for that:

from content_settings.types.basic import SimpleText

DESCRIPTION = SimpleText(
    "The best bookstore in the world",
    fetch_permission="any",  # <-- update
)

More about permissions can be found here.

Usage in Python Code

Variables are accessible via content_settings located in content_settings.conf.

Example

from decimal import Decimal
from content_settings.conf import content_settings

def update_price(request):
    new_price = Decimal(request.POST["price"])
    if new_price > content_settings.MAX_PRICE:
        raise ValueError("Price is too high")

    # ...

Prefix System

The content_settings object has a system of prefixes, which can be read as "functions under the setting." A prefix is always lowercased with the following double-underscore (__).

content_settings.prefix_name__SETTINGS_NAME

type__ - Accessing Variable Type

This prefix is the simplest way to access the settings type object. For example:

content_settings.type__MAX_PRICE.help

Returns the value of the help attribute of the setting.

lazy__ - Get a Lazy/Proxy Object of the Setting

In cases where a variable is used in class or function attributes, you should use a lazy object with the lazy__ prefix:

from decimal import Decimal
from content_settings.conf import content_settings

def update_price(request, max_price=content_settings.lazy__MAX_PRICE):
    new_price = Decimal(request.POST["price"])
    if new_price > max_price:
        raise ValueError("Price is too high")

    # ...

Why is that?

If you don't use the lazy__ prefix and just use the variable directly:

def update_price(request, max_price=content_settings.MAX_PRICE):
    ...

everything would work as expected, until you decide to change the value of the variable in the Django admin panel. In the example above (without lazy), the value of max_price will remain unchanged, which is undesirable and unexpected. In the lazy-prefix example, the value will be updated when the variable in Django admin changes.

The lazy-prefix returns not the value itself but a proxy object that retrieves the value every time you access it.

withtag__ - Dictionary with All Settings with a Specific Tag

For this prefix, instead of SETTING_NAME, use TAG_NAME.

Example:

all_main = content_settings.withtag__MAIN

all_main is a dictionary where the setting name is the key and the setting value is the value.

startswith__ - Dictionary with All Settings Starting with a Specific Value

Works in the same way as the withtag__ prefix.

all_main = content_settings.startswith__MAIN

all_main contains all of the settings whose names start with "MAIN," as a dictionary where the setting name is the key and the setting value is the value.

Custom Prefix

You can register your own prefix using the store.register_prefix decorator. Read more about it in the article about Possible Extensions.

Assigning Values

You can assign a value directly in the code (not only in the Admin Panel):

content_settings.IS_OPEN = "-"
assert content_settings.IS_OPEN is False

This is not how django-content-settings was intended to be used, so keep in mind:

  • The assigned value is always a string (raw_value), but the returned value has the type of the setting.
  • The assignment process includes value validation, which can take some time.
  • Assigning the value updates the database value as well as the cache.
  • For user-defined values, you can also define creation attributes that will be used in case the type setting is not created:
content_settings.IS_OPEN = ("-", "bool")

Stand With Ukraine