From 9f905cf8429a5266da3e7c5a4e439bfffe5078b6 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 9 Jun 2026 11:17:36 -0400 Subject: [PATCH] Closes #22288: Rename JINJA2_FILTERS to JINJA_FILTERS --- docs/configuration/system.md | 17 ++++++++++------- docs/plugins/development/config-templates.md | 10 +++++----- netbox/extras/tests/test_models.py | 2 +- netbox/netbox/plugins/registration.py | 2 +- netbox/netbox/settings.py | 8 +++++++- netbox/netbox/tests/test_plugins.py | 4 ++-- netbox/utilities/jinja2.py | 4 ++-- 7 files changed, 28 insertions(+), 19 deletions(-) diff --git a/docs/configuration/system.md b/docs/configuration/system.md index efc983407..eb8e58635 100644 --- a/docs/configuration/system.md +++ b/docs/configuration/system.md @@ -149,7 +149,7 @@ Set this configuration parameter to `True` for NetBox deployments which do not h Default: `[]` -A list of system environment variable names which may be referenced from within Jinja2 templates via the built-in [`env`](#jinja2_filters) filter. Patterns may include wildcards (matched using Python's `fnmatch` syntax). Any variable whose name does not match an entry in this list cannot be referenced from a template. For example: +A list of system environment variable names which may be referenced from within Jinja templates via the built-in [`env`](#jinja_filters) filter. Patterns may include wildcards (matched using Python's `fnmatch` syntax). Any variable whose name does not match an entry in this list cannot be referenced from a template. For example: ```python JINJA_ENVIRONMENT_PARAMS = [ @@ -163,35 +163,38 @@ JINJA_ENVIRONMENT_PARAMS = [ --- -## JINJA2_FILTERS +## JINJA_FILTERS + +!!! info "Renamed in NetBox v4.7" + This parameter was formerly named `JINJA2_FILTERS`. The old name is still supported for backward compatibility but is deprecated and will be removed in NetBox v5.0. Default: `{}` -A dictionary of custom Jinja2 filters with the key being the filter name and the value being a callable. For more information see the [Jinja2 documentation](https://jinja.palletsprojects.com/en/3.1.x/api/#custom-filters). For example: +A dictionary of custom Jinja filters with the key being the filter name and the value being a callable. For more information see the [Jinja documentation](https://jinja.palletsprojects.com/en/3.1.x/api/#custom-filters). For example: ```python def uppercase(x): return str(x).upper() -JINJA2_FILTERS = { +JINJA_FILTERS = { 'uppercase': uppercase, } ``` -NetBox also registers the following filters by default. Any entry defined in `JINJA2_FILTERS` with the same name will override the default. +NetBox also registers the following filters by default. Any entry defined in `JINJA_FILTERS` with the same name will override the default. | Filter | Description | |---|---| | `env` | Returns the value of the system environment variable with the given name, provided its name matches an entry in [`JINJA_ENVIRONMENT_PARAMS`](#jinja_environment_params). Returns `None` if the variable is not defined or its name is not whitelisted. | -For example, given `JINJA_ENVIRONMENT_PARAMS = ['WEBHOOK_TOKEN_*']`, a Jinja2 template may reference an environment variable as: +For example, given `JINJA_ENVIRONMENT_PARAMS = ['WEBHOOK_TOKEN_*']`, a Jinja template may reference an environment variable as: ``` Authorization: Bearer {{ 'WEBHOOK_TOKEN_3' | env }} ``` !!! tip "Plugin-provided filters" - Plugins can also register Jinja2 filters without requiring instance configuration. See [Jinja2 Config Templates](../plugins/development/config-templates.md) in the plugin development documentation. Instance-level `JINJA2_FILTERS` always takes precedence over plugin-registered filters of the same name. + Plugins can also register Jinja filters without requiring instance configuration. See [Jinja Config Templates](../plugins/development/config-templates.md) in the plugin development documentation. Instance-level `JINJA_FILTERS` always takes precedence over plugin-registered filters of the same name. --- diff --git a/docs/plugins/development/config-templates.md b/docs/plugins/development/config-templates.md index 91476a865..cdcd68b6c 100644 --- a/docs/plugins/development/config-templates.md +++ b/docs/plugins/development/config-templates.md @@ -1,13 +1,13 @@ -# Jinja2 Config Templates +# Jinja Config Templates -NetBox uses [Jinja2](https://jinja.palletsprojects.com/) to render [configuration templates](../../features/config-templates.md). Plugins can extend this rendering pipeline in two complementary ways: +NetBox uses [Jinja](https://jinja.palletsprojects.com/) to render [configuration templates](../../features/config-templates.md). Plugins can extend this rendering pipeline in two complementary ways: 1. **Register custom filters** — make new template filters available by name in every config template. 2. **Inject context variables** — add extra variables that are available inside every config template render. --- -## Registering Jinja2 Filters +## Registering Jinja Filters ### Via `jinja2_env.py` (auto-discovery) @@ -57,7 +57,7 @@ class MyPluginConfig(PluginConfig): ### Precedence -The full filter precedence from lowest to highest is: **NetBox built-in filters** (e.g. `env`) → **plugin-registered filters** → **instance [`JINJA2_FILTERS`](../../configuration/system.md#jinja2_filters)**. Instance-level filters always win, so site admins can override anything without touching a plugin. +The full filter precedence from lowest to highest is: **NetBox built-in filters** (e.g. `env`) → **plugin-registered filters** → **instance [`JINJA_FILTERS`](../../configuration/system.md#jinja_filters)**. Instance-level filters always win, so site admins can override anything without touching a plugin. If two plugins register a filter with the same name, the later-loaded plugin's version wins and NetBox will log a warning. @@ -72,7 +72,7 @@ def prefix_list(device): for ip in iface.ip_addresses.all() ] -JINJA2_FILTERS = { +JINJA_FILTERS = { 'prefix_list': prefix_list, } ``` diff --git a/netbox/extras/tests/test_models.py b/netbox/extras/tests/test_models.py index d827c641b..7f7721258 100644 --- a/netbox/extras/tests/test_models.py +++ b/netbox/extras/tests/test_models.py @@ -1010,7 +1010,7 @@ class JinjaEnvFilterTestCase(TestCase): self.assertEqual(output, 'secret') def test_user_defined_filter_overrides_default(self): - with self.settings(JINJA2_FILTERS={'env': lambda name: 'overridden'}): + with self.settings(JINJA_FILTERS={'env': lambda name: 'overridden'}): output = render_jinja2("{{ 'NETBOX_TEST_TOKEN' | env }}", {}) self.assertEqual(output, 'overridden') diff --git a/netbox/netbox/plugins/registration.py b/netbox/netbox/plugins/registration.py index b8d28ab51..c5eda45a8 100644 --- a/netbox/netbox/plugins/registration.py +++ b/netbox/netbox/plugins/registration.py @@ -25,7 +25,7 @@ def register_jinja2_filters(filters): """ Register a dict of Jinja2 filter functions provided by a plugin. Each key is the filter name as it will appear in templates; the value is the callable implementing it. - Plugin-registered filters have lower precedence than instance-level JINJA2_FILTERS + Plugin-registered filters have lower precedence than instance-level JINJA_FILTERS so that site admins can always override them in configuration.py. """ if not isinstance(filters, dict): diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index bd4054eb3..092ac44db 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -141,7 +141,7 @@ HTTP_PROXIES = getattr(configuration, 'HTTP_PROXIES', {}) INTERNAL_IPS = getattr(configuration, 'INTERNAL_IPS', ('127.0.0.1', '::1')) ISOLATED_DEPLOYMENT = getattr(configuration, 'ISOLATED_DEPLOYMENT', False) JINJA_ENVIRONMENT_PARAMS = getattr(configuration, 'JINJA_ENVIRONMENT_PARAMS', []) -JINJA2_FILTERS = getattr(configuration, 'JINJA2_FILTERS', {}) +JINJA_FILTERS = getattr(configuration, 'JINJA_FILTERS', getattr(configuration, 'JINJA2_FILTERS', {})) LANGUAGE_CODE = getattr(configuration, 'DEFAULT_LANGUAGE', 'en-us') LANGUAGE_COOKIE_PATH = CSRF_COOKIE_PATH LOGGING = getattr(configuration, 'LOGGING', {}) @@ -263,6 +263,12 @@ elif hasattr(configuration, 'LOGIN_REQUIRED'): "configuration file.", DeprecationWarning, ) +if hasattr(configuration, 'JINJA2_FILTERS'): + warnings.warn( + "JINJA2_FILTERS has been renamed to JINJA_FILTERS and the old name will be removed in NetBox v5.0. Please " + "update your configuration file to use JINJA_FILTERS instead.", + DeprecationWarning, + ) # diff --git a/netbox/netbox/tests/test_plugins.py b/netbox/netbox/tests/test_plugins.py index aa652c36d..d7eb469f6 100644 --- a/netbox/netbox/tests/test_plugins.py +++ b/netbox/netbox/tests/test_plugins.py @@ -281,12 +281,12 @@ class PluginTestCase(TestCase): def test_instance_jinja2_filters_override_plugin_filters(self): """ - Instance-level JINJA2_FILTERS must take precedence over plugin-registered filters + Instance-level JINJA_FILTERS must take precedence over plugin-registered filters of the same name. """ from utilities.jinja2 import render_jinja2 override = {'dummy_upper': lambda v: 'overridden'} - with self.settings(JINJA2_FILTERS=override): + with self.settings(JINJA_FILTERS=override): result = render_jinja2("{{ 'hello' | dummy_upper }}", {}) self.assertEqual(result, 'overridden') diff --git a/netbox/utilities/jinja2.py b/netbox/utilities/jinja2.py index a7a4ded01..8437b9344 100644 --- a/netbox/utilities/jinja2.py +++ b/netbox/utilities/jinja2.py @@ -98,12 +98,12 @@ def render_jinja2(template_code, context, environment_params=None, data_file=Non environment = SandboxedEnvironment(**environment_params) - # Build filter table: default < plugin-registered < instance JINJA2_FILTERS. + # Build filter table: default < plugin-registered < instance JINJA_FILTERS. # Instance-level config always wins so site admins can override anything. filters = { **DEFAULT_JINJA2_FILTERS, **registry['plugins'].get('jinja2_filters', {}), - **get_config().JINJA2_FILTERS, + **get_config().JINJA_FILTERS, } environment.filters.update(filters)