From ddef4965d6903c7ed539c52f66db714f4ebccf4b Mon Sep 17 00:00:00 2001 From: Sven Luethi Date: Tue, 11 Aug 2026 18:54:38 +0200 Subject: [PATCH] new file: netbox_dns_bridge/filtersets.py new file: netbox_dns_bridge/forms.py new file: netbox_dns_bridge/tables.py modified: netbox_dns_bridge/templates/netbox_dns_bridge/catz_overview.html modified: netbox_dns_bridge/views.py Change catz table to ObjectListView --- netbox_dns_bridge/filtersets.py | 29 ++++++++ netbox_dns_bridge/forms.py | 21 ++++++ netbox_dns_bridge/tables.py | 24 +++++++ .../netbox_dns_bridge/catz_overview.html | 70 ++++--------------- netbox_dns_bridge/views.py | 49 +++++-------- 5 files changed, 104 insertions(+), 89 deletions(-) create mode 100644 netbox_dns_bridge/filtersets.py create mode 100644 netbox_dns_bridge/forms.py create mode 100644 netbox_dns_bridge/tables.py diff --git a/netbox_dns_bridge/filtersets.py b/netbox_dns_bridge/filtersets.py new file mode 100644 index 0000000..b611931 --- /dev/null +++ b/netbox_dns_bridge/filtersets.py @@ -0,0 +1,29 @@ +import django_filters +from django.db.models import Q + +import netbox_dns.models +from netbox.filtersets import NetBoxModelFilterSet +from netbox_dns.choices import ZoneStatusChoices + + +class ZoneFilterSet(NetBoxModelFilterSet): + view = django_filters.ModelMultipleChoiceFilter( + field_name="view", + queryset=netbox_dns.models.View.objects.all(), + ) + status = django_filters.MultipleChoiceFilter( + choices=ZoneStatusChoices, + null_value=None, + ) + + class Meta: + model = netbox_dns.models.Zone + fields = ("id", "name", "view", "status", "catz_identifier") + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(name__icontains=value) + | Q(catz_identifier__name__icontains=value) + ) diff --git a/netbox_dns_bridge/forms.py b/netbox_dns_bridge/forms.py new file mode 100644 index 0000000..9987d40 --- /dev/null +++ b/netbox_dns_bridge/forms.py @@ -0,0 +1,21 @@ +from django import forms +from django.utils.translation import gettext_lazy as _ + +import netbox_dns.models +from netbox.forms import NetBoxModelFilterSetForm +from netbox_dns.choices import ZoneStatusChoices +from utilities.forms.fields import DynamicModelMultipleChoiceField + + +class CatalogZoneFilterForm(NetBoxModelFilterSetForm): + model = netbox_dns.models.Zone + + q = forms.CharField(required=False, label=_("Search")) + view = DynamicModelMultipleChoiceField( + queryset=netbox_dns.models.View.objects.all(), + required=False, + ) + status = forms.MultipleChoiceField( + choices=ZoneStatusChoices, + required=False, + ) diff --git a/netbox_dns_bridge/tables.py b/netbox_dns_bridge/tables.py new file mode 100644 index 0000000..b2ac39a --- /dev/null +++ b/netbox_dns_bridge/tables.py @@ -0,0 +1,24 @@ +import django_tables2 as tables +from django.utils.translation import gettext_lazy as _ + +import netbox_dns.models +from netbox.tables import NetBoxTable + + +class CatalogZoneTable(NetBoxTable): + name = tables.Column(linkify=True) + view = tables.Column( + accessor="view__name", + verbose_name=_("View"), + ) + status = tables.Column(verbose_name=_("Status")) + catz_identifier = tables.Column( + accessor="catz_identifier__name", + verbose_name=_("Catalog Zone Identifier"), + default="—", + ) + + class Meta(NetBoxTable.Meta): + model = netbox_dns.models.Zone + fields = ("name", "view", "status", "catz_identifier") + default_columns = ("name", "view", "status", "catz_identifier") diff --git a/netbox_dns_bridge/templates/netbox_dns_bridge/catz_overview.html b/netbox_dns_bridge/templates/netbox_dns_bridge/catz_overview.html index fe2554b..efb6c02 100644 --- a/netbox_dns_bridge/templates/netbox_dns_bridge/catz_overview.html +++ b/netbox_dns_bridge/templates/netbox_dns_bridge/catz_overview.html @@ -1,68 +1,22 @@ -{% extends 'base/layout.html' %} +{% extends 'generic/object_list.html' %} +{% load i18n %} -{% block title %}Catalog Zone Info{% endblock %} +{% block title %}{% trans "Catalog Zone Info" %}{% endblock %} {% block content %} -
+
- -
-
Catalog Zone SOA Serial Number
+
+
{% trans "Catalog Zone SOA Serial Number" %}
- - - - - - - - {% if soa_serial is not None %} - - - - {% else %} - - {% endif %} - -
Value
{{ soa_serial }}
Not yet initialized.
+ {% if soa_serial is not None %} + {{ soa_serial }} + {% else %} + {% trans "Not yet initialized." %} + {% endif %}
- - {% for view_name, rows in zones_grouped.items %} -
-
Zone Identifiers | {{ view_name }}
-
- - - - - - - - - - {% for z in rows %} - - - - - - {% empty %} - - {% endfor %} - -
ZoneActiveCatalog Zone Identifier
{{ z.name }}{{ z.active|yesno:"Yes,No" }}{{ z.catz_identifier|default:"—" }}
No zones in this view.
-
-
- {% empty %} -
-
Zone Identifiers
-
-

No zones found.

-
-
- {% endfor %} -
+{{ block.super }} {% endblock %} diff --git a/netbox_dns_bridge/views.py b/netbox_dns_bridge/views.py index 95834eb..f5e645f 100644 --- a/netbox_dns_bridge/views.py +++ b/netbox_dns_bridge/views.py @@ -1,50 +1,37 @@ -from collections import OrderedDict - from django.contrib.auth.decorators import user_passes_test from django.shortcuts import render from django.utils.decorators import method_decorator from django.views import View +import netbox_dns.models +from netbox.views.generic import ObjectListView + +from .filtersets import ZoneFilterSet +from .forms import CatalogZoneFilterForm from .models import IntegerKeyValueSetting, SeenTransferClients +from .tables import CatalogZoneTable @method_decorator( user_passes_test(lambda u: u.is_superuser), name="dispatch" ) -class CatzOverviewView(View): +class CatzOverviewView(ObjectListView): + queryset = netbox_dns.models.Zone.objects.select_related( + "view", "catz_identifier" + ).order_by("view__name", "name") + table = CatalogZoneTable + filterset = ZoneFilterSet + filterset_form = CatalogZoneFilterForm template_name = "netbox_dns_bridge/catz_overview.html" + actions = () - def get(self, request): - import netbox_dns.models - + def get_extra_context(self, request): + context = super().get_extra_context(request) soa_serial_obj = IntegerKeyValueSetting.objects.filter( key="catalog-zone-soa-serial" ).first() - soa_serial = soa_serial_obj.value if soa_serial_obj else None - - zones_grouped = OrderedDict() - for z in netbox_dns.models.Zone.objects.select_related( - "view", "catz_identifier" - ).order_by("view__name", "name"): - view_name = z.view.name if z.view else "" - view_display = view_name[0].upper() + view_name[1:] if view_name else "" - try: - catz_identifier = z.catz_identifier.name - except netbox_dns.models.Zone.catz_identifier.RelatedObjectDoesNotExist: - catz_identifier = None - zones_grouped.setdefault(view_display, []).append( - { - "name": z.name, - "active": z.active, - "catz_identifier": catz_identifier, - } - ) - - context = { - "soa_serial": soa_serial, - "zones_grouped": zones_grouped, - } - return render(request, self.template_name, context) + context["soa_serial"] = soa_serial_obj.value if soa_serial_obj else None + return context @method_decorator(