Templates
The most powerful part of Content Settings, where the raw value of your content settings is used to generate the actual value within your project.
The module introduces advanced variable types for template rendering and Python code evaluation, utilizing CallToPythonMixin to allow setting variables to be used as functions. The implementation of this mixin is explained here using the SimpleFunc type. However, in a real-world project, you may want to use more advanced types like DjangoTemplate, DjangoModelTemplate, SimpleEval, and more. Feel free to skip the explanation of CallToPythonMixin if you only need an overview of practical templates.
CallToPythonMixin - Explanation (Can Be Skipped)
This mixin has two important methods you may want to override:
prepare_python_call: Prepares the Python object and returns a dictionary used askwargsfor calling the attribute.python_call: This method is called when the user invokes the setting as a function.
If you don't want to override these methods, you can use attributes:
- call_func: Defines a function that will be executed when the user calls the attribute. By default, it is
lambda *args, prepared=None, **kwargs: prepared(*args, **kwargs). - call_prepare_func: A function that processes values from Django Admin and stores them for use. By default, it is
lambda value: value. - call_func_argument_name: The argument name for the prepared value (default:
"prepared").
Using call_prepare_func and call_func together can boost performance.
Example: SimpleFunc
The simplest use of CallToPythonMixin with a text value:
class SimpleFunc(CallToPythonMixin, SimpleText):
admin_preview_as = PREVIEW.PYTHON
Example 1: Logic Within Call
THE_FUNC = SimpleFunc(
"Welcome {name}",
call_func=lambda name, prepared: prepared.format(name=name),
validators=(call_validator("Alex"),),
)
Usage:
print(content_settings.THE_FUNC("Alex"))
# Output: Welcome Alex
Example 2: Pre-processing Before Use
THE_FUNC = SimpleFunc(
"Welcome {name}",
call_prepare_func=lambda value: value.format,
validators=(call_validator(name="Alex"),),
)
Usage remains the same:
print(content_settings.THE_FUNC(name="Alex"))
# Output: Welcome Alex
Example 3: Using Non-Text Input
THE_SUM_FUNC = mix(CallToPythonMixin, SimpleInt)(
"10",
call_func=lambda value, prepared: prepared + value,
validators=(call_validator(20),),
)
Usage:
print(content_settings.THE_SUM_FUNC(12))
# Output: 22
These are basic examples, mainly for understanding how template types work.
Types
DjangoTemplate (SimpleCallTemplate)
Converts a raw value into a Django template and returns a function that takes arguments as context and returns the rendered value.
Example:
WELCOME_TEXT = DjangoTemplate("Hi, {{name}}")
Usage:
content_settings.WELCOME_TEXT() # Output: Hi,
content_settings.WELCOME_TEXT(name="Alex") # Output: Hi, Alex
You can define default arguments:
WELCOME_TEXT = DjangoTemplate("Hi, {{name}}", template_args_default={"name": "Alex"})
Required Arguments:
from content_settings.types import required
WELCOME_TEXT = DjangoTemplate("Hi, {{name}}", template_args_default={"name": required})
To render in a Django template:
{% load content_settings_extras %}
<b>{% content_settings_call "WELCOME_TEXT" "Bob" %}</b>
DjangoTemplateNoArgs (GiveCallMixin, DjangoTemplate)
Similar to DjangoTemplate, but doesn't require calling to render. The value is rendered automatically:
AVATAR = DjangoTemplateNoArgs("""<img src="{{SETTINGS.STATIC_URL}}test.png" />""")
content_settings.AVATAR # Output: <img src="/static/test.png" />
DjangoModelTemplate (DjangoModelTemplateMixin, DjangoTemplate)
Similar to DjangoTemplate, but accepts a model object as the first argument.
from django.contrib.auth.models import User
WELCOME_TEXT = DjangoModelTemplate("Hi, {{object.username}}", template_model_queryset=User.objects.all())
Usage:
cur_user = User.objects.get(id=1)
content_settings.WELCOME_TEXT(cur_user)
SimpleEval (SimpleCallTemplate)
Stores Python code as the setting's value. When called, arguments are passed to the code execution. Similar to DjangoTemplate, SimpleEval compiles the code before use.
THE_PRICE = SimpleEval('100 + addition', template_args_default={"addition": 0})
content_settings.THE_PRICE() # Output: 100
content_settings.THE_PRICE(20) # Output: 120
To extend the context:
from content_settings.types.template import required
from decimal import Decimal
COMMISSION = SimpleEval(
"total * Decimal('0.2')",
template_args_default={"total": required},
template_static_data={"Decimal": Decimal},
)
content_settings.COMMISSION(Decimal('100')) # Output: Decimal("20")
SimpleExec (SystemExec, SimpleCallTemplate)
Uses exec instead of eval to execute Python code. Always returns a dictionary with the executed context. Configure template_return to control what part of the context to return:
Options for template_return:
- None: Returns the entire context.
- str: Returns a specific variable from the context.
- dict: Returns specific keys from the context.
- list or tuple: List of keys to return.
- function: A function that returns a dictionary with default values.
Example with template_return:
THE_VALUE = SimpleExec("""
result = 5
""", template_return="result")
content_settings.THE_VALUE() # Output: 5
Calling Functions in Template
To render a callable setting like DjangoTemplate or SimpleEval in a template:
{% load content_settings_extras %}
{% content_settings_call "WELCOME_TEXT" "Bob" %}
Validators for Templates
call_validator
Validates the function by calling it without exceptions for specific arguments.
from content_settings.types.validators import call_validator
PLUS_ONE = SimpleEval(
"1 + val",
validators=(call_validator(), call_validator(0), call_validator(-1), call_validator(100)),
template_args_default={"val": 3},
)
result_validator
Use this validator to ensure the result meets specific criteria.
from content_settings.types.validators import result_validator
PLUS_ONE = SimpleEval(
"1 + val",
validators=(result_validator(lambda val: isinstance(val, int), "The result should be an int", 100)),
template_args_default={"val": 3},
)
Setting Evaluation and Flexibility
Template settings provide a powerful mechanism for evaluating logic within a project, allowing easy switching between flexible user-defined calculations and more stable default values. Using mixins like MakeCallMixin, you can maintain backward compatibility with callable settings, even as their underlying types change.