mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-28 10:16:10 -06:00
Closes #19977: Denormalize device relationships on component models (#19984)
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, actions) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Waiting to run
CI / build (20.x, 3.10) (push) Has been cancelled
CI / build (20.x, 3.11) (push) Has been cancelled
CI / build (20.x, 3.12) (push) Has been cancelled
Some checks failed
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, actions) (push) Waiting to run
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Waiting to run
CI / build (20.x, 3.10) (push) Has been cancelled
CI / build (20.x, 3.11) (push) Has been cancelled
CI / build (20.x, 3.12) (push) Has been cancelled
* Closes #19977: Denormalize site, location, and rack for device components * Set blank=True on denormalized ForeignKeys * Populate denormalized field in test data * Ignore private fields when constructing test GraphQL requests
This commit is contained in:
parent
35b9d80819
commit
aa9ee0e5c6
@ -1515,34 +1515,34 @@ class DeviceComponentFilterSet(django_filters.FilterSet):
|
|||||||
label=_('Site group (slug)'),
|
label=_('Site group (slug)'),
|
||||||
)
|
)
|
||||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='device__site',
|
field_name='_site',
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
label=_('Site (ID)'),
|
label=_('Site (ID)'),
|
||||||
)
|
)
|
||||||
site = django_filters.ModelMultipleChoiceFilter(
|
site = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='device__site__slug',
|
field_name='_site__slug',
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label=_('Site name (slug)'),
|
label=_('Site name (slug)'),
|
||||||
)
|
)
|
||||||
location_id = django_filters.ModelMultipleChoiceFilter(
|
location_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='device__location',
|
field_name='_location',
|
||||||
queryset=Location.objects.all(),
|
queryset=Location.objects.all(),
|
||||||
label=_('Location (ID)'),
|
label=_('Location (ID)'),
|
||||||
)
|
)
|
||||||
location = django_filters.ModelMultipleChoiceFilter(
|
location = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='device__location__slug',
|
field_name='_location__slug',
|
||||||
queryset=Location.objects.all(),
|
queryset=Location.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label=_('Location (slug)'),
|
label=_('Location (slug)'),
|
||||||
)
|
)
|
||||||
rack_id = django_filters.ModelMultipleChoiceFilter(
|
rack_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='device__rack',
|
field_name='_rack',
|
||||||
queryset=Rack.objects.all(),
|
queryset=Rack.objects.all(),
|
||||||
label=_('Rack (ID)'),
|
label=_('Rack (ID)'),
|
||||||
)
|
)
|
||||||
rack = django_filters.ModelMultipleChoiceFilter(
|
rack = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='device__rack__name',
|
field_name='_rack__name',
|
||||||
queryset=Rack.objects.all(),
|
queryset=Rack.objects.all(),
|
||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
label=_('Rack (name)'),
|
label=_('Rack (name)'),
|
||||||
|
@ -0,0 +1,287 @@
|
|||||||
|
import django.db.models.deletion
|
||||||
|
from django.db import migrations, models
|
||||||
|
from django.db.models import OuterRef, Subquery
|
||||||
|
|
||||||
|
|
||||||
|
def populate_denormalized_data(apps, schema_editor):
|
||||||
|
Device = apps.get_model('dcim', 'Device')
|
||||||
|
component_models = (
|
||||||
|
apps.get_model('dcim', 'ConsolePort'),
|
||||||
|
apps.get_model('dcim', 'ConsoleServerPort'),
|
||||||
|
apps.get_model('dcim', 'PowerPort'),
|
||||||
|
apps.get_model('dcim', 'PowerOutlet'),
|
||||||
|
apps.get_model('dcim', 'Interface'),
|
||||||
|
apps.get_model('dcim', 'FrontPort'),
|
||||||
|
apps.get_model('dcim', 'RearPort'),
|
||||||
|
apps.get_model('dcim', 'DeviceBay'),
|
||||||
|
apps.get_model('dcim', 'ModuleBay'),
|
||||||
|
apps.get_model('dcim', 'InventoryItem'),
|
||||||
|
)
|
||||||
|
|
||||||
|
for model in component_models:
|
||||||
|
subquery = Device.objects.filter(pk=OuterRef('device_id'))
|
||||||
|
model.objects.update(
|
||||||
|
_site=Subquery(subquery.values('site_id')[:1]),
|
||||||
|
_location=Subquery(subquery.values('location_id')[:1]),
|
||||||
|
_rack=Subquery(subquery.values('rack_id')[:1]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('dcim', '0208_devicerole_uniqueness'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='consoleport',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='consoleport',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='consoleport',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='consoleserverport',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='consoleserverport',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='consoleserverport',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='devicebay',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='devicebay',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='devicebay',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='frontport',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='frontport',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='frontport',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='interface',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='interface',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='interface',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventoryitem',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventoryitem',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='inventoryitem',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='modulebay',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='modulebay',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='modulebay',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='poweroutlet',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='poweroutlet',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='poweroutlet',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='powerport',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='powerport',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='powerport',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rearport',
|
||||||
|
name='_location',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rearport',
|
||||||
|
name='_rack',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.rack'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rearport',
|
||||||
|
name='_site',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='dcim.site'
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.RunPython(populate_denormalized_data),
|
||||||
|
]
|
@ -65,6 +65,29 @@ class ComponentModel(NetBoxModel):
|
|||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Denormalized references replicated from the parent Device
|
||||||
|
_site = models.ForeignKey(
|
||||||
|
to='dcim.Site',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
_location = models.ForeignKey(
|
||||||
|
to='dcim.Location',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
_rack = models.ForeignKey(
|
||||||
|
to='dcim.Rack',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
related_name='+',
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
ordering = ('device', 'name')
|
ordering = ('device', 'name')
|
||||||
@ -100,6 +123,14 @@ class ComponentModel(NetBoxModel):
|
|||||||
"device": _("Components cannot be moved to a different device.")
|
"device": _("Components cannot be moved to a different device.")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
# Save denormalized references
|
||||||
|
self._site = self.device.site
|
||||||
|
self._location = self.device.location
|
||||||
|
self._rack = self.device.rack
|
||||||
|
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def parent_object(self):
|
def parent_object(self):
|
||||||
return self.device
|
return self.device
|
||||||
|
@ -3,13 +3,28 @@ import logging
|
|||||||
from django.db.models.signals import post_save, post_delete, pre_delete
|
from django.db.models.signals import post_save, post_delete, pre_delete
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from .choices import CableEndChoices, LinkStatusChoices
|
from dcim.choices import CableEndChoices, LinkStatusChoices
|
||||||
from .models import (
|
from .models import (
|
||||||
Cable, CablePath, CableTermination, Device, FrontPort, PathEndpoint, PowerPanel, Rack, Location, VirtualChassis,
|
Cable, CablePath, CableTermination, ConsolePort, ConsoleServerPort, Device, DeviceBay, FrontPort, Interface,
|
||||||
|
InventoryItem, ModuleBay, PathEndpoint, PowerOutlet, PowerPanel, PowerPort, Rack, RearPort, Location,
|
||||||
|
VirtualChassis,
|
||||||
)
|
)
|
||||||
from .models.cables import trace_paths
|
from .models.cables import trace_paths
|
||||||
from .utils import create_cablepath, rebuild_paths
|
from .utils import create_cablepath, rebuild_paths
|
||||||
|
|
||||||
|
COMPONENT_MODELS = (
|
||||||
|
ConsolePort,
|
||||||
|
ConsoleServerPort,
|
||||||
|
DeviceBay,
|
||||||
|
FrontPort,
|
||||||
|
Interface,
|
||||||
|
InventoryItem,
|
||||||
|
ModuleBay,
|
||||||
|
PowerOutlet,
|
||||||
|
PowerPort,
|
||||||
|
RearPort,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Location/rack/device assignment
|
# Location/rack/device assignment
|
||||||
@ -39,6 +54,20 @@ def handle_rack_site_change(instance, created, **kwargs):
|
|||||||
Device.objects.filter(rack=instance).update(site=instance.site, location=instance.location)
|
Device.objects.filter(rack=instance).update(site=instance.site, location=instance.location)
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=Device)
|
||||||
|
def handle_device_site_change(instance, created, **kwargs):
|
||||||
|
"""
|
||||||
|
Update child components to update the parent Site, Location, and Rack when a Device is saved.
|
||||||
|
"""
|
||||||
|
if not created:
|
||||||
|
for model in COMPONENT_MODELS:
|
||||||
|
model.objects.filter(device=instance).update(
|
||||||
|
_site=instance.site,
|
||||||
|
_location=instance.location,
|
||||||
|
_rack=instance.rack,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Virtual chassis
|
# Virtual chassis
|
||||||
#
|
#
|
||||||
|
@ -3367,9 +3367,36 @@ class ConsolePortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF
|
|||||||
ConsoleServerPort.objects.bulk_create(console_server_ports)
|
ConsoleServerPort.objects.bulk_create(console_server_ports)
|
||||||
|
|
||||||
console_ports = (
|
console_ports = (
|
||||||
ConsolePort(device=devices[0], module=modules[0], name='Console Port 1', label='A', description='First'),
|
ConsolePort(
|
||||||
ConsolePort(device=devices[1], module=modules[1], name='Console Port 2', label='B', description='Second'),
|
device=devices[0],
|
||||||
ConsolePort(device=devices[2], module=modules[2], name='Console Port 3', label='C', description='Third'),
|
module=modules[0],
|
||||||
|
name='Console Port 1',
|
||||||
|
label='A',
|
||||||
|
description='First',
|
||||||
|
_site=devices[0].site,
|
||||||
|
_location=devices[0].location,
|
||||||
|
_rack=devices[0].rack,
|
||||||
|
),
|
||||||
|
ConsolePort(
|
||||||
|
device=devices[1],
|
||||||
|
module=modules[1],
|
||||||
|
name='Console Port 2',
|
||||||
|
label='B',
|
||||||
|
description='Second',
|
||||||
|
_site=devices[1].site,
|
||||||
|
_location=devices[1].location,
|
||||||
|
_rack=devices[1].rack,
|
||||||
|
),
|
||||||
|
ConsolePort(
|
||||||
|
device=devices[2],
|
||||||
|
module=modules[2],
|
||||||
|
name='Console Port 3',
|
||||||
|
label='C',
|
||||||
|
description='Third',
|
||||||
|
_site=devices[2].site,
|
||||||
|
_location=devices[2].location,
|
||||||
|
_rack=devices[2].rack,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
ConsolePort.objects.bulk_create(console_ports)
|
ConsolePort.objects.bulk_create(console_ports)
|
||||||
|
|
||||||
@ -3581,13 +3608,34 @@ class ConsoleServerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeL
|
|||||||
|
|
||||||
console_server_ports = (
|
console_server_ports = (
|
||||||
ConsoleServerPort(
|
ConsoleServerPort(
|
||||||
device=devices[0], module=modules[0], name='Console Server Port 1', label='A', description='First'
|
device=devices[0],
|
||||||
|
module=modules[0],
|
||||||
|
name='Console Server Port 1',
|
||||||
|
label='A',
|
||||||
|
description='First',
|
||||||
|
_site=devices[0].site,
|
||||||
|
_location=devices[0].location,
|
||||||
|
_rack=devices[0].rack,
|
||||||
),
|
),
|
||||||
ConsoleServerPort(
|
ConsoleServerPort(
|
||||||
device=devices[1], module=modules[1], name='Console Server Port 2', label='B', description='Second'
|
device=devices[1],
|
||||||
|
module=modules[1],
|
||||||
|
name='Console Server Port 2',
|
||||||
|
label='B',
|
||||||
|
description='Second',
|
||||||
|
_site=devices[1].site,
|
||||||
|
_location=devices[1].location,
|
||||||
|
_rack=devices[1].rack,
|
||||||
),
|
),
|
||||||
ConsoleServerPort(
|
ConsoleServerPort(
|
||||||
device=devices[2], module=modules[2], name='Console Server Port 3', label='C', description='Third'
|
device=devices[2],
|
||||||
|
module=modules[2],
|
||||||
|
name='Console Server Port 3',
|
||||||
|
label='C',
|
||||||
|
description='Third',
|
||||||
|
_site=devices[2].site,
|
||||||
|
_location=devices[2].location,
|
||||||
|
_rack=devices[2].rack,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
ConsoleServerPort.objects.bulk_create(console_server_ports)
|
ConsoleServerPort.objects.bulk_create(console_server_ports)
|
||||||
@ -3807,6 +3855,9 @@ class PowerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
maximum_draw=100,
|
maximum_draw=100,
|
||||||
allocated_draw=50,
|
allocated_draw=50,
|
||||||
description='First',
|
description='First',
|
||||||
|
_site=devices[0].site,
|
||||||
|
_location=devices[0].location,
|
||||||
|
_rack=devices[0].rack,
|
||||||
),
|
),
|
||||||
PowerPort(
|
PowerPort(
|
||||||
device=devices[1],
|
device=devices[1],
|
||||||
@ -3816,6 +3867,9 @@ class PowerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
maximum_draw=200,
|
maximum_draw=200,
|
||||||
allocated_draw=100,
|
allocated_draw=100,
|
||||||
description='Second',
|
description='Second',
|
||||||
|
_site=devices[1].site,
|
||||||
|
_location=devices[1].location,
|
||||||
|
_rack=devices[1].rack,
|
||||||
),
|
),
|
||||||
PowerPort(
|
PowerPort(
|
||||||
device=devices[2],
|
device=devices[2],
|
||||||
@ -3825,6 +3879,9 @@ class PowerPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
maximum_draw=300,
|
maximum_draw=300,
|
||||||
allocated_draw=150,
|
allocated_draw=150,
|
||||||
description='Third',
|
description='Third',
|
||||||
|
_site=devices[2].site,
|
||||||
|
_location=devices[2].location,
|
||||||
|
_rack=devices[2].rack,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
PowerPort.objects.bulk_create(power_ports)
|
PowerPort.objects.bulk_create(power_ports)
|
||||||
@ -4053,6 +4110,9 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF
|
|||||||
description='First',
|
description='First',
|
||||||
color='ff0000',
|
color='ff0000',
|
||||||
status=PowerOutletStatusChoices.STATUS_ENABLED,
|
status=PowerOutletStatusChoices.STATUS_ENABLED,
|
||||||
|
_site=devices[0].site,
|
||||||
|
_location=devices[0].location,
|
||||||
|
_rack=devices[0].rack,
|
||||||
),
|
),
|
||||||
PowerOutlet(
|
PowerOutlet(
|
||||||
device=devices[1],
|
device=devices[1],
|
||||||
@ -4063,6 +4123,9 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF
|
|||||||
description='Second',
|
description='Second',
|
||||||
color='00ff00',
|
color='00ff00',
|
||||||
status=PowerOutletStatusChoices.STATUS_DISABLED,
|
status=PowerOutletStatusChoices.STATUS_DISABLED,
|
||||||
|
_site=devices[1].site,
|
||||||
|
_location=devices[1].location,
|
||||||
|
_rack=devices[1].rack,
|
||||||
),
|
),
|
||||||
PowerOutlet(
|
PowerOutlet(
|
||||||
device=devices[2],
|
device=devices[2],
|
||||||
@ -4073,6 +4136,9 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF
|
|||||||
description='Third',
|
description='Third',
|
||||||
color='0000ff',
|
color='0000ff',
|
||||||
status=PowerOutletStatusChoices.STATUS_FAULTY,
|
status=PowerOutletStatusChoices.STATUS_FAULTY,
|
||||||
|
_site=devices[2].site,
|
||||||
|
_location=devices[2].location,
|
||||||
|
_rack=devices[2].rack,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
PowerOutlet.objects.bulk_create(power_outlets)
|
PowerOutlet.objects.bulk_create(power_outlets)
|
||||||
@ -4381,13 +4447,19 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
poe_mode=InterfacePoEModeChoices.MODE_PSE,
|
poe_mode=InterfacePoEModeChoices.MODE_PSE,
|
||||||
poe_type=InterfacePoETypeChoices.TYPE_1_8023AF,
|
poe_type=InterfacePoETypeChoices.TYPE_1_8023AF,
|
||||||
vlan_translation_policy=vlan_translation_policies[0],
|
vlan_translation_policy=vlan_translation_policies[0],
|
||||||
|
_site=devices[0].site,
|
||||||
|
_location=devices[0].location,
|
||||||
|
_rack=devices[0].rack,
|
||||||
),
|
),
|
||||||
Interface(
|
Interface(
|
||||||
device=devices[1],
|
device=devices[1],
|
||||||
module=modules[1],
|
module=modules[1],
|
||||||
name='VC Chassis Interface',
|
name='VC Chassis Interface',
|
||||||
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
type=InterfaceTypeChoices.TYPE_1GE_SFP,
|
||||||
enabled=True
|
enabled=True,
|
||||||
|
_site=devices[1].site,
|
||||||
|
_location=devices[1].location,
|
||||||
|
_rack=devices[1].rack,
|
||||||
),
|
),
|
||||||
Interface(
|
Interface(
|
||||||
device=devices[2],
|
device=devices[2],
|
||||||
@ -4406,6 +4478,9 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
poe_mode=InterfacePoEModeChoices.MODE_PD,
|
poe_mode=InterfacePoEModeChoices.MODE_PD,
|
||||||
poe_type=InterfacePoETypeChoices.TYPE_1_8023AF,
|
poe_type=InterfacePoETypeChoices.TYPE_1_8023AF,
|
||||||
vlan_translation_policy=vlan_translation_policies[0],
|
vlan_translation_policy=vlan_translation_policies[0],
|
||||||
|
_site=devices[2].site,
|
||||||
|
_location=devices[2].location,
|
||||||
|
_rack=devices[2].rack,
|
||||||
),
|
),
|
||||||
Interface(
|
Interface(
|
||||||
device=devices[3],
|
device=devices[3],
|
||||||
@ -4424,6 +4499,9 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
poe_mode=InterfacePoEModeChoices.MODE_PSE,
|
poe_mode=InterfacePoEModeChoices.MODE_PSE,
|
||||||
poe_type=InterfacePoETypeChoices.TYPE_2_8023AT,
|
poe_type=InterfacePoETypeChoices.TYPE_2_8023AT,
|
||||||
vlan_translation_policy=vlan_translation_policies[1],
|
vlan_translation_policy=vlan_translation_policies[1],
|
||||||
|
_site=devices[3].site,
|
||||||
|
_location=devices[3].location,
|
||||||
|
_rack=devices[3].rack,
|
||||||
),
|
),
|
||||||
Interface(
|
Interface(
|
||||||
device=devices[4],
|
device=devices[4],
|
||||||
@ -4440,6 +4518,9 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
mode=InterfaceModeChoices.MODE_Q_IN_Q,
|
mode=InterfaceModeChoices.MODE_Q_IN_Q,
|
||||||
qinq_svlan=vlans[0],
|
qinq_svlan=vlans[0],
|
||||||
vlan_translation_policy=vlan_translation_policies[1],
|
vlan_translation_policy=vlan_translation_policies[1],
|
||||||
|
_site=devices[4].site,
|
||||||
|
_location=devices[4].location,
|
||||||
|
_rack=devices[4].rack,
|
||||||
),
|
),
|
||||||
Interface(
|
Interface(
|
||||||
device=devices[4],
|
device=devices[4],
|
||||||
@ -4450,7 +4531,10 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
mgmt_only=True,
|
mgmt_only=True,
|
||||||
tx_power=40,
|
tx_power=40,
|
||||||
mode=InterfaceModeChoices.MODE_Q_IN_Q,
|
mode=InterfaceModeChoices.MODE_Q_IN_Q,
|
||||||
qinq_svlan=vlans[1]
|
qinq_svlan=vlans[1],
|
||||||
|
_site=devices[4].site,
|
||||||
|
_location=devices[4].location,
|
||||||
|
_rack=devices[4].rack,
|
||||||
),
|
),
|
||||||
Interface(
|
Interface(
|
||||||
device=devices[4],
|
device=devices[4],
|
||||||
@ -4461,7 +4545,10 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
mgmt_only=False,
|
mgmt_only=False,
|
||||||
tx_power=40,
|
tx_power=40,
|
||||||
mode=InterfaceModeChoices.MODE_Q_IN_Q,
|
mode=InterfaceModeChoices.MODE_Q_IN_Q,
|
||||||
qinq_svlan=vlans[2]
|
qinq_svlan=vlans[2],
|
||||||
|
_site=devices[4].site,
|
||||||
|
_location=devices[4].location,
|
||||||
|
_rack=devices[4].rack,
|
||||||
),
|
),
|
||||||
Interface(
|
Interface(
|
||||||
device=devices[4],
|
device=devices[4],
|
||||||
@ -4470,7 +4557,10 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
rf_role=WirelessRoleChoices.ROLE_AP,
|
rf_role=WirelessRoleChoices.ROLE_AP,
|
||||||
rf_channel=WirelessChannelChoices.CHANNEL_24G_1,
|
rf_channel=WirelessChannelChoices.CHANNEL_24G_1,
|
||||||
rf_channel_frequency=2412,
|
rf_channel_frequency=2412,
|
||||||
rf_channel_width=22
|
rf_channel_width=22,
|
||||||
|
_site=devices[4].site,
|
||||||
|
_location=devices[4].location,
|
||||||
|
_rack=devices[4].rack,
|
||||||
),
|
),
|
||||||
Interface(
|
Interface(
|
||||||
device=devices[4],
|
device=devices[4],
|
||||||
@ -4479,7 +4569,10 @@ class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
rf_role=WirelessRoleChoices.ROLE_STATION,
|
rf_role=WirelessRoleChoices.ROLE_STATION,
|
||||||
rf_channel=WirelessChannelChoices.CHANNEL_5G_32,
|
rf_channel=WirelessChannelChoices.CHANNEL_5G_32,
|
||||||
rf_channel_frequency=5160,
|
rf_channel_frequency=5160,
|
||||||
rf_channel_width=20
|
rf_channel_width=20,
|
||||||
|
_site=devices[4].site,
|
||||||
|
_location=devices[4].location,
|
||||||
|
_rack=devices[4].rack,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
Interface.objects.bulk_create(interfaces)
|
Interface.objects.bulk_create(interfaces)
|
||||||
@ -4906,6 +4999,9 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
rear_port=rear_ports[0],
|
rear_port=rear_ports[0],
|
||||||
rear_port_position=1,
|
rear_port_position=1,
|
||||||
description='First',
|
description='First',
|
||||||
|
_site=devices[0].site,
|
||||||
|
_location=devices[0].location,
|
||||||
|
_rack=devices[0].rack,
|
||||||
),
|
),
|
||||||
FrontPort(
|
FrontPort(
|
||||||
device=devices[1],
|
device=devices[1],
|
||||||
@ -4917,6 +5013,9 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
rear_port=rear_ports[1],
|
rear_port=rear_ports[1],
|
||||||
rear_port_position=2,
|
rear_port_position=2,
|
||||||
description='Second',
|
description='Second',
|
||||||
|
_site=devices[1].site,
|
||||||
|
_location=devices[1].location,
|
||||||
|
_rack=devices[1].rack,
|
||||||
),
|
),
|
||||||
FrontPort(
|
FrontPort(
|
||||||
device=devices[2],
|
device=devices[2],
|
||||||
@ -4928,6 +5027,9 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
rear_port=rear_ports[2],
|
rear_port=rear_ports[2],
|
||||||
rear_port_position=3,
|
rear_port_position=3,
|
||||||
description='Third',
|
description='Third',
|
||||||
|
_site=devices[2].site,
|
||||||
|
_location=devices[2].location,
|
||||||
|
_rack=devices[2].rack,
|
||||||
),
|
),
|
||||||
FrontPort(
|
FrontPort(
|
||||||
device=devices[3],
|
device=devices[3],
|
||||||
@ -4936,6 +5038,9 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
type=PortTypeChoices.TYPE_FC,
|
type=PortTypeChoices.TYPE_FC,
|
||||||
rear_port=rear_ports[3],
|
rear_port=rear_ports[3],
|
||||||
rear_port_position=1,
|
rear_port_position=1,
|
||||||
|
_site=devices[3].site,
|
||||||
|
_location=devices[3].location,
|
||||||
|
_rack=devices[3].rack,
|
||||||
),
|
),
|
||||||
FrontPort(
|
FrontPort(
|
||||||
device=devices[3],
|
device=devices[3],
|
||||||
@ -4944,6 +5049,9 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
type=PortTypeChoices.TYPE_FC,
|
type=PortTypeChoices.TYPE_FC,
|
||||||
rear_port=rear_ports[4],
|
rear_port=rear_ports[4],
|
||||||
rear_port_position=1,
|
rear_port_position=1,
|
||||||
|
_site=devices[3].site,
|
||||||
|
_location=devices[3].location,
|
||||||
|
_rack=devices[3].rack,
|
||||||
),
|
),
|
||||||
FrontPort(
|
FrontPort(
|
||||||
device=devices[3],
|
device=devices[3],
|
||||||
@ -4952,6 +5060,9 @@ class FrontPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
type=PortTypeChoices.TYPE_FC,
|
type=PortTypeChoices.TYPE_FC,
|
||||||
rear_port=rear_ports[5],
|
rear_port=rear_ports[5],
|
||||||
rear_port_position=1,
|
rear_port_position=1,
|
||||||
|
_site=devices[3].site,
|
||||||
|
_location=devices[3].location,
|
||||||
|
_rack=devices[3].rack,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
FrontPort.objects.bulk_create(front_ports)
|
FrontPort.objects.bulk_create(front_ports)
|
||||||
@ -5168,6 +5279,9 @@ class RearPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilt
|
|||||||
color=ColorChoices.COLOR_RED,
|
color=ColorChoices.COLOR_RED,
|
||||||
positions=1,
|
positions=1,
|
||||||
description='First',
|
description='First',
|
||||||
|
_site=devices[0].site,
|
||||||
|
_location=devices[0].location,
|
||||||
|
_rack=devices[0].rack,
|
||||||
),
|
),
|
||||||
RearPort(
|
RearPort(
|
||||||
device=devices[1],
|
device=devices[1],
|
||||||
@ -5178,6 +5292,9 @@ class RearPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilt
|
|||||||
color=ColorChoices.COLOR_GREEN,
|
color=ColorChoices.COLOR_GREEN,
|
||||||
positions=2,
|
positions=2,
|
||||||
description='Second',
|
description='Second',
|
||||||
|
_site=devices[1].site,
|
||||||
|
_location=devices[1].location,
|
||||||
|
_rack=devices[1].rack,
|
||||||
),
|
),
|
||||||
RearPort(
|
RearPort(
|
||||||
device=devices[2],
|
device=devices[2],
|
||||||
@ -5188,10 +5305,40 @@ class RearPortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilt
|
|||||||
color=ColorChoices.COLOR_BLUE,
|
color=ColorChoices.COLOR_BLUE,
|
||||||
positions=3,
|
positions=3,
|
||||||
description='Third',
|
description='Third',
|
||||||
|
_site=devices[2].site,
|
||||||
|
_location=devices[2].location,
|
||||||
|
_rack=devices[2].rack,
|
||||||
|
),
|
||||||
|
RearPort(
|
||||||
|
device=devices[3],
|
||||||
|
name='Rear Port 4',
|
||||||
|
label='D',
|
||||||
|
type=PortTypeChoices.TYPE_FC,
|
||||||
|
positions=4,
|
||||||
|
_site=devices[3].site,
|
||||||
|
_location=devices[3].location,
|
||||||
|
_rack=devices[3].rack,
|
||||||
|
),
|
||||||
|
RearPort(
|
||||||
|
device=devices[3],
|
||||||
|
name='Rear Port 5',
|
||||||
|
label='E',
|
||||||
|
type=PortTypeChoices.TYPE_FC,
|
||||||
|
positions=5,
|
||||||
|
_site=devices[3].site,
|
||||||
|
_location=devices[3].location,
|
||||||
|
_rack=devices[3].rack,
|
||||||
|
),
|
||||||
|
RearPort(
|
||||||
|
device=devices[3],
|
||||||
|
name='Rear Port 6',
|
||||||
|
label='F',
|
||||||
|
type=PortTypeChoices.TYPE_FC,
|
||||||
|
positions=6,
|
||||||
|
_site=devices[3].site,
|
||||||
|
_location=devices[3].location,
|
||||||
|
_rack=devices[3].rack,
|
||||||
),
|
),
|
||||||
RearPort(device=devices[3], name='Rear Port 4', label='D', type=PortTypeChoices.TYPE_FC, positions=4),
|
|
||||||
RearPort(device=devices[3], name='Rear Port 5', label='E', type=PortTypeChoices.TYPE_FC, positions=5),
|
|
||||||
RearPort(device=devices[3], name='Rear Port 6', label='F', type=PortTypeChoices.TYPE_FC, positions=6),
|
|
||||||
)
|
)
|
||||||
RearPort.objects.bulk_create(rear_ports)
|
RearPort.objects.bulk_create(rear_ports)
|
||||||
|
|
||||||
@ -5550,9 +5697,33 @@ class DeviceBayTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFil
|
|||||||
Device.objects.bulk_create(devices)
|
Device.objects.bulk_create(devices)
|
||||||
|
|
||||||
device_bays = (
|
device_bays = (
|
||||||
DeviceBay(device=devices[0], name='Device Bay 1', label='A', description='First'),
|
DeviceBay(
|
||||||
DeviceBay(device=devices[1], name='Device Bay 2', label='B', description='Second'),
|
device=devices[0],
|
||||||
DeviceBay(device=devices[2], name='Device Bay 3', label='C', description='Third'),
|
name='Device Bay 1',
|
||||||
|
label='A',
|
||||||
|
description='First',
|
||||||
|
_site=devices[0].site,
|
||||||
|
_location=devices[0].location,
|
||||||
|
_rack=devices[0].rack,
|
||||||
|
),
|
||||||
|
DeviceBay(
|
||||||
|
device=devices[1],
|
||||||
|
name='Device Bay 2',
|
||||||
|
label='B',
|
||||||
|
description='Second',
|
||||||
|
_site=devices[1].site,
|
||||||
|
_location=devices[1].location,
|
||||||
|
_rack=devices[1].rack,
|
||||||
|
),
|
||||||
|
DeviceBay(
|
||||||
|
device=devices[2],
|
||||||
|
name='Device Bay 3',
|
||||||
|
label='C',
|
||||||
|
description='Third',
|
||||||
|
_site=devices[2].site,
|
||||||
|
_location=devices[2].location,
|
||||||
|
_rack=devices[2].rack,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
DeviceBay.objects.bulk_create(device_bays)
|
DeviceBay.objects.bulk_create(device_bays)
|
||||||
|
|
||||||
|
@ -470,6 +470,9 @@ class APIViewTestCases:
|
|||||||
elif type(field.type) is StrawberryOptional and type(field.type.of_type) is LazyType:
|
elif type(field.type) is StrawberryOptional and type(field.type.of_type) is LazyType:
|
||||||
fields_string += f'{field.name} {{ id }}\n'
|
fields_string += f'{field.name} {{ id }}\n'
|
||||||
elif hasattr(field, 'is_relation') and field.is_relation:
|
elif hasattr(field, 'is_relation') and field.is_relation:
|
||||||
|
# Ignore private fields
|
||||||
|
if field.name.startswith('_'):
|
||||||
|
continue
|
||||||
# Note: StrawberryField types do not have is_relation
|
# Note: StrawberryField types do not have is_relation
|
||||||
fields_string += f'{field.name} {{ id }}\n'
|
fields_string += f'{field.name} {{ id }}\n'
|
||||||
elif inspect.isclass(field.type) and issubclass(field.type, IPAddressFamilyType):
|
elif inspect.isclass(field.type) and issubclass(field.type, IPAddressFamilyType):
|
||||||
|
Loading…
Reference in New Issue
Block a user