Просмотр исходного кода

Fixes 18208: Consolidate rendering configuration templates (#18604)

Alexander Haase 1 год назад
Родитель
Сommit
3e1cc0d7f3

+ 4 - 46
netbox/dcim/views.py

@@ -4,17 +4,15 @@ from django.core.paginator import EmptyPage, PageNotAnInteger
 from django.db import transaction
 from django.db.models import Prefetch
 from django.forms import ModelMultipleChoiceField, MultipleHiddenInput, modelformset_factory
-from django.http import HttpResponse
 from django.shortcuts import get_object_or_404, redirect, render
 from django.urls import reverse
 from django.utils.html import escape
 from django.utils.safestring import mark_safe
 from django.utils.translation import gettext_lazy as _
 from django.views.generic import View
-from jinja2.exceptions import TemplateError
 
 from circuits.models import Circuit, CircuitTermination
-from extras.views import ObjectConfigContextView
+from extras.views import ObjectConfigContextView, ObjectRenderConfigView
 from ipam.models import ASN, IPAddress, Prefix, VLANGroup
 from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
 from netbox.constants import DEFAULT_ACTION_PERMISSIONS
@@ -2253,54 +2251,14 @@ class DeviceConfigContextView(ObjectConfigContextView):
 
 
 @register_model_view(Device, 'render-config')
-class DeviceRenderConfigView(generic.ObjectView):
+class DeviceRenderConfigView(ObjectRenderConfigView):
     queryset = Device.objects.all()
-    template_name = 'dcim/device/render_config.html'
+    base_template = 'dcim/device/base.html'
     tab = ViewTab(
         label=_('Render Config'),
-        weight=2100
+        weight=2100,
     )
 
-    def get(self, request, **kwargs):
-        instance = self.get_object(**kwargs)
-        context = self.get_extra_context(request, instance)
-
-        # If a direct export has been requested, return the rendered template content as a
-        # downloadable file.
-        if request.GET.get('export'):
-            content = context['rendered_config'] or context['error_message']
-            response = HttpResponse(content, content_type='text')
-            filename = f"{instance.name or 'config'}.txt"
-            response['Content-Disposition'] = f'attachment; filename="{filename}"'
-            return response
-
-        return render(request, self.get_template_name(), {
-            'object': instance,
-            'tab': self.tab,
-            **context,
-        })
-
-    def get_extra_context(self, request, instance):
-        # Compile context data
-        context_data = instance.get_config_context()
-        context_data.update({'device': instance})
-
-        # Render the config template
-        rendered_config = None
-        error_message = None
-        if config_template := instance.get_config_template():
-            try:
-                rendered_config = config_template.render(context=context_data)
-            except TemplateError as e:
-                error_message = _("An error occurred while rendering the template: {error}").format(error=e)
-
-        return {
-            'config_template': config_template,
-            'context_data': context_data,
-            'rendered_config': rendered_config,
-            'error_message': error_message,
-        }
-
 
 @register_model_view(Device, 'virtual-machines')
 class DeviceVirtualMachinesView(generic.ObjectChildrenView):

+ 56 - 0
netbox/extras/views.py

@@ -10,6 +10,7 @@ from django.utils import timezone
 from django.utils.module_loading import import_string
 from django.utils.translation import gettext as _
 from django.views.generic import View
+from jinja2.exceptions import TemplateError
 
 from core.choices import ManagedFileRootPathChoices
 from core.forms import ManagedFileForm
@@ -885,6 +886,61 @@ class ConfigTemplateBulkSyncDataView(generic.BulkSyncDataView):
     queryset = ConfigTemplate.objects.all()
 
 
+class ObjectRenderConfigView(generic.ObjectView):
+    base_template = None
+    template_name = 'extras/object_render_config.html'
+
+    def get(self, request, **kwargs):
+        instance = self.get_object(**kwargs)
+        context = self.get_extra_context(request, instance)
+
+        # If a direct export has been requested, return the rendered template content as a
+        # downloadable file.
+        if request.GET.get('export'):
+            content = context['rendered_config'] or context['error_message']
+            response = HttpResponse(content, content_type='text')
+            filename = f"{instance.name or 'config'}.txt"
+            response['Content-Disposition'] = f'attachment; filename="{filename}"'
+            return response
+
+        return render(
+            request,
+            self.get_template_name(),
+            {
+                'object': instance,
+                'tab': self.tab,
+                **context,
+            },
+        )
+
+    def get_extra_context_data(self, request, instance):
+        return {
+            f'{instance._meta.model_name}': instance,
+        }
+
+    def get_extra_context(self, request, instance):
+        # Compile context data
+        context_data = instance.get_config_context()
+        context_data.update(self.get_extra_context_data(request, instance))
+
+        # Render the config template
+        rendered_config = None
+        error_message = None
+        if config_template := instance.get_config_template():
+            try:
+                rendered_config = config_template.render(context=context_data)
+            except TemplateError as e:
+                error_message = _("An error occurred while rendering the template: {error}").format(error=e)
+
+        return {
+            'base_template': self.base_template,
+            'config_template': config_template,
+            'context_data': context_data,
+            'rendered_config': rendered_config,
+            'error_message': error_message,
+        }
+
+
 #
 # Image attachments
 #

+ 3 - 2
netbox/templates/dcim/device/render_config.html → netbox/templates/extras/object_render_config.html

@@ -1,4 +1,5 @@
-{% extends 'dcim/device/base.html' %}
+{% extends base_template %}
+{% load helpers %}
 {% load static %}
 {% load i18n %}
 
@@ -67,7 +68,7 @@
         {% endif %}
       {% else %}
         <div class="alert alert-info">
-          {% trans "No configuration template has been assigned for this device." %}
+          {% trans "No configuration template has been assigned." %}
         </div>
       {% endif %}
     </div>

+ 0 - 75
netbox/templates/virtualization/virtualmachine/render_config.html

@@ -1,75 +0,0 @@
-{% extends 'virtualization/virtualmachine/base.html' %}
-{% load static %}
-{% load i18n %}
-
-{% block title %}{{ object }} - {% trans "Config" %}{% endblock %}
-
-{% block content %}
-  <div class="row">
-    <div class="col-5">
-      <div class="card">
-        <h2 class="card-header">{% trans "Config Template" %}</h2>
-        <table class="table table-hover attr-table">
-          <tr>
-            <th scope="row">{% trans "Config Template" %}</th>
-            <td>{{ config_template|linkify|placeholder }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Data Source" %}</th>
-            <td>{{ config_template.data_file.source|linkify|placeholder }}</td>
-          </tr>
-          <tr>
-            <th scope="row">{% trans "Data File" %}</th>
-            <td>{{ config_template.data_file|linkify|placeholder }}</td>
-          </tr>
-        </table>
-      </div>
-    </div>
-    <div class="col-7">
-      <div class="card">
-        <div class="accordion accordion-flush" id="renderConfig">
-          <div class="card-body">
-            <div class="accordion-item">
-              <h2 class="accordion-header" id="renderConfigHeading">
-                <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapsedRenderConfig" aria-expanded="false" aria-controls="collapsedRenderConfig">
-                  {% trans "Context Data" %}
-                </button>
-              </h2>
-              <div id="collapsedRenderConfig" class="accordion-collapse collapse" aria-labelledby="renderConfigHeading" data-bs-parent="#renderConfig">
-                <div class="accordion-body">
-                  <pre class="card-body">{{ context_data|pprint }}</pre>
-                </div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-  <div class="row">
-    <div class="col">
-      {% if config_template %}
-        {% if rendered_config %}
-          <div class="card">
-            <h2 class="card-header d-flex justify-content-between">
-              {% trans "Rendered Config" %}
-              <a href="?export=True" class="btn btn-primary lh-1" role="button">
-                <i class="mdi mdi-download" aria-hidden="true"></i> {% trans "Download" %}
-              </a>
-            </h2>
-            <pre class="card-body">{{ rendered_config }}</pre>
-          </div>
-        {% else %}
-          <div class="alert alert-warning">
-            <h4 class="alert-title mb-1">{% trans "Error rendering template" %}</h4>
-            {% trans error_message %}
-          </div>
-        {% endif %}
-      {% else %}
-        <div class="alert alert-info">
-          {% trans "No configuration template has been assigned for this virtual machine." %}
-        </div>
-      {% endif %}
-    </div>
-  </div>
-{% endblock %}

+ 4 - 46
netbox/virtualization/views.py

@@ -1,17 +1,15 @@
 from django.contrib import messages
 from django.db import transaction
 from django.db.models import Prefetch, Sum
-from django.http import HttpResponse
 from django.shortcuts import get_object_or_404, redirect, render
 from django.urls import reverse
 from django.utils.translation import gettext_lazy as _
-from jinja2.exceptions import TemplateError
 
 from dcim.filtersets import DeviceFilterSet
 from dcim.forms import DeviceFilterForm
 from dcim.models import Device
 from dcim.tables import DeviceTable
-from extras.views import ObjectConfigContextView
+from extras.views import ObjectConfigContextView, ObjectRenderConfigView
 from ipam.models import IPAddress
 from ipam.tables import InterfaceVLANTable, VLANTranslationRuleTable
 from netbox.constants import DEFAULT_ACTION_PERMISSIONS
@@ -427,54 +425,14 @@ class VirtualMachineConfigContextView(ObjectConfigContextView):
 
 
 @register_model_view(VirtualMachine, 'render-config')
-class VirtualMachineRenderConfigView(generic.ObjectView):
+class VirtualMachineRenderConfigView(ObjectRenderConfigView):
     queryset = VirtualMachine.objects.all()
-    template_name = 'virtualization/virtualmachine/render_config.html'
+    base_template = 'virtualization/virtualmachine/base.html'
     tab = ViewTab(
         label=_('Render Config'),
-        weight=2100
+        weight=2100,
     )
 
-    def get(self, request, **kwargs):
-        instance = self.get_object(**kwargs)
-        context = self.get_extra_context(request, instance)
-
-        # If a direct export has been requested, return the rendered template content as a
-        # downloadable file.
-        if request.GET.get('export'):
-            content = context['rendered_config'] or context['error_message']
-            response = HttpResponse(content, content_type='text')
-            filename = f"{instance.name or 'config'}.txt"
-            response['Content-Disposition'] = f'attachment; filename="{filename}"'
-            return response
-
-        return render(request, self.get_template_name(), {
-            'object': instance,
-            'tab': self.tab,
-            **context,
-        })
-
-    def get_extra_context(self, request, instance):
-        # Compile context data
-        context_data = instance.get_config_context()
-        context_data.update({'virtualmachine': instance})
-
-        # Render the config template
-        rendered_config = None
-        error_message = None
-        if config_template := instance.get_config_template():
-            try:
-                rendered_config = config_template.render(context=context_data)
-            except TemplateError as e:
-                error_message = _("An error occurred while rendering the template: {error}").format(error=e)
-
-        return {
-            'config_template': config_template,
-            'context_data': context_data,
-            'rendered_config': rendered_config,
-            'error_message': error_message,
-        }
-
 
 @register_model_view(VirtualMachine, 'add', detail=False)
 @register_model_view(VirtualMachine, 'edit')