From a11bfd19612418a8a8c378502a02a90165c2f2c3 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 12:31:10 +0000 Subject: [PATCH] NetBox 4.7 compatibility Bump the supported NetBox range to 4.7.x (release 0.9.3) and fix issues found while verifying the plugin against a live NetBox 4.7.0 install. Verified against NetBox 4.7.0 (Django 6.1, django-tables2 3.0.1, PostgreSQL 16 with ltree, Python 3.12): migrations apply with no pending model changes, every plugin view/tab/HTMX table and REST endpoint returns 200, the canvas/dimension/background PATCH save paths work, and the OpenAPI schema and collectstatic run clean. No code changes were needed for the 4.7 breaking changes themselves -- the plugin does not use the renamed django-tables2 `querystring` tag, the removed `RelatedLinkColumn`, `registry['models']`, or MPTT-only Location/Region methods. Fixes found during that verification: - FloorplanFilterSet.search() filtered on `description`, which Floorplan does not have, so any `?q=` query against the REST API raised FieldError (HTTP 500). Search now matches site, location and assigned image names, and short-circuits on blank input. - Add FloorplanImageFilterSet and wire it to FloorplanImageViewSet, which previously had no filterset at all. - Annotate FloorplanImage.filename as returning str, silencing four drf-spectacular type-hint warnings emitted during schema generation. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01RDsiDcH4D2jfv2k9VjoNcX --- COMPATIBILITY.md | 1 + netbox-plugin.yaml | 12 ++++++++++++ netbox_floorplan/__init__.py | 4 ++-- netbox_floorplan/api/views.py | 1 + netbox_floorplan/filtersets.py | 27 +++++++++++++++++++++++++-- netbox_floorplan/models.py | 2 +- netbox_floorplan/version.py | 2 +- setup.py | 4 ++-- 8 files changed, 45 insertions(+), 8 deletions(-) diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md index 20f9cfc..1a6e8bf 100644 --- a/COMPATIBILITY.md +++ b/COMPATIBILITY.md @@ -2,6 +2,7 @@ | Release | Minimum NetBox Version | Maximum NetBox Version | |---------|------------------------|------------------------| +| 0.9.3 | 4.7.0 | 4.7.x | | 0.9.2 | 4.6.0 | 4.6.x | | 0.9.1 | 4.5.0 | 4.5.x | | 0.8.0 | 4.4.0 | 4.4.x | diff --git a/netbox-plugin.yaml b/netbox-plugin.yaml index 2fee72f..95617e2 100644 --- a/netbox-plugin.yaml +++ b/netbox-plugin.yaml @@ -1,6 +1,18 @@ version: 0.1 package_name: netbox-floorplan-plugin compatibility: + - release: 0.9.3 + netbox_min: 4.7.0 + netbox_max: 4.7.99 + - release: 0.9.2 + netbox_min: 4.6.0 + netbox_max: 4.6.99 + - release: 0.9.1 + netbox_min: 4.5.0 + netbox_max: 4.5.99 + - release: 0.8.0 + netbox_min: 4.4.0 + netbox_max: 4.4.99 - release: 0.7.0 netbox_min: 4.3.0 netbox_max: 4.3.99 diff --git a/netbox_floorplan/__init__.py b/netbox_floorplan/__init__.py index 665622a..dd643e1 100644 --- a/netbox_floorplan/__init__.py +++ b/netbox_floorplan/__init__.py @@ -9,8 +9,8 @@ class FloorplanConfig(PluginConfig): description = "" version = __version__ base_url = "floorplan" - min_version = "4.6.0" - max_version = "4.6.99" + min_version = "4.7.0" + max_version = "4.7.99" config = FloorplanConfig diff --git a/netbox_floorplan/api/views.py b/netbox_floorplan/api/views.py index 318e7e6..7c4d0bd 100644 --- a/netbox_floorplan/api/views.py +++ b/netbox_floorplan/api/views.py @@ -13,3 +13,4 @@ class FloorplanViewSet(NetBoxModelViewSet): class FloorplanImageViewSet(NetBoxModelViewSet): queryset = models.FloorplanImage.objects.prefetch_related('tags') serializer_class = FloorplanImageSerializer + filterset_class = filtersets.FloorplanImageFilterSet diff --git a/netbox_floorplan/filtersets.py b/netbox_floorplan/filtersets.py index 9cf541c..42b0298 100644 --- a/netbox_floorplan/filtersets.py +++ b/netbox_floorplan/filtersets.py @@ -1,5 +1,7 @@ +from django.db.models import Q + from netbox.filtersets import NetBoxModelFilterSet -from .models import Floorplan +from .models import Floorplan, FloorplanImage class FloorplanFilterSet(NetBoxModelFilterSet): @@ -8,4 +10,25 @@ class Meta: fields = ['id', 'site', 'location'] def search(self, queryset, name, value): - return queryset.filter(description__icontains=value) + if not value.strip(): + return queryset + return queryset.filter( + Q(site__name__icontains=value) | + Q(location__name__icontains=value) | + Q(assigned_image__name__icontains=value) + ) + + +class FloorplanImageFilterSet(NetBoxModelFilterSet): + class Meta: + model = FloorplanImage + fields = ['id', 'name', 'external_url'] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + return queryset.filter( + Q(name__icontains=value) | + Q(external_url__icontains=value) | + Q(comments__icontains=value) + ) diff --git a/netbox_floorplan/models.py b/netbox_floorplan/models.py index 759f51c..8ffe907 100644 --- a/netbox_floorplan/models.py +++ b/netbox_floorplan/models.py @@ -60,7 +60,7 @@ def size(self): return None @property - def filename(self): + def filename(self) -> str: filename = self.file.name.rsplit('/', 1)[-1] return filename diff --git a/netbox_floorplan/version.py b/netbox_floorplan/version.py index a2fecb4..c598173 100644 --- a/netbox_floorplan/version.py +++ b/netbox_floorplan/version.py @@ -1 +1 @@ -__version__ = "0.9.2" +__version__ = "0.9.3" diff --git a/setup.py b/setup.py index c0dba23..7e614b9 100644 --- a/setup.py +++ b/setup.py @@ -37,6 +37,6 @@ def get_version(rel_path): packages=find_packages(), include_package_data=True, zip_safe=False, - min_version="4.6.0", - max_version="4.6.99" + min_version="4.7.0", + max_version="4.7.99" )