add load/save values, fix filterset

This commit is contained in:
dreng
2023-05-06 22:57:12 +02:00
parent 7e2ffc575f
commit 9cc1607811
5 changed files with 88 additions and 27 deletions
+37 -1
View File
@@ -14,7 +14,7 @@ from netbox_topology_views.api.serializers import (
RoleImageSerializer,
TopologyDummySerializer,
)
from netbox_topology_views.models import RoleImage, IndividualOptions
from netbox_topology_views.models import RoleImage, IndividualOptions, CoordinateGroup, Coordinate
from netbox_topology_views.views import get_topology_data
from netbox_topology_views.utils import get_image_from_url, export_data_to_xml, get_query_settings
from netbox_topology_views.filters import DeviceFilterSet
@@ -50,6 +50,8 @@ class SaveCoordsViewSet(ReadOnlyModelViewSet):
if not actual_device:
return Response({"status": "invalid node_id in body"}, status=400)
# Storing coordinates in custom field is deprecated now.
# We preserve this for backwards compatibility.
try:
actual_device.custom_field_data["coordinates"] = "%s;%s" % (
x_coord,
@@ -61,6 +63,40 @@ class SaveCoordsViewSet(ReadOnlyModelViewSet):
{"status": "coords custom field could not be saved"}, status=500
)
# Default group named "default" must always exist in order to make sure
# that coordinate values can be stored even if no coordinate group has been
# selected. The default group will be added automatically if it does not exist.
try:
group = CoordinateGroup.objects.get(name="default")
except CoordinateGroup.DoesNotExist:
try:
group = CoordinateGroup(
name="default",
description="Automatically generated default group. If you delete "
"this group, all default coordinates are gone for good but "
"the group itself will be re-created."
)
group.save()
except:
return Response(
{"status": "Error while creating default group."}, status=500
)
try:
# Hen-and-egg-problem. Thanks, Django! By default, Django updates records that
# already exist and inserts otherwise. This does not work with our
# unique_together key if no pk is given. But: No record, no pk.
if not Coordinate.objects.filter(group=group, device=actual_device):
# Unique group/device pair does not exist. Prepare new data set
coords = Coordinate(group=group, device=actual_device, x=x_coord, y=y_coord)
else:
# Unique group/device pair already exists. Update data
coords = Coordinate(pk=Coordinate.objects.get(group=group, device=actual_device).pk, group=group, device=actual_device, x=x_coord, y=y_coord)
coords.save()
except:
return Response(
{"status": "Coordinates could not be saved."}, status=500
)
return Response({"status": "saved coords"})
class ExportTopoToXML(PermissionRequiredMixin, ViewSet):
+15 -5
View File
@@ -1,7 +1,7 @@
import django_filters
from dcim.choices import DeviceStatusChoices
from dcim.models import Device, DeviceRole, Location, Rack, Region, Site
from .models import Coordinate
from .models import Coordinate, CoordinateGroup
from django.db.models import Q
from netbox.filtersets import NetBoxModelFilterSet
from tenancy.filtersets import TenancyFilterSet
@@ -55,14 +55,24 @@ class DeviceFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
qs_filter = Q(name__icontains=value)
return queryset.filter(qs_filter)
class CoordinateFilterSet(NetBoxModelFilterSet):
class CoordinatesFilterSet(NetBoxModelFilterSet):
group = django_filters.ModelMultipleChoiceFilter(
queryset = CoordinateGroup.objects.all(),
)
device = django_filters.ModelMultipleChoiceFilter(
queryset = Device.objects.all(),
)
class Meta:
model = Coordinate
fields = ('id', 'group', 'device', 'x', 'y')
fields = ['id', 'group', 'device', 'x', 'y']
def search(self, queryset, name, value):
"""Perform the filtered search."""
if not value.strip():
return queryset
qs_filter = Q(group__icontains=value | Q(device__icontains=value))
return queryset.filter(qs_filter)
return queryset.filter(
Q(group__name__icontains=value) |
Q(device__name__icontains=value)
)
+6 -12
View File
@@ -162,27 +162,21 @@ class CoordinatesForm(NetBoxModelForm):
class CoordinatesFilterForm(NetBoxModelFilterSetForm):
model = Coordinate
fieldsets = (
(None, ('q', 'filter_id')),
('Coordinates', ('group', 'device', 'x', 'y'))
)
group = forms.ModelMultipleChoiceField(
queryset=CoordinateGroup.objects.all(),
required=False
)
device = DynamicModelChoiceField(
device = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False
)
id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False,
label=_("Device"),
query_params={
"location_id": "$location_id",
"region_id": "$region_id",
"site_id": "$site_id",
"role_id": "$device_role_id",
},
)
x = forms.IntegerField(
required=False
)
+1 -6
View File
@@ -121,7 +121,7 @@ class CoordinateGroup(NetBoxModel):
class Coordinate(NetBoxModel):
"""
Coordinates are being used to place devices in a topology view onto a certian
Coordinates are being used to place devices in a topology view onto a certain
position. Devices belong to one or more coordinate groups. They have to
be unique together.
"""
@@ -147,11 +147,6 @@ class Coordinate(NetBoxModel):
def get_absolute_url(self):
return reverse('plugins:netbox_topology_views:coordinate', args=[self.pk])
def set_xy_from_text_coords(self, coords: str):
xy = coords.split(';')
self.x = xy[0]
self.y = xy[1]
class IndividualOptions(NetBoxModel):
CHOICES = (
('interface', 'interface'),
+29 -3
View File
@@ -32,7 +32,7 @@ from wireless.models import WirelessLink
from netbox.views.generic import ObjectView, ObjectListView, ObjectEditView, ObjectDeleteView, ObjectChangeLogView
from netbox_topology_views.filters import DeviceFilterSet, CoordinateFilterSet
from netbox_topology_views.filters import DeviceFilterSet, CoordinatesFilterSet
from netbox_topology_views.forms import DeviceFilterForm, IndividualOptionsForm, CoordinateGroupsForm, CoordinatesForm, CoordinatesFilterForm
from netbox_topology_views.models import RoleImage, CoordinateGroup, Coordinate, IndividualOptions
from netbox_topology_views.tables import CoordinateGroupListTable, CoordinateListTable
@@ -156,8 +156,31 @@ def create_node(
node["href"] = device.get_absolute_url()
node["image"] = get_image_for_entity(device)
# Default group named "default" must always exist in order to make sure
# that coordinate values can be stored even if no coordinate group has been
# selected. The default group will be added automatically if it does not exist.
try:
group = CoordinateGroup.objects.get(name="default")
except CoordinateGroup.DoesNotExist:
try:
group = CoordinateGroup(
name="default",
description="Automatically generated default group. If you delete "
"this group, all default coordinates are gone for good but "
"the group itself will be re-created."
)
group.save()
except:
pass
node["physics"] = True
if "coordinates" in device.custom_field_data:
if Coordinate.objects.filter(group=group, device=device.pk).values('x') and Coordinate.objects.filter(group=group, device=device.pk).values('y'):
node["x"] = Coordinate.objects.get(group=group, device=device.pk).x
node["y"] = Coordinate.objects.get(group=group, device=device.pk).y
node["physics"] = False
elif "coordinates" in device.custom_field_data:
# We prefer the new Coordinate model but leave the deprecated method
# for now as fallback for compatibility reasons
if device.custom_field_data["coordinates"] is not None:
if ";" in device.custom_field_data["coordinates"]:
cords = device.custom_field_data["coordinates"].split(";")
@@ -166,6 +189,9 @@ def create_node(
node["physics"] = False
elif save_coords:
node["physics"] = False
elif save_coords:
node["physics"] = False
return node
@@ -772,7 +798,7 @@ class CoordinateListView(PermissionRequiredMixin, ObjectListView):
queryset = Coordinate.objects.all()
table = CoordinateListTable
template_name = 'netbox_topology_views/coordinate_list.html'
filterset = CoordinateFilterSet
filterset = CoordinatesFilterSet
filterset_form = CoordinatesFilterForm
class CoordinateEditView(PermissionRequiredMixin, ObjectEditView):