Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/models/extras/configtemplate.md
Original file line number Diff line number Diff line change
Expand Up @@ -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."
Expand Down
8 changes: 8 additions & 0 deletions docs/models/extras/exporttemplate.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`.
Expand Down
6 changes: 6 additions & 0 deletions netbox/extras/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@
JOB_ERRORED: 'job_ended',
}

# Jinja environment parameters which support path imports
JINJA_ENV_PARAMS_WITH_PATH_IMPORT = (
'undefined',
'finalize',
)

# Dashboard
DEFAULT_DASHBOARD = [
{
Expand Down
19 changes: 15 additions & 4 deletions netbox/extras/models/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
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',
Expand Down Expand Up @@ -125,12 +126,22 @@ def get_context(self, context=None, queryset=None):
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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of questions here:

  1. Should we do any validation of value? E.g. make sure it's within a set of accepted values?
  2. I assume import_string() might raise some exceptions, especially around dotted-paths that don't exist. Is the intention to let those bubble up to the user?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. What would the valid values be? I don't think we have a way of knowing, unless we limited it to a very small, prescribed set of choices.
  2. Yes; exceptions will be raised to surface the invalid configuration.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.


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
Expand Down