From 063d1fef7ac8fbc0de4991663bea92c154b0af4c Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 29 Jul 2025 10:09:25 -0400 Subject: [PATCH] Closes #18797: Support path import for certain Jinja environment parameters (#19962) * Closes #18797: Support path import for certain Jinja environment parameters * Document dotted path support for Jinja env params --- docs/models/extras/configtemplate.md | 8 ++++++++ docs/models/extras/exporttemplate.md | 8 ++++++++ netbox/extras/constants.py | 6 ++++++ netbox/extras/models/mixins.py | 19 +++++++++++++++---- 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/docs/models/extras/configtemplate.md b/docs/models/extras/configtemplate.md index 6b245e5e9..ac059bdc5 100644 --- a/docs/models/extras/configtemplate.md +++ b/docs/models/extras/configtemplate.md @@ -24,6 +24,14 @@ Jinja2 template code, if being defined locally rather than replicated from a dat A dictionary of any additional parameters to pass when instantiating the [Jinja2 environment](https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.Environment). Jinja2 supports various optional parameters which can be used to modify its default behavior. +The `undefined` and `finalize` Jinja environment parameters, which must reference a Python class or function, can define a dotted path to the desired resource. For example: + +```json +{ + "undefined": "jinja2.StrictUndefined" +} +``` + ### MIME Type !!! info "This field was introduced in NetBox v4.3." diff --git a/docs/models/extras/exporttemplate.md b/docs/models/extras/exporttemplate.md index 86e1ae04a..32ee5eabc 100644 --- a/docs/models/extras/exporttemplate.md +++ b/docs/models/extras/exporttemplate.md @@ -26,6 +26,14 @@ Jinja2 template code for rendering the exported data. A dictionary of any additional parameters to pass when instantiating the [Jinja2 environment](https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.Environment). Jinja2 supports various optional parameters which can be used to modify its default behavior. +The `undefined` and `finalize` Jinja environment parameters, which must reference a Python class or function, can define a dotted path to the desired resource. For example: + +```json +{ + "undefined": "jinja2.StrictUndefined" +} +``` + ### MIME Type The MIME type to indicate in the response when rendering the export template (optional). Defaults to `text/plain`. diff --git a/netbox/extras/constants.py b/netbox/extras/constants.py index 94f0b25ad..cadf20cfe 100644 --- a/netbox/extras/constants.py +++ b/netbox/extras/constants.py @@ -21,6 +21,12 @@ WEBHOOK_EVENT_TYPES = { JOB_ERRORED: 'job_ended', } +# Jinja environment parameters which support path imports +JINJA_ENV_PARAMS_WITH_PATH_IMPORT = ( + 'undefined', + 'finalize', +) + # Dashboard DEFAULT_DASHBOARD = [ { diff --git a/netbox/extras/models/mixins.py b/netbox/extras/models/mixins.py index eb017302a..d04220982 100644 --- a/netbox/extras/models/mixins.py +++ b/netbox/extras/models/mixins.py @@ -2,16 +2,17 @@ import importlib.abc import importlib.util import os import sys + from django.core.files.storage import storages from django.db import models -from django.utils.translation import gettext_lazy as _ from django.http import HttpResponse +from django.utils.module_loading import import_string +from django.utils.translation import gettext_lazy as _ -from extras.constants import DEFAULT_MIME_TYPE +from extras.constants import DEFAULT_MIME_TYPE, JINJA_ENV_PARAMS_WITH_PATH_IMPORT from extras.utils import filename_from_model, filename_from_object from utilities.jinja2 import render_jinja2 - __all__ = ( 'PythonModuleMixin', 'RenderTemplateMixin', @@ -125,12 +126,22 @@ class RenderTemplateMixin(models.Model): class_name=self.__class__ )) + def get_environment_params(self): + """ + Pre-processing of any defined Jinja environment parameters (e.g. to support path resolution). + """ + params = self.environment_params or {} + for name, value in params.items(): + if name in JINJA_ENV_PARAMS_WITH_PATH_IMPORT and type(value) is str: + params[name] = import_string(value) + return params + def render(self, context=None, queryset=None): """ Render the template with the provided context. The context is passed to the Jinja2 environment as a dictionary. """ context = self.get_context(context=context, queryset=queryset) - env_params = self.environment_params or {} + env_params = self.get_environment_params() output = render_jinja2(self.template_code, context, env_params, getattr(self, 'data_file', None)) # Replace CRLF-style line terminators