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

Closes #21929: Eliminate redundant object view templates (#21930)

Jeremy Stretch 1 месяц назад
Родитель
Сommit
1f9ed248bd
47 измененных файлов с 59 добавлено и 65 удалено
  1. 5 0
      netbox/dcim/views.py
  2. 14 0
      netbox/extras/views.py
  3. 5 0
      netbox/ipam/views.py
  4. 5 25
      netbox/netbox/views/generic/feature_views.py
  5. 2 2
      netbox/netbox/views/generic/object_views.py
  6. 0 1
      netbox/templates/dcim/cable.html
  7. 0 1
      netbox/templates/dcim/inventoryitemrole.html
  8. 0 1
      netbox/templates/dcim/macaddress.html
  9. 0 1
      netbox/templates/dcim/moduletypeprofile.html
  10. 0 1
      netbox/templates/dcim/racktype.html
  11. 0 1
      netbox/templates/dcim/virtualchassis.html
  12. 0 1
      netbox/templates/dcim/virtualdevicecontext.html
  13. 0 1
      netbox/templates/extras/configcontext.html
  14. 0 1
      netbox/templates/extras/configcontextprofile.html
  15. 0 1
      netbox/templates/extras/configtemplate.html
  16. 0 1
      netbox/templates/extras/customfield.html
  17. 0 1
      netbox/templates/extras/customfieldchoiceset.html
  18. 0 1
      netbox/templates/extras/customlink.html
  19. 0 1
      netbox/templates/extras/eventrule.html
  20. 0 1
      netbox/templates/extras/exporttemplate.html
  21. 0 1
      netbox/templates/extras/imageattachment.html
  22. 0 1
      netbox/templates/extras/notificationgroup.html
  23. 0 1
      netbox/templates/extras/savedfilter.html
  24. 0 1
      netbox/templates/extras/tableconfig.html
  25. 0 1
      netbox/templates/extras/tag.html
  26. 0 1
      netbox/templates/extras/webhook.html
  27. 0 1
      netbox/templates/ipam/routetarget.html
  28. 0 1
      netbox/templates/ipam/servicetemplate.html
  29. 0 1
      netbox/templates/ipam/vlantranslationpolicy.html
  30. 0 1
      netbox/templates/ipam/vlantranslationrule.html
  31. 0 1
      netbox/templates/ipam/vrf.html
  32. 0 1
      netbox/templates/tenancy/contact.html
  33. 0 1
      netbox/templates/tenancy/contactrole.html
  34. 0 1
      netbox/templates/vpn/ikepolicy.html
  35. 0 1
      netbox/templates/vpn/ikeproposal.html
  36. 0 1
      netbox/templates/vpn/ipsecpolicy.html
  37. 0 1
      netbox/templates/vpn/ipsecprofile.html
  38. 0 1
      netbox/templates/vpn/ipsecproposal.html
  39. 0 1
      netbox/templates/vpn/l2vpn.html
  40. 0 1
      netbox/templates/vpn/l2vpntermination.html
  41. 0 1
      netbox/templates/vpn/tunneltermination.html
  42. 0 1
      netbox/templates/wireless/wirelesslan.html
  43. 0 1
      netbox/templates/wireless/wirelesslink.html
  44. 2 0
      netbox/tenancy/views.py
  45. 16 0
      netbox/utilities/views.py
  46. 8 0
      netbox/vpn/views.py
  47. 2 0
      netbox/wireless/views.py

+ 5 - 0
netbox/dcim/views.py

@@ -4060,6 +4060,7 @@ class InventoryItemRoleListView(generic.ObjectListView):
 @register_model_view(InventoryItemRole)
 class InventoryItemRoleView(GetRelatedModelsMixin, generic.ObjectView):
     queryset = InventoryItemRole.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.InventoryItemRolePanel(),
@@ -4308,6 +4309,7 @@ class CableListView(generic.ObjectListView):
 @register_model_view(Cable)
 class CableView(generic.ObjectView):
     queryset = Cable.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.CablePanel(),
@@ -4458,6 +4460,7 @@ class VirtualChassisListView(generic.ObjectListView):
 @register_model_view(VirtualChassis)
 class VirtualChassisView(generic.ObjectView):
     queryset = VirtualChassis.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.VirtualChassisPanel(),
@@ -4883,6 +4886,7 @@ class VirtualDeviceContextListView(generic.ObjectListView):
 @register_model_view(VirtualDeviceContext)
 class VirtualDeviceContextView(GetRelatedModelsMixin, generic.ObjectView):
     queryset = VirtualDeviceContext.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.VirtualDeviceContextPanel(),
@@ -4968,6 +4972,7 @@ class MACAddressListView(generic.ObjectListView):
 @register_model_view(MACAddress)
 class MACAddressView(generic.ObjectView):
     queryset = MACAddress.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.MACAddressPanel(),

+ 14 - 0
netbox/extras/views.py

@@ -65,6 +65,7 @@ class CustomFieldListView(generic.ObjectListView):
 @register_model_view(CustomField)
 class CustomFieldView(generic.ObjectView):
     queryset = CustomField.objects.select_related('choice_set')
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.CustomFieldPanel(),
@@ -148,6 +149,7 @@ class CustomFieldChoiceSetListView(generic.ObjectListView):
 @register_model_view(CustomFieldChoiceSet)
 class CustomFieldChoiceSetView(generic.ObjectView):
     queryset = CustomFieldChoiceSet.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.CustomFieldChoiceSetPanel(),
@@ -231,6 +233,7 @@ class CustomLinkListView(generic.ObjectListView):
 @register_model_view(CustomLink)
 class CustomLinkView(generic.ObjectView):
     queryset = CustomLink.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.CustomLinkPanel(),
@@ -298,6 +301,7 @@ class ExportTemplateListView(generic.ObjectListView):
 @register_model_view(ExportTemplate)
 class ExportTemplateView(generic.ObjectView):
     queryset = ExportTemplate.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.ExportTemplatePanel(),
@@ -372,6 +376,7 @@ class SavedFilterListView(SharedObjectViewMixin, generic.ObjectListView):
 @register_model_view(SavedFilter)
 class SavedFilterView(SharedObjectViewMixin, generic.ObjectView):
     queryset = SavedFilter.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.SavedFilterPanel(),
@@ -443,6 +448,7 @@ class TableConfigListView(SharedObjectViewMixin, generic.ObjectListView):
 @register_model_view(TableConfig)
 class TableConfigView(SharedObjectViewMixin, generic.ObjectView):
     queryset = TableConfig.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.TableConfigPanel(),
@@ -545,6 +551,7 @@ class NotificationGroupListView(generic.ObjectListView):
 @register_model_view(NotificationGroup)
 class NotificationGroupView(generic.ObjectView):
     queryset = NotificationGroup.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.NotificationGroupPanel(),
@@ -738,6 +745,7 @@ class WebhookListView(generic.ObjectListView):
 @register_model_view(Webhook)
 class WebhookView(generic.ObjectView):
     queryset = Webhook.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.WebhookPanel(),
@@ -807,6 +815,7 @@ class EventRuleListView(generic.ObjectListView):
 @register_model_view(EventRule)
 class EventRuleView(generic.ObjectView):
     queryset = EventRule.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.EventRulePanel(),
@@ -878,6 +887,7 @@ class TagListView(generic.ObjectListView):
 @register_model_view(Tag)
 class TagView(generic.ObjectView):
     queryset = Tag.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.TagPanel(),
@@ -969,6 +979,7 @@ class ConfigContextProfileListView(generic.ObjectListView):
 @register_model_view(ConfigContextProfile)
 class ConfigContextProfileView(generic.ObjectView):
     queryset = ConfigContextProfile.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.ConfigContextProfilePanel(),
@@ -1043,6 +1054,7 @@ class ConfigContextListView(generic.ObjectListView):
 @register_model_view(ConfigContext)
 class ConfigContextView(generic.ObjectView):
     queryset = ConfigContext.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.ConfigContextPanel(),
@@ -1172,6 +1184,7 @@ class ConfigTemplateListView(generic.ObjectListView):
 @register_model_view(ConfigTemplate)
 class ConfigTemplateView(generic.ObjectView):
     queryset = ConfigTemplate.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.ConfigTemplatePanel(),
@@ -1302,6 +1315,7 @@ class ImageAttachmentListView(generic.ObjectListView):
 @register_model_view(ImageAttachment)
 class ImageAttachmentView(generic.ObjectView):
     queryset = ImageAttachment.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.ImageAttachmentPanel(),

+ 5 - 0
netbox/ipam/views.py

@@ -51,6 +51,7 @@ class VRFListView(generic.ObjectListView):
 @register_model_view(VRF)
 class VRFView(GetRelatedModelsMixin, generic.ObjectView):
     queryset = VRF.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.Layout(
         layout.Row(
             layout.Column(
@@ -172,6 +173,7 @@ class RouteTargetListView(generic.ObjectListView):
 @register_model_view(RouteTarget)
 class RouteTargetView(generic.ObjectView):
     queryset = RouteTarget.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.Layout(
         layout.Row(
             layout.Column(
@@ -1332,6 +1334,7 @@ class VLANTranslationPolicyListView(generic.ObjectListView):
 @register_model_view(VLANTranslationPolicy)
 class VLANTranslationPolicyView(generic.ObjectView):
     queryset = VLANTranslationPolicy.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.VLANTranslationPolicyPanel(),
@@ -1414,6 +1417,7 @@ class VLANTranslationRuleListView(generic.ObjectListView):
 @register_model_view(VLANTranslationRule)
 class VLANTranslationRuleView(generic.ObjectView):
     queryset = VLANTranslationRule.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.VLANTranslationRulePanel(),
@@ -1753,6 +1757,7 @@ class ServiceTemplateListView(generic.ObjectListView):
 @register_model_view(ServiceTemplate)
 class ServiceTemplateView(generic.ObjectView):
     queryset = ServiceTemplate.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.ServiceTemplatePanel(),

+ 5 - 25
netbox/netbox/views/generic/feature_views.py

@@ -17,7 +17,7 @@ from tenancy.forms import ContactAssignmentFilterForm
 from tenancy.models import ContactAssignment
 from tenancy.tables import ContactAssignmentTable
 from utilities.permissions import get_permission_for_model
-from utilities.views import ConditionalLoginRequiredMixin, GetReturnURLMixin, ViewTab
+from utilities.views import ConditionalLoginRequiredMixin, GetReturnURLMixin, ViewTab, get_default_template
 
 from .base import BaseMultiObjectView
 from .object_views import ObjectChildrenView
@@ -72,15 +72,10 @@ class ObjectChangeLogView(ConditionalLoginRequiredMixin, View):
         )
         objectchanges_table.configure(request)
 
-        # Default to using "<app>/<model>.html" as the template, if it exists. Otherwise,
-        # fall back to using base.html.
-        if self.base_template is None:
-            self.base_template = f"{model._meta.app_label}/{model._meta.model_name}.html"
-
         return render(request, 'extras/object_changelog.html', {
             'object': obj,
             'table': objectchanges_table,
-            'base_template': self.base_template,
+            'base_template': self.base_template or get_default_template(model),
             'tab': self.tab,
         })
 
@@ -107,15 +102,10 @@ class ObjectImageAttachmentsView(ConditionalLoginRequiredMixin, View):
             object_id=obj.pk,
         )
 
-        # Default to using "<app>/<model>.html" as the template, if it exists. Otherwise,
-        # fall back to using base.html.
-        if self.base_template is None:
-            self.base_template = f"{model._meta.app_label}/{model._meta.model_name}.html"
-
         return render(request, 'extras/object_imageattachments.html', {
             'object': obj,
             'image_attachments': image_attachments,
-            'base_template': self.base_template,
+            'base_template': self.base_template or get_default_template(model),
             'tab': self.tab,
         })
 
@@ -167,16 +157,11 @@ class ObjectJournalView(ConditionalLoginRequiredMixin, View):
         else:
             form = None
 
-        # Default to using "<app>/<model>.html" as the template, if it exists. Otherwise,
-        # fall back to using base.html.
-        if self.base_template is None:
-            self.base_template = f"{model._meta.app_label}/{model._meta.model_name}.html"
-
         return render(request, 'extras/object_journal.html', {
             'object': obj,
             'form': form,
             'table': journalentry_table,
-            'base_template': self.base_template,
+            'base_template': self.base_template or get_default_template(model),
             'tab': self.tab,
         })
 
@@ -222,15 +207,10 @@ class ObjectJobsView(ConditionalLoginRequiredMixin, View):
         jobs_table = JobTable(data=jobs, orderable=False)
         jobs_table.configure(request)
 
-        # Default to using "<app>/<model>.html" as the template, if it exists. Otherwise,
-        # fall back to using base.html.
-        if self.base_template is None:
-            self.base_template = f"{model._meta.app_label}/{model._meta.model_name}.html"
-
         return render(request, 'core/object_jobs.html', {
             'object': obj,
             'table': jobs_table,
-            'base_template': self.base_template,
+            'base_template': self.base_template or get_default_template(model),
             'tab': self.tab,
         })
 

+ 2 - 2
netbox/netbox/views/generic/object_views.py

@@ -22,7 +22,7 @@ from utilities.permissions import get_permission_for_model
 from utilities.querydict import normalize_querydict, prepare_cloned_fields
 from utilities.request import safe_for_redirect
 from utilities.tables import get_table_configs
-from utilities.views import GetReturnURLMixin, get_action_url
+from utilities.views import GetReturnURLMixin, get_action_url, get_default_template
 
 from .base import BaseObjectView
 from .mixins import ActionsMixin, TableMixin
@@ -163,7 +163,7 @@ class ObjectChildrenView(ObjectView, ActionsMixin, TableMixin):
             'object': instance,
             'model': self.child_model,
             'child_model': self.child_model,
-            'base_template': f'{instance._meta.app_label}/{instance._meta.model_name}.html',
+            'base_template': get_default_template(instance),
             'table': table,
             'table_config': f'{table.name}_config',
             'table_configs': get_table_configs(table, request.user),

+ 0 - 1
netbox/templates/dcim/cable.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/dcim/inventoryitemrole.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/dcim/macaddress.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/dcim/moduletypeprofile.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/dcim/racktype.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/dcim/virtualchassis.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/dcim/virtualdevicecontext.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/configcontext.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/configcontextprofile.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/configtemplate.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/customfield.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/customfieldchoiceset.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/customlink.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/eventrule.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/exporttemplate.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/imageattachment.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/notificationgroup.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/savedfilter.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/tableconfig.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/tag.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/extras/webhook.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/ipam/routetarget.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/ipam/servicetemplate.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/ipam/vlantranslationpolicy.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/ipam/vlantranslationrule.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/ipam/vrf.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/tenancy/contact.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/tenancy/contactrole.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/vpn/ikepolicy.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/vpn/ikeproposal.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/vpn/ipsecpolicy.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/vpn/ipsecprofile.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/vpn/ipsecproposal.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/vpn/l2vpn.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/vpn/l2vpntermination.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/vpn/tunneltermination.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/wireless/wirelesslan.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 0 - 1
netbox/templates/wireless/wirelesslink.html

@@ -1 +0,0 @@
-{% extends 'generic/object.html' %}

+ 2 - 0
netbox/tenancy/views.py

@@ -328,6 +328,7 @@ class ContactRoleListView(generic.ObjectListView):
 @register_model_view(ContactRole)
 class ContactRoleView(GetRelatedModelsMixin, generic.ObjectView):
     queryset = ContactRole.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             OrganizationalObjectPanel(),
@@ -402,6 +403,7 @@ class ContactListView(generic.ObjectListView):
 @register_model_view(Contact)
 class ContactView(generic.ObjectView):
     queryset = Contact.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.ContactPanel(),

+ 16 - 0
netbox/utilities/views.py

@@ -6,6 +6,8 @@ from django.contrib.auth.mixins import AccessMixin
 from django.core.exceptions import ImproperlyConfigured
 from django.db.models import QuerySet
 from django.http import HttpResponseForbidden
+from django.template import TemplateDoesNotExist
+from django.template.loader import get_template
 from django.urls import reverse
 from django.urls.exceptions import NoReverseMatch
 from django.utils.translation import gettext_lazy as _
@@ -29,6 +31,7 @@ __all__ = (
     'TokenConditionalLoginRequiredMixin',
     'ViewTab',
     'get_action_url',
+    'get_default_template',
     'get_viewname',
     'register_model_view',
 )
@@ -335,6 +338,19 @@ def get_action_url(model, action=None, rest_api=False, kwargs=None):
     return reverse(get_viewname(model, action, rest_api), kwargs=kwargs)
 
 
+def get_default_template(model):
+    """
+    Return the base template for the given model. If the presumed "{app}/{model}.html" template
+    does not exist, fall back to "generic/object.html".
+    """
+    template_name = f'{model._meta.app_label}/{model._meta.model_name}.html'
+    try:
+        get_template(template_name)
+        return template_name
+    except TemplateDoesNotExist:
+        return 'generic/object.html'
+
+
 def register_model_view(model, name='', path=None, detail=True, kwargs=None):
     """
     This decorator can be used to "attach" a view to any model in NetBox. This is typically used to inject

+ 8 - 0
netbox/vpn/views.py

@@ -208,6 +208,7 @@ class TunnelTerminationListView(generic.ObjectListView):
 @register_model_view(TunnelTermination)
 class TunnelTerminationView(generic.ObjectView):
     queryset = TunnelTermination.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.TunnelTerminationPanel(),
@@ -278,6 +279,7 @@ class IKEProposalListView(generic.ObjectListView):
 @register_model_view(IKEProposal)
 class IKEProposalView(generic.ObjectView):
     queryset = IKEProposal.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.IKEProposalPanel(),
@@ -351,6 +353,7 @@ class IKEPolicyListView(generic.ObjectListView):
 @register_model_view(IKEPolicy)
 class IKEPolicyView(GetRelatedModelsMixin, generic.ObjectView):
     queryset = IKEPolicy.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.IKEPolicyPanel(),
@@ -430,6 +433,7 @@ class IPSecProposalListView(generic.ObjectListView):
 @register_model_view(IPSecProposal)
 class IPSecProposalView(generic.ObjectView):
     queryset = IPSecProposal.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.IPSecProposalPanel(),
@@ -503,6 +507,7 @@ class IPSecPolicyListView(generic.ObjectListView):
 @register_model_view(IPSecPolicy)
 class IPSecPolicyView(GetRelatedModelsMixin, generic.ObjectView):
     queryset = IPSecPolicy.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.IPSecPolicyPanel(),
@@ -582,6 +587,7 @@ class IPSecProfileListView(generic.ObjectListView):
 @register_model_view(IPSecProfile)
 class IPSecProfileView(generic.ObjectView):
     queryset = IPSecProfile.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.IPSecProfilePanel(),
@@ -650,6 +656,7 @@ class L2VPNListView(generic.ObjectListView):
 @register_model_view(L2VPN)
 class L2VPNView(generic.ObjectView):
     queryset = L2VPN.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.Layout(
         layout.Row(
             layout.Column(
@@ -764,6 +771,7 @@ class L2VPNTerminationListView(generic.ObjectListView):
 @register_model_view(L2VPNTermination)
 class L2VPNTerminationView(generic.ObjectView):
     queryset = L2VPNTermination.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.L2VPNTerminationPanel(),

+ 2 - 0
netbox/wireless/views.py

@@ -143,6 +143,7 @@ class WirelessLANListView(generic.ObjectListView):
 @register_model_view(WirelessLAN)
 class WirelessLANView(generic.ObjectView):
     queryset = WirelessLAN.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.WirelessLANPanel(),
@@ -218,6 +219,7 @@ class WirelessLinkListView(generic.ObjectListView):
 @register_model_view(WirelessLink)
 class WirelessLinkView(generic.ObjectView):
     queryset = WirelessLink.objects.all()
+    template_name = 'generic/object.html'
     layout = layout.SimpleLayout(
         left_panels=[
             panels.WirelessLinkInterfacePanel('interface_a', title=_('Interface A')),