mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-27 02:48:38 -06:00
Move RenderMixin to extras.models.mixins, Rename RenderMixin to RenderTemplateMixin
This commit is contained in:
parent
fea7926197
commit
517c8016c3
@ -6,9 +6,9 @@ from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from extras.querysets import ConfigContextQuerySet
|
||||
from extras.models.mixins import RenderTemplateMixin
|
||||
from netbox.models import ChangeLoggedModel
|
||||
from netbox.models.features import (
|
||||
CloningMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin, RenderMixin)
|
||||
from netbox.models.features import CloningMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin
|
||||
from netbox.registry import registry
|
||||
from utilities.data import deepmerge
|
||||
|
||||
@ -208,7 +208,7 @@ class ConfigContextModel(models.Model):
|
||||
#
|
||||
|
||||
class ConfigTemplate(
|
||||
SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel, RenderMixin):
|
||||
SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel, RenderTemplateMixin):
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=100
|
||||
|
@ -3,9 +3,18 @@ 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 extras.constants import DEFAULT_MIME_TYPE
|
||||
from extras.utils import filename_from_model, filename_from_object
|
||||
from utilities.jinja2 import render_jinja2
|
||||
|
||||
|
||||
__all__ = (
|
||||
'PythonModuleMixin',
|
||||
'RenderTemplateMixin',
|
||||
)
|
||||
|
||||
|
||||
@ -66,3 +75,87 @@ class PythonModuleMixin:
|
||||
loader.exec_module(module)
|
||||
|
||||
return module
|
||||
|
||||
|
||||
class RenderTemplateMixin(models.Model):
|
||||
"""
|
||||
Enables support for rendering templates.
|
||||
"""
|
||||
template_code = models.TextField(
|
||||
verbose_name=_('template code'),
|
||||
help_text=_('Jinja template code.')
|
||||
)
|
||||
environment_params = models.JSONField(
|
||||
verbose_name=_('environment parameters'),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=dict,
|
||||
help_text=_(
|
||||
'Any <a href="{url}">additional parameters</a> to pass when constructing the Jinja2 environment.'
|
||||
).format(url='https://jinja.palletsprojects.com/en/stable/api/#jinja2.Environment')
|
||||
)
|
||||
mime_type = models.CharField(
|
||||
max_length=50,
|
||||
blank=True,
|
||||
verbose_name=_('MIME type'),
|
||||
help_text=_('Defaults to <code>{default}</code>').format(
|
||||
default=DEFAULT_MIME_TYPE
|
||||
),
|
||||
)
|
||||
file_name = models.CharField(
|
||||
max_length=200,
|
||||
blank=True,
|
||||
help_text=_('Filename to give to the rendered export file')
|
||||
)
|
||||
file_extension = models.CharField(
|
||||
verbose_name=_('file extension'),
|
||||
max_length=15,
|
||||
blank=True,
|
||||
help_text=_('Extension to append to the rendered filename')
|
||||
)
|
||||
as_attachment = models.BooleanField(
|
||||
verbose_name=_('as attachment'),
|
||||
default=True,
|
||||
help_text=_("Download file as attachment")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def get_context(self, context=None, queryset=None):
|
||||
raise NotImplementedError(_("{class_name} must implement a get_context() method.").format(
|
||||
class_name=self.__class__
|
||||
))
|
||||
|
||||
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 {}
|
||||
output = render_jinja2(self.template_code, context, env_params)
|
||||
|
||||
# Replace CRLF-style line terminators
|
||||
output = output.replace('\r\n', '\n')
|
||||
|
||||
return output
|
||||
|
||||
def render_to_response(self, context=None, queryset=None):
|
||||
output = self.render(context=context, queryset=queryset)
|
||||
mime_type = self.mime_type or DEFAULT_MIME_TYPE
|
||||
|
||||
# Build the response
|
||||
response = HttpResponse(output, content_type=mime_type)
|
||||
|
||||
if self.as_attachment:
|
||||
extension = f'.{self.file_extension}' if self.file_extension else ''
|
||||
if queryset:
|
||||
filename = self.file_name or filename_from_model(queryset.model)
|
||||
elif context:
|
||||
filename = self.file_name or filename_from_object(context)
|
||||
else:
|
||||
filename = self.file_name or "template"
|
||||
full_filename = f'{filename}{extension}'
|
||||
response['Content-Disposition'] = f'attachment; filename="{full_filename}"'
|
||||
|
||||
return response
|
||||
|
@ -16,11 +16,12 @@ from extras.choices import *
|
||||
from extras.conditions import ConditionSet
|
||||
from extras.constants import *
|
||||
from extras.utils import image_upload
|
||||
from extras.models.mixins import RenderTemplateMixin
|
||||
from netbox.config import get_config
|
||||
from netbox.events import get_event_type_choices
|
||||
from netbox.models import ChangeLoggedModel
|
||||
from netbox.models.features import (
|
||||
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin, RenderMixin
|
||||
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin
|
||||
)
|
||||
from utilities.html import clean_html
|
||||
from utilities.jinja2 import render_jinja2
|
||||
@ -381,7 +382,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
|
||||
}
|
||||
|
||||
|
||||
class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, RenderMixin):
|
||||
class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, RenderTemplateMixin):
|
||||
object_types = models.ManyToManyField(
|
||||
to='core.ObjectType',
|
||||
related_name='export_templates',
|
||||
|
@ -6,7 +6,6 @@ from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.validators import ValidationError
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.http import HttpResponse
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from taggit.managers import TaggableManager
|
||||
@ -14,12 +13,11 @@ from taggit.managers import TaggableManager
|
||||
from core.choices import JobStatusChoices, ObjectChangeActionChoices
|
||||
from core.models import ObjectType
|
||||
from extras.choices import *
|
||||
from extras.constants import CUSTOMFIELD_EMPTY_VALUES, DEFAULT_MIME_TYPE
|
||||
from extras.utils import is_taggable, filename_from_model, filename_from_object
|
||||
from extras.constants import CUSTOMFIELD_EMPTY_VALUES
|
||||
from extras.utils import is_taggable
|
||||
from netbox.config import get_config
|
||||
from netbox.registry import registry
|
||||
from netbox.signals import post_clean
|
||||
from utilities.jinja2 import render_jinja2
|
||||
from utilities.json import CustomFieldJSONEncoder
|
||||
from utilities.serialization import serialize_object
|
||||
from utilities.views import register_model_view
|
||||
@ -39,7 +37,6 @@ __all__ = (
|
||||
'JournalingMixin',
|
||||
'NotificationsMixin',
|
||||
'SyncedDataMixin',
|
||||
'RenderMixin',
|
||||
'TagsMixin',
|
||||
'register_models',
|
||||
)
|
||||
@ -340,89 +337,6 @@ class ExportTemplatesMixin(models.Model):
|
||||
abstract = True
|
||||
|
||||
|
||||
class RenderMixin(models.Model):
|
||||
"""
|
||||
Enables support for rendering templates.
|
||||
"""
|
||||
template_code = models.TextField(
|
||||
verbose_name=_('template code'),
|
||||
help_text=_('Jinja2 template code.')
|
||||
)
|
||||
environment_params = models.JSONField(
|
||||
verbose_name=_('environment parameters'),
|
||||
blank=True,
|
||||
null=True,
|
||||
default=dict,
|
||||
help_text=_(
|
||||
'Any <a href="https://jinja.palletsprojects.com/en/3.1.x/api/#jinja2.Environment">additional parameters</a>'
|
||||
' to pass when constructing the Jinja2 environment.'
|
||||
)
|
||||
)
|
||||
mime_type = models.CharField(
|
||||
max_length=50,
|
||||
blank=True,
|
||||
verbose_name=_('MIME type'),
|
||||
help_text=_('Defaults to <code>{default_mime_type}<code>').format(
|
||||
default_mime_type=DEFAULT_MIME_TYPE
|
||||
),
|
||||
)
|
||||
file_name = models.CharField(
|
||||
max_length=200,
|
||||
blank=True,
|
||||
help_text=_('Filename to give to the rendered export file')
|
||||
)
|
||||
file_extension = models.CharField(
|
||||
verbose_name=_('file extension'),
|
||||
max_length=15,
|
||||
blank=True,
|
||||
help_text=_('Extension to append to the rendered filename')
|
||||
)
|
||||
as_attachment = models.BooleanField(
|
||||
verbose_name=_('as attachment'),
|
||||
default=True,
|
||||
help_text=_("Download file as attachment")
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def get_context(self, context=None, queryset=None):
|
||||
raise NotImplementedError(_("{class_name} must implement a get_context() method.").format(
|
||||
class_name=self.__class__
|
||||
))
|
||||
|
||||
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 {}
|
||||
output = render_jinja2(self.template_code, context, env_params)
|
||||
|
||||
# Replace CRLF-style line terminators
|
||||
output = output.replace('\r\n', '\n')
|
||||
|
||||
return output
|
||||
|
||||
def render_to_response(self, context=None, queryset=None):
|
||||
output = self.render(context=context, queryset=queryset)
|
||||
mime_type = self.mime_type or DEFAULT_MIME_TYPE
|
||||
|
||||
# Build the response
|
||||
response = HttpResponse(output, content_type=mime_type)
|
||||
|
||||
if self.as_attachment:
|
||||
extension = f'.{self.file_extension}' if self.file_extension else ''
|
||||
if queryset:
|
||||
filename = self.file_name or filename_from_model(queryset.model)
|
||||
elif context:
|
||||
filename = self.file_name or filename_from_object(context)
|
||||
full_filename = f'{filename}{extension}'
|
||||
response['Content-Disposition'] = f'attachment; filename="{full_filename}"'
|
||||
|
||||
return response
|
||||
|
||||
|
||||
class ImageAttachmentsMixin(models.Model):
|
||||
"""
|
||||
Enables the assignments of ImageAttachments.
|
||||
|
Loading…
Reference in New Issue
Block a user