mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 09:28:38 -06:00
Merge pull request #3550 from netbox-community/3259-cable-filters
3259 cable filters
This commit is contained in:
commit
63ad93afd0
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,3 +1,11 @@
|
|||||||
|
v2.6.6 (FUTURE)
|
||||||
|
|
||||||
|
## Enhancements
|
||||||
|
|
||||||
|
* [#3259](https://github.com/netbox-community/netbox/issues/3259) - Add `rack` and `site` filters for cables
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
v2.6.5 (2019-09-25)
|
v2.6.5 (2019-09-25)
|
||||||
|
|
||||||
## Enhancements
|
## Enhancements
|
||||||
@ -20,6 +28,8 @@ v2.6.5 (2019-09-25)
|
|||||||
* [#3540](https://github.com/netbox-community/netbox/issues/3540) - Fixed virtual machine interface edit with new inline vlan edit fields
|
* [#3540](https://github.com/netbox-community/netbox/issues/3540) - Fixed virtual machine interface edit with new inline vlan edit fields
|
||||||
* [#3543](https://github.com/netbox-community/netbox/issues/3543) - Added inline VLAN editing to virtual machine interfaces
|
* [#3543](https://github.com/netbox-community/netbox/issues/3543) - Added inline VLAN editing to virtual machine interfaces
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
v2.6.4 (2019-09-19)
|
v2.6.4 (2019-09-19)
|
||||||
|
|
||||||
## Enhancements
|
## Enhancements
|
||||||
@ -39,6 +49,8 @@ v2.6.4 (2019-09-19)
|
|||||||
* [#3513](https://github.com/netbox-community/netbox/issues/3513) - Fix assignment of tags when creating front/rear ports
|
* [#3513](https://github.com/netbox-community/netbox/issues/3513) - Fix assignment of tags when creating front/rear ports
|
||||||
* [#3514](https://github.com/netbox-community/netbox/issues/3514) - Label TextVar fields when rendering custom script forms
|
* [#3514](https://github.com/netbox-community/netbox/issues/3514) - Label TextVar fields when rendering custom script forms
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
v2.6.3 (2019-09-04)
|
v2.6.3 (2019-09-04)
|
||||||
|
|
||||||
## New Features
|
## New Features
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import django_filters
|
import django_filters
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
|
||||||
from extras.filters import CustomFieldFilterSet, LocalConfigContextFilter
|
from extras.filters import CustomFieldFilterSet, LocalConfigContextFilter
|
||||||
@ -931,13 +930,28 @@ class CableFilter(django_filters.FilterSet):
|
|||||||
color = django_filters.MultipleChoiceFilter(
|
color = django_filters.MultipleChoiceFilter(
|
||||||
choices=COLOR_CHOICES
|
choices=COLOR_CHOICES
|
||||||
)
|
)
|
||||||
device = django_filters.CharFilter(
|
device_id = MultiValueNumberFilter(
|
||||||
method='filter_connected_device',
|
method='filter_device'
|
||||||
field_name='name'
|
|
||||||
)
|
)
|
||||||
device_id = django_filters.CharFilter(
|
device = MultiValueNumberFilter(
|
||||||
method='filter_connected_device',
|
method='filter_device',
|
||||||
field_name='pk'
|
field_name='device__name'
|
||||||
|
)
|
||||||
|
rack_id = MultiValueNumberFilter(
|
||||||
|
method='filter_device',
|
||||||
|
field_name='device__rack_id'
|
||||||
|
)
|
||||||
|
rack = MultiValueNumberFilter(
|
||||||
|
method='filter_device',
|
||||||
|
field_name='device__rack__name'
|
||||||
|
)
|
||||||
|
site_id = MultiValueNumberFilter(
|
||||||
|
method='filter_device',
|
||||||
|
field_name='device__site_id'
|
||||||
|
)
|
||||||
|
site = MultiValueNumberFilter(
|
||||||
|
method='filter_device',
|
||||||
|
field_name='device__site__slug'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -949,15 +963,12 @@ class CableFilter(django_filters.FilterSet):
|
|||||||
return queryset
|
return queryset
|
||||||
return queryset.filter(label__icontains=value)
|
return queryset.filter(label__icontains=value)
|
||||||
|
|
||||||
def filter_connected_device(self, queryset, name, value):
|
def filter_device(self, queryset, name, value):
|
||||||
if not value.strip():
|
queryset = queryset.filter(
|
||||||
|
Q(**{'_termination_a_{}__in'.format(name): value}) |
|
||||||
|
Q(**{'_termination_b_{}__in'.format(name): value})
|
||||||
|
)
|
||||||
return queryset
|
return queryset
|
||||||
try:
|
|
||||||
device = Device.objects.get(**{name: value})
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
return queryset.none()
|
|
||||||
cable_pks = device.get_cables(pk_list=True)
|
|
||||||
return queryset.filter(pk__in=cable_pks)
|
|
||||||
|
|
||||||
|
|
||||||
class ConsoleConnectionFilter(django_filters.FilterSet):
|
class ConsoleConnectionFilter(django_filters.FilterSet):
|
||||||
|
46
netbox/dcim/migrations/0075_cable_devices.py
Normal file
46
netbox/dcim/migrations/0075_cable_devices.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
def cache_cable_devices(apps, schema_editor):
|
||||||
|
Cable = apps.get_model('dcim', 'Cable')
|
||||||
|
|
||||||
|
# Cache A/B termination devices on all existing Cables. Note that the custom save() method on Cable is not
|
||||||
|
# available during a migration, so we replicate its logic here.
|
||||||
|
for cable in Cable.objects.all():
|
||||||
|
|
||||||
|
termination_a_model = apps.get_model(cable.termination_a_type.app_label, cable.termination_a_type.model)
|
||||||
|
if hasattr(termination_a_model, 'device'):
|
||||||
|
termination_a = termination_a_model.objects.get(pk=cable.termination_a_id)
|
||||||
|
cable._termination_a_device = termination_a.device
|
||||||
|
|
||||||
|
termination_b_model = apps.get_model(cable.termination_b_type.app_label, cable.termination_b_type.model)
|
||||||
|
if hasattr(termination_b_model, 'device'):
|
||||||
|
termination_b = termination_b_model.objects.get(pk=cable.termination_b_id)
|
||||||
|
cable._termination_b_device = termination_b.device
|
||||||
|
|
||||||
|
cable.save()
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dcim', '0074_increase_field_length_platform_name_slug'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='cable',
|
||||||
|
name='_termination_a_device',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.Device'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='cable',
|
||||||
|
name='_termination_b_device',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.Device'),
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
code=cache_cable_devices,
|
||||||
|
reverse_code=migrations.RunPython.noop
|
||||||
|
),
|
||||||
|
]
|
@ -2781,6 +2781,22 @@ class Cable(ChangeLoggedModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
|
# Cache the associated device (where applicable) for the A and B terminations. This enables filtering of Cables by
|
||||||
|
# their associated Devices.
|
||||||
|
_termination_a_device = models.ForeignKey(
|
||||||
|
to=Device,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name='+',
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
_termination_b_device = models.ForeignKey(
|
||||||
|
to=Device,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name='+',
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
|
||||||
csv_headers = [
|
csv_headers = [
|
||||||
'termination_a_type', 'termination_a_id', 'termination_b_type', 'termination_b_id', 'type', 'status', 'label',
|
'termination_a_type', 'termination_a_id', 'termination_b_type', 'termination_b_id', 'type', 'status', 'label',
|
||||||
@ -2895,6 +2911,12 @@ class Cable(ChangeLoggedModel):
|
|||||||
if self.length and self.length_unit:
|
if self.length and self.length_unit:
|
||||||
self._abs_length = to_meters(self.length, self.length_unit)
|
self._abs_length = to_meters(self.length, self.length_unit)
|
||||||
|
|
||||||
|
# Store the parent Device for the A and B terminations (if applicable) to enable filtering
|
||||||
|
if hasattr(self.termination_a, 'device'):
|
||||||
|
self._termination_a_device = self.termination_a.device
|
||||||
|
if hasattr(self.termination_b, 'device'):
|
||||||
|
self._termination_b_device = self.termination_b.device
|
||||||
|
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
def to_csv(self):
|
def to_csv(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user