Merge branch 'main' into feature

This commit is contained in:
Jeremy Stretch
2025-05-01 09:45:38 -04:00
191 changed files with 10297 additions and 9102 deletions

View File

@@ -1390,10 +1390,75 @@ class ModuleFilterSet(NetBoxModelFilterSet):
lookup_expr='in',
label=_('Module bay (ID)'),
)
region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='device__site__region',
lookup_expr='in',
label=_('Region (ID)'),
)
region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(),
field_name='device__site__region',
lookup_expr='in',
to_field_name='slug',
label=_('Region (slug)'),
)
site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
field_name='device__site__group',
lookup_expr='in',
label=_('Site group (ID)'),
)
site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(),
field_name='device__site__group',
lookup_expr='in',
to_field_name='slug',
label=_('Site group (slug)'),
)
site_id = django_filters.ModelMultipleChoiceFilter(
field_name='device__site',
queryset=Site.objects.all(),
label=_('Site (ID)'),
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='device__site__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label=_('Site name (slug)'),
)
location_id = django_filters.ModelMultipleChoiceFilter(
field_name='device__location',
queryset=Location.objects.all(),
label=_('Location (ID)'),
)
location = django_filters.ModelMultipleChoiceFilter(
field_name='device__location__slug',
queryset=Location.objects.all(),
to_field_name='slug',
label=_('Location (slug)'),
)
rack_id = django_filters.ModelMultipleChoiceFilter(
field_name='device__rack',
queryset=Rack.objects.all(),
label=_('Rack (ID)'),
)
rack = django_filters.ModelMultipleChoiceFilter(
field_name='device__rack__name',
queryset=Rack.objects.all(),
to_field_name='name',
label=_('Rack (name)'),
)
device_id = django_filters.ModelMultipleChoiceFilter(
queryset=Device.objects.all(),
label=_('Device (ID)'),
)
device = django_filters.ModelMultipleChoiceFilter(
field_name='device__name',
queryset=Device.objects.all(),
to_field_name='name',
label=_('Device (name)'),
)
status = django_filters.MultipleChoiceFilter(
choices=ModuleStatusChoices,
null_value=None

View File

@@ -121,11 +121,11 @@ class DeviceBayBulkCreateForm(DeviceBulkAddComponentForm):
class InventoryItemBulkCreateForm(
form_from_model(InventoryItem, ['role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered']),
form_from_model(InventoryItem, ['status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered']),
DeviceBulkAddComponentForm
):
model = InventoryItem
field_order = (
'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered',
'name', 'label', 'status', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered',
'description', 'tags',
)

View File

@@ -41,7 +41,6 @@ class InterfaceCommonForm(forms.Form):
def clean(self):
super().clean()
parent_field = 'device' if 'device' in self.cleaned_data else 'virtual_machine'
if 'tagged_vlans' in self.fields.keys():
tagged_vlans = self.cleaned_data.get('tagged_vlans') if self.is_bound else \
@@ -61,6 +60,12 @@ class InterfaceCommonForm(forms.Form):
"or they must be global"
).format(vlans=', '.join(invalid_vlans))
})
# Validate mode change
if self.instance.pk and (self.instance.mode != self.cleaned_data['mode']):
if 'untagged_vlan' not in self.cleaned_data and self.instance.untagged_vlan is not None:
self.instance.untagged_vlan = None
if 'tagged_vlans' not in self.cleaned_data and self.instance.tagged_vlans is not None:
self.instance.tagged_vlans.clear()
class ModuleCommonForm(forms.Form):

View File

@@ -959,8 +959,56 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxMo
model = Module
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')),
FieldSet('manufacturer_id', 'module_type_id', 'status', 'serial', 'asset_tag', name=_('Hardware')),
)
device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
required=False,
query_params={
'site_id': '$site_id',
'location_id': '$location_id',
'rack_id': '$rack_id',
},
label=_('Device')
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
required=False,
label=_('Region')
)
site_group_id = DynamicModelMultipleChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
label=_('Site group')
)
site_id = DynamicModelMultipleChoiceField(
queryset=Site.objects.all(),
required=False,
query_params={
'region_id': '$region_id',
'group_id': '$site_group_id',
},
label=_('Site')
)
location_id = DynamicModelMultipleChoiceField(
queryset=Location.objects.all(),
required=False,
query_params={
'site_id': '$site_id',
},
label=_('Location')
)
rack_id = DynamicModelMultipleChoiceField(
queryset=Rack.objects.all(),
required=False,
label=_('Rack'),
null_option='None',
query_params={
'site_id': '$site_id',
'location_id': '$location_id',
}
)
manufacturer_id = DynamicModelMultipleChoiceField(
queryset=Manufacturer.objects.all(),
required=False,

View File

@@ -993,7 +993,7 @@ class ComponentTemplateForm(forms.ModelForm):
class ModularComponentTemplateForm(ComponentTemplateForm):
device_type = DynamicModelChoiceField(
label=_('Device type'),
queryset=DeviceType.objects.all().all(),
queryset=DeviceType.objects.all(),
required=False,
context={
'parent': 'manufacturer',
@@ -1008,6 +1008,16 @@ class ModularComponentTemplateForm(ComponentTemplateForm):
}
)
fieldsets = (
FieldSet(
TabbedGroups(
FieldSet('device_type', name=_('Device Type')),
FieldSet('module_type', name=_('Module Type')),
),
'name', 'label', 'type', 'description'
),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -1024,10 +1034,6 @@ class ModularComponentTemplateForm(ComponentTemplateForm):
class ConsolePortTemplateForm(ModularComponentTemplateForm):
fieldsets = (
FieldSet('device_type', 'module_type', 'name', 'label', 'type', 'description'),
)
class Meta:
model = ConsolePortTemplate
fields = [
@@ -1036,10 +1042,6 @@ class ConsolePortTemplateForm(ModularComponentTemplateForm):
class ConsoleServerPortTemplateForm(ModularComponentTemplateForm):
fieldsets = (
FieldSet('device_type', 'module_type', 'name', 'label', 'type', 'description'),
)
class Meta:
model = ConsoleServerPortTemplate
fields = [
@@ -1050,7 +1052,11 @@ class ConsoleServerPortTemplateForm(ModularComponentTemplateForm):
class PowerPortTemplateForm(ModularComponentTemplateForm):
fieldsets = (
FieldSet(
'device_type', 'module_type', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description',
TabbedGroups(
FieldSet('device_type', name=_('Device Type')),
FieldSet('module_type', name=_('Module Type')),
),
'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description',
),
)
@@ -1072,7 +1078,13 @@ class PowerOutletTemplateForm(ModularComponentTemplateForm):
)
fieldsets = (
FieldSet('device_type', 'module_type', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description'),
FieldSet(
TabbedGroups(
FieldSet('device_type', name=_('Device Type')),
FieldSet('module_type', name=_('Module Type')),
),
'name', 'label', 'type', 'power_port', 'feed_leg', 'description',
),
)
class Meta:
@@ -1095,7 +1107,11 @@ class InterfaceTemplateForm(ModularComponentTemplateForm):
fieldsets = (
FieldSet(
'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'bridge',
TabbedGroups(
FieldSet('device_type', name=_('Device Type')),
FieldSet('module_type', name=_('Module Type')),
),
'name', 'label', 'type', 'enabled', 'mgmt_only', 'description', 'bridge',
),
FieldSet('poe_mode', 'poe_type', name=_('PoE')),
FieldSet('rf_role', name=_('Wireless')),
@@ -1122,8 +1138,11 @@ class FrontPortTemplateForm(ModularComponentTemplateForm):
fieldsets = (
FieldSet(
'device_type', 'module_type', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position',
'description',
TabbedGroups(
FieldSet('device_type', name=_('Device Type')),
FieldSet('module_type', name=_('Module Type')),
),
'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description',
),
)
@@ -1137,7 +1156,13 @@ class FrontPortTemplateForm(ModularComponentTemplateForm):
class RearPortTemplateForm(ModularComponentTemplateForm):
fieldsets = (
FieldSet('device_type', 'module_type', 'name', 'label', 'type', 'color', 'positions', 'description'),
FieldSet(
TabbedGroups(
FieldSet('device_type', name=_('Device Type')),
FieldSet('module_type', name=_('Module Type')),
),
'name', 'label', 'type', 'color', 'positions', 'description',
),
)
class Meta:
@@ -1149,7 +1174,13 @@ class RearPortTemplateForm(ModularComponentTemplateForm):
class ModuleBayTemplateForm(ModularComponentTemplateForm):
fieldsets = (
FieldSet('device_type', 'module_type', 'name', 'label', 'position', 'description'),
FieldSet(
TabbedGroups(
FieldSet('device_type', name=_('Device Type')),
FieldSet('module_type', name=_('Module Type')),
),
'name', 'label', 'position', 'description',
),
)
class Meta:

View File

@@ -4,7 +4,7 @@ from django.utils.translation import gettext_lazy as _
from dcim.models import *
from netbox.forms import NetBoxModelForm
from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField
from utilities.forms.rendering import FieldSet
from utilities.forms.rendering import FieldSet, TabbedGroups
from utilities.forms.widgets import APISelect
from . import model_forms
@@ -118,7 +118,13 @@ class FrontPortTemplateCreateForm(ComponentCreateForm, model_forms.FrontPortTemp
# Override fieldsets from FrontPortTemplateForm to omit rear_port_position
fieldsets = (
FieldSet('device_type', 'module_type', 'name', 'label', 'type', 'color', 'rear_port', 'description'),
FieldSet(
TabbedGroups(
FieldSet('device_type', name=_('Device Type')),
FieldSet('module_type', name=_('Module Type')),
),
'name', 'label', 'type', 'color', 'rear_port', 'description',
),
)
class Meta(model_forms.FrontPortTemplateForm.Meta):

View File

@@ -159,7 +159,7 @@ class ModuleBayTemplateImportForm(forms.ModelForm):
class Meta:
model = ModuleBayTemplate
fields = [
'device_type', 'name', 'label', 'position', 'description',
'device_type', 'module_type', 'name', 'label', 'position', 'description',
]

View File

@@ -3,7 +3,6 @@ import itertools
from django.contrib.contenttypes.fields import GenericForeignKey
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Sum
from django.dispatch import Signal
from django.utils.translation import gettext_lazy as _
@@ -774,9 +773,28 @@ class CablePath(models.Model):
Return a tuple containing the sum of the length of each cable in the path
and a flag indicating whether the length is definitive.
"""
cable_ct = ObjectType.objects.get_for_model(Cable).pk
# Pre-cache cable lengths by ID
cable_ids = self.get_cable_ids()
cables = Cable.objects.filter(id__in=cable_ids, _abs_length__isnull=False)
total_length = cables.aggregate(total=Sum('_abs_length'))['total']
cables = {
cable['pk']: cable['_abs_length']
for cable in Cable.objects.filter(id__in=cable_ids, _abs_length__isnull=False).values('pk', '_abs_length')
}
# Iterate through each set of nodes in the path. For cables, add the length of the longest cable to the total
# length of the path.
total_length = 0
for node_set in self.path:
hop_length = 0
for node in node_set:
ct, pk = decompile_path_node(node)
if ct != cable_ct:
break # Not a cable
if pk in cables and cables[pk] > hop_length:
hop_length = cables[pk]
total_length += hop_length
is_definitive = len(cables) == len(cable_ids)
return total_length, is_definitive

View File

@@ -732,3 +732,8 @@ class RackReservation(PrimaryModel):
@property
def unit_list(self):
return array_to_string(self.units)
def to_objectchange(self, action):
objectchange = super().to_objectchange(action)
objectchange.related_object = self.rack
return objectchange

View File

@@ -2859,15 +2859,23 @@ class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests):
addresses = IPAddress.objects.filter(address__family=4)
params = {'primary_ip4_id': [addresses[0].pk, addresses[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip4': [str(addresses[0].address), str(addresses[1].address)]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip4_id': [addresses[2].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
params = {'primary_ip4': [str(addresses[2].address)]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
def test_primary_ip6(self):
addresses = IPAddress.objects.filter(address__family=6)
params = {'primary_ip6_id': [addresses[0].pk, addresses[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip6': [str(addresses[0].address), str(addresses[1].address)]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip6_id': [addresses[2].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
params = {'primary_ip6': [str(addresses[2].address)]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
def test_virtual_chassis_id(self):
params = {'virtual_chassis_id': [VirtualChassis.objects.first().pk]}
@@ -2961,6 +2969,29 @@ class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests):
@classmethod
def setUpTestData(cls):
regions = (
Region(name='Region 1', slug='region-1'),
Region(name='Region 2', slug='region-2'),
Region(name='Region 3', slug='region-3'),
)
for region in regions:
region.save()
groups = (
SiteGroup(name='Site Group 1', slug='site-group-1'),
SiteGroup(name='Site Group 2', slug='site-group-2'),
SiteGroup(name='Site Group 3', slug='site-group-3'),
)
for group in groups:
group.save()
sites = Site.objects.bulk_create((
Site(name='Site 1', slug='site-1', region=regions[0], group=groups[0]),
Site(name='Site 2', slug='site-2', region=regions[1], group=groups[1]),
Site(name='Site 3', slug='site-3', region=regions[2], group=groups[2]),
Site(name='Site X', slug='site-x'),
))
manufacturers = (
Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
@@ -2968,11 +2999,66 @@ class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests):
)
Manufacturer.objects.bulk_create(manufacturers)
devices = (
create_test_device('Test Device 1'),
create_test_device('Test Device 2'),
create_test_device('Test Device 3'),
device_types = (
DeviceType(manufacturer=manufacturers[0], model='Device Type 1', slug='device-type-1'),
DeviceType(manufacturer=manufacturers[1], model='Device Type 2', slug='device-type-2'),
DeviceType(manufacturer=manufacturers[2], model='Device Type 3', slug='device-type-3'),
)
DeviceType.objects.bulk_create(device_types)
roles = (
DeviceRole(name='Device Role 1', slug='device-role-1'),
DeviceRole(name='Device Role 2', slug='device-role-2'),
DeviceRole(name='Device Role 3', slug='device-role-3'),
)
for role in roles:
role.save()
locations = (
Location(name='Location 1', slug='location-1', site=sites[0]),
Location(name='Location 2', slug='location-2', site=sites[1]),
Location(name='Location 3', slug='location-3', site=sites[2]),
)
for location in locations:
location.save()
racks = (
Rack(name='Rack 1', site=sites[0]),
Rack(name='Rack 2', site=sites[1]),
Rack(name='Rack 3', site=sites[2]),
)
Rack.objects.bulk_create(racks)
devices = (
Device(
name='Test Device 1',
device_type=device_types[0],
role=roles[0],
site=sites[0],
location=locations[0],
rack=racks[0],
status='active',
),
Device(
name='Test Device 2',
device_type=device_types[1],
role=roles[1],
site=sites[1],
location=locations[1],
rack=racks[1],
status='planned',
),
Device(
name='Test Device 3',
device_type=device_types[2],
role=roles[2],
site=sites[2],
location=locations[2],
rack=racks[2],
status='offline',
),
)
Device.objects.bulk_create(devices)
module_types = (
ModuleType(manufacturer=manufacturers[0], model='Module Type 1'),
@@ -3120,6 +3206,41 @@ class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'asset_tag': ['A', 'B']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_region(self):
regions = Region.objects.all()[:2]
params = {'region_id': [regions[0].pk, regions[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
params = {'region': [regions[0].slug, regions[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
def test_site_group(self):
site_groups = SiteGroup.objects.all()[:2]
params = {'site_group_id': [site_groups[0].pk, site_groups[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
params = {'site_group': [site_groups[0].slug, site_groups[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
def test_site(self):
sites = Site.objects.all()[:2]
params = {'site_id': [sites[0].pk, sites[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
params = {'site': [sites[0].slug, sites[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
def test_location(self):
locations = Location.objects.all()[:2]
params = {'location_id': [locations[0].pk, locations[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
params = {'location': [locations[0].slug, locations[1].slug]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
def test_rack(self):
racks = Rack.objects.all()[:2]
params = {'rack_id': [racks[0].pk, racks[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
params = {'rack': [racks[0].name, racks[1].name]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
class ConsolePortTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests):
queryset = ConsolePort.objects.all()
@@ -6722,15 +6843,23 @@ class VirtualDeviceContextTestCase(TestCase, ChangeLoggedFilterSetTests):
addresses = IPAddress.objects.filter(address__family=4)
params = {'primary_ip4_id': [addresses[0].pk, addresses[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip4': [str(addresses[0].address), str(addresses[1].address)]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip4_id': [addresses[2].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
params = {'primary_ip4': [str(addresses[2].address)]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
def test_primary_ip6(self):
addresses = IPAddress.objects.filter(address__family=6)
params = {'primary_ip6_id': [addresses[0].pk, addresses[1].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip6': [str(addresses[0].address), str(addresses[1].address)]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
params = {'primary_ip6_id': [addresses[2].pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
params = {'primary_ip6': [str(addresses[2].address)]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
class MACAddressTestCase(TestCase, ChangeLoggedFilterSetTests):

View File

@@ -1217,6 +1217,13 @@ front-ports:
- name: Front Port 3
type: 8p8c
rear_port: Rear Port 3
module-bays:
- name: Module Bay 1
position: 1
- name: Module Bay 2
position: 2
- name: Module Bay 3
position: 3
"""
# Create the manufacturer
@@ -1234,6 +1241,7 @@ front-ports:
'dcim.add_interfacetemplate',
'dcim.add_frontporttemplate',
'dcim.add_rearporttemplate',
'dcim.add_modulebaytemplate',
)
form_data = {
@@ -1288,6 +1296,11 @@ front-ports:
self.assertEqual(fp1.rear_port, rp1)
self.assertEqual(fp1.rear_port_position, 1)
self.assertEqual(module_type.modulebaytemplates.count(), 3)
mb1 = ModuleBayTemplate.objects.first()
self.assertEqual(mb1.name, 'Module Bay 1')
self.assertEqual(mb1.position, '1')
def test_export_objects(self):
url = reverse('dcim:moduletype_list')
self.add_permissions('dcim.view_moduletype')

View File

@@ -22,6 +22,7 @@ from utilities.paginator import EnhancedPaginator, get_paginate_count
from utilities.permissions import get_permission_for_model
from utilities.query import count_related
from utilities.query_functions import CollateAsChar
from utilities.request import safe_for_redirect
from utilities.views import (
GetRelatedModelsMixin, GetReturnURLMixin, ObjectPermissionRequiredMixin, ViewTab, register_model_view
)
@@ -279,7 +280,7 @@ class RegionDeleteView(generic.ObjectDeleteView):
queryset = Region.objects.all()
@register_model_view(Region, 'bulk_import', detail=False)
@register_model_view(Region, 'bulk_import', path='import', detail=False)
class RegionBulkImportView(generic.BulkImportView):
queryset = Region.objects.all()
model_form = forms.RegionImportForm
@@ -405,7 +406,7 @@ class SiteGroupDeleteView(generic.ObjectDeleteView):
queryset = SiteGroup.objects.all()
@register_model_view(SiteGroup, 'bulk_import', detail=False)
@register_model_view(SiteGroup, 'bulk_import', path='import', detail=False)
class SiteGroupBulkImportView(generic.BulkImportView):
queryset = SiteGroup.objects.all()
model_form = forms.SiteGroupImportForm
@@ -496,7 +497,7 @@ class SiteDeleteView(generic.ObjectDeleteView):
queryset = Site.objects.all()
@register_model_view(Site, 'bulk_import', detail=False)
@register_model_view(Site, 'bulk_import', path='import', detail=False)
class SiteBulkImportView(generic.BulkImportView):
queryset = Site.objects.all()
model_form = forms.SiteImportForm
@@ -594,7 +595,7 @@ class LocationDeleteView(generic.ObjectDeleteView):
queryset = Location.objects.all()
@register_model_view(Location, 'bulk_import', detail=False)
@register_model_view(Location, 'bulk_import', path='import', detail=False)
class LocationBulkImportView(generic.BulkImportView):
queryset = Location.objects.all()
model_form = forms.LocationImportForm
@@ -663,7 +664,7 @@ class RackRoleDeleteView(generic.ObjectDeleteView):
queryset = RackRole.objects.all()
@register_model_view(RackRole, 'bulk_import', detail=False)
@register_model_view(RackRole, 'bulk_import', path='import', detail=False)
class RackRoleBulkImportView(generic.BulkImportView):
queryset = RackRole.objects.all()
model_form = forms.RackRoleImportForm
@@ -724,7 +725,7 @@ class RackTypeDeleteView(generic.ObjectDeleteView):
queryset = RackType.objects.all()
@register_model_view(RackType, 'bulk_import', detail=False)
@register_model_view(RackType, 'bulk_import', path='import', detail=False)
class RackTypeBulkImportView(generic.BulkImportView):
queryset = RackType.objects.all()
model_form = forms.RackTypeImportForm
@@ -903,7 +904,7 @@ class RackDeleteView(generic.ObjectDeleteView):
queryset = Rack.objects.all()
@register_model_view(Rack, 'bulk_import', detail=False)
@register_model_view(Rack, 'bulk_import', path='import', detail=False)
class RackBulkImportView(generic.BulkImportView):
queryset = Rack.objects.all()
model_form = forms.RackImportForm
@@ -960,7 +961,7 @@ class RackReservationDeleteView(generic.ObjectDeleteView):
queryset = RackReservation.objects.all()
@register_model_view(RackReservation, 'bulk_import', detail=False)
@register_model_view(RackReservation, 'bulk_import', path='import', detail=False)
class RackReservationImportView(generic.BulkImportView):
queryset = RackReservation.objects.all()
model_form = forms.RackReservationImportForm
@@ -1031,7 +1032,7 @@ class ManufacturerDeleteView(generic.ObjectDeleteView):
queryset = Manufacturer.objects.all()
@register_model_view(Manufacturer, 'bulk_import', detail=False)
@register_model_view(Manufacturer, 'bulk_import', path='import', detail=False)
class ManufacturerBulkImportView(generic.BulkImportView):
queryset = Manufacturer.objects.all()
model_form = forms.ManufacturerImportForm
@@ -1252,7 +1253,7 @@ class DeviceTypeInventoryItemsView(DeviceTypeComponentsView):
)
@register_model_view(DeviceType, 'bulk_import', detail=False)
@register_model_view(DeviceType, 'bulk_import', path='import', detail=False)
class DeviceTypeImportView(generic.BulkImportView):
additional_permissions = [
'dcim.add_devicetype',
@@ -1522,7 +1523,7 @@ class ModuleTypeModuleBaysView(ModuleTypeComponentsView):
)
@register_model_view(ModuleType, 'bulk_import', detail=False)
@register_model_view(ModuleType, 'bulk_import', path='import', detail=False)
class ModuleTypeImportView(generic.BulkImportView):
additional_permissions = [
'dcim.add_moduletype',
@@ -1533,6 +1534,7 @@ class ModuleTypeImportView(generic.BulkImportView):
'dcim.add_interfacetemplate',
'dcim.add_frontporttemplate',
'dcim.add_rearporttemplate',
'dcim.add_modulebaytemplate',
]
queryset = ModuleType.objects.all()
model_form = forms.ModuleTypeImportForm
@@ -1544,6 +1546,7 @@ class ModuleTypeImportView(generic.BulkImportView):
'interfaces': forms.InterfaceTemplateImportForm,
'rear-ports': forms.RearPortTemplateImportForm,
'front-ports': forms.FrontPortTemplateImportForm,
'module-bays': forms.ModuleBayTemplateImportForm,
}
def prep_related_object_data(self, parent, data):
@@ -2018,7 +2021,7 @@ class DeviceRoleDeleteView(generic.ObjectDeleteView):
queryset = DeviceRole.objects.all()
@register_model_view(DeviceRole, 'bulk_import', detail=False)
@register_model_view(DeviceRole, 'bulk_import', path='import', detail=False)
class DeviceRoleBulkImportView(generic.BulkImportView):
queryset = DeviceRole.objects.all()
model_form = forms.DeviceRoleImportForm
@@ -2082,7 +2085,7 @@ class PlatformDeleteView(generic.ObjectDeleteView):
queryset = Platform.objects.all()
@register_model_view(Platform, 'bulk_import', detail=False)
@register_model_view(Platform, 'bulk_import', path='import', detail=False)
class PlatformBulkImportView(generic.BulkImportView):
queryset = Platform.objects.all()
model_form = forms.PlatformImportForm
@@ -2365,7 +2368,7 @@ class DeviceVirtualMachinesView(generic.ObjectChildrenView):
return self.child_model.objects.restrict(request.user, 'view').filter(cluster=parent.cluster, device=parent)
@register_model_view(Device, 'bulk_import', detail=False)
@register_model_view(Device, 'bulk_import', path='import', detail=False)
class DeviceBulkImportView(generic.BulkImportView):
queryset = Device.objects.all()
model_form = forms.DeviceImportForm
@@ -2438,7 +2441,7 @@ class ModuleDeleteView(generic.ObjectDeleteView):
queryset = Module.objects.all()
@register_model_view(Module, 'bulk_import', detail=False)
@register_model_view(Module, 'bulk_import', path='import', detail=False)
class ModuleBulkImportView(generic.BulkImportView):
queryset = Module.objects.all()
model_form = forms.ModuleImportForm
@@ -2499,7 +2502,7 @@ class ConsolePortDeleteView(generic.ObjectDeleteView):
queryset = ConsolePort.objects.all()
@register_model_view(ConsolePort, 'bulk_import', detail=False)
@register_model_view(ConsolePort, 'bulk_import', path='import', detail=False)
class ConsolePortBulkImportView(generic.BulkImportView):
queryset = ConsolePort.objects.all()
model_form = forms.ConsolePortImportForm
@@ -2574,7 +2577,7 @@ class ConsoleServerPortDeleteView(generic.ObjectDeleteView):
queryset = ConsoleServerPort.objects.all()
@register_model_view(ConsoleServerPort, 'bulk_import', detail=False)
@register_model_view(ConsoleServerPort, 'bulk_import', path='import', detail=False)
class ConsoleServerPortBulkImportView(generic.BulkImportView):
queryset = ConsoleServerPort.objects.all()
model_form = forms.ConsoleServerPortImportForm
@@ -2649,7 +2652,7 @@ class PowerPortDeleteView(generic.ObjectDeleteView):
queryset = PowerPort.objects.all()
@register_model_view(PowerPort, 'bulk_import', detail=False)
@register_model_view(PowerPort, 'bulk_import', path='import', detail=False)
class PowerPortBulkImportView(generic.BulkImportView):
queryset = PowerPort.objects.all()
model_form = forms.PowerPortImportForm
@@ -2724,7 +2727,7 @@ class PowerOutletDeleteView(generic.ObjectDeleteView):
queryset = PowerOutlet.objects.all()
@register_model_view(PowerOutlet, 'bulk_import', detail=False)
@register_model_view(PowerOutlet, 'bulk_import', path='import', detail=False)
class PowerOutletBulkImportView(generic.BulkImportView):
queryset = PowerOutlet.objects.all()
model_form = forms.PowerOutletImportForm
@@ -2856,7 +2859,7 @@ class InterfaceDeleteView(generic.ObjectDeleteView):
queryset = Interface.objects.all()
@register_model_view(Interface, 'bulk_import', detail=False)
@register_model_view(Interface, 'bulk_import', path='import', detail=False)
class InterfaceBulkImportView(generic.BulkImportView):
queryset = Interface.objects.all()
model_form = forms.InterfaceImportForm
@@ -2942,7 +2945,7 @@ class FrontPortDeleteView(generic.ObjectDeleteView):
queryset = FrontPort.objects.all()
@register_model_view(FrontPort, 'bulk_import', detail=False)
@register_model_view(FrontPort, 'bulk_import', path='import', detail=False)
class FrontPortBulkImportView(generic.BulkImportView):
queryset = FrontPort.objects.all()
model_form = forms.FrontPortImportForm
@@ -3017,7 +3020,7 @@ class RearPortDeleteView(generic.ObjectDeleteView):
queryset = RearPort.objects.all()
@register_model_view(RearPort, 'bulk_import', detail=False)
@register_model_view(RearPort, 'bulk_import', path='import', detail=False)
class RearPortBulkImportView(generic.BulkImportView):
queryset = RearPort.objects.all()
model_form = forms.RearPortImportForm
@@ -3092,7 +3095,7 @@ class ModuleBayDeleteView(generic.ObjectDeleteView):
queryset = ModuleBay.objects.all()
@register_model_view(ModuleBay, 'bulk_import', detail=False)
@register_model_view(ModuleBay, 'bulk_import', path='import', detail=False)
class ModuleBayBulkImportView(generic.BulkImportView):
queryset = ModuleBay.objects.all()
model_form = forms.ModuleBayImportForm
@@ -3239,7 +3242,7 @@ class DeviceBayDepopulateView(generic.ObjectEditView):
})
@register_model_view(DeviceBay, 'bulk_import', detail=False)
@register_model_view(DeviceBay, 'bulk_import', path='import', detail=False)
class DeviceBayBulkImportView(generic.BulkImportView):
queryset = DeviceBay.objects.all()
model_form = forms.DeviceBayImportForm
@@ -3305,7 +3308,7 @@ class InventoryItemDeleteView(generic.ObjectDeleteView):
queryset = InventoryItem.objects.all()
@register_model_view(InventoryItem, 'bulk_import', detail=False)
@register_model_view(InventoryItem, 'bulk_import', path='import', detail=False)
class InventoryItemBulkImportView(generic.BulkImportView):
queryset = InventoryItem.objects.all()
model_form = forms.InventoryItemImportForm
@@ -3386,7 +3389,7 @@ class InventoryItemRoleDeleteView(generic.ObjectDeleteView):
queryset = InventoryItemRole.objects.all()
@register_model_view(InventoryItemRole, 'bulk_import', detail=False)
@register_model_view(InventoryItemRole, 'bulk_import', path='import', detail=False)
class InventoryItemRoleBulkImportView(generic.BulkImportView):
queryset = InventoryItemRole.objects.all()
model_form = forms.InventoryItemRoleImportForm
@@ -3582,7 +3585,7 @@ class CableDeleteView(generic.ObjectDeleteView):
queryset = Cable.objects.all()
@register_model_view(Cable, 'bulk_import', detail=False)
@register_model_view(Cable, 'bulk_import', path='import', detail=False)
class CableBulkImportView(generic.BulkImportView):
queryset = Cable.objects.all()
model_form = forms.CableImportForm
@@ -3811,7 +3814,7 @@ class VirtualChassisAddMemberView(ObjectPermissionRequiredMixin, GetReturnURLMix
)
))
if '_addanother' in request.POST:
if '_addanother' in request.POST and safe_for_redirect(request.get_full_path()):
return redirect(request.get_full_path())
return redirect(self.get_return_url(request, device))
@@ -3883,7 +3886,7 @@ class VirtualChassisRemoveMemberView(ObjectPermissionRequiredMixin, GetReturnURL
})
@register_model_view(VirtualChassis, 'bulk_import', detail=False)
@register_model_view(VirtualChassis, 'bulk_import', path='import', detail=False)
class VirtualChassisBulkImportView(generic.BulkImportView):
queryset = VirtualChassis.objects.all()
model_form = forms.VirtualChassisImportForm
@@ -3940,7 +3943,7 @@ class PowerPanelDeleteView(generic.ObjectDeleteView):
queryset = PowerPanel.objects.all()
@register_model_view(PowerPanel, 'bulk_import', detail=False)
@register_model_view(PowerPanel, 'bulk_import', path='import', detail=False)
class PowerPanelBulkImportView(generic.BulkImportView):
queryset = PowerPanel.objects.all()
model_form = forms.PowerPanelImportForm
@@ -3992,7 +3995,7 @@ class PowerFeedDeleteView(generic.ObjectDeleteView):
queryset = PowerFeed.objects.all()
@register_model_view(PowerFeed, 'bulk_import', detail=False)
@register_model_view(PowerFeed, 'bulk_import', path='import', detail=False)
class PowerFeedBulkImportView(generic.BulkImportView):
queryset = PowerFeed.objects.all()
model_form = forms.PowerFeedImportForm
@@ -4064,7 +4067,7 @@ class VirtualDeviceContextDeleteView(generic.ObjectDeleteView):
queryset = VirtualDeviceContext.objects.all()
@register_model_view(VirtualDeviceContext, 'bulk_import', detail=False)
@register_model_view(VirtualDeviceContext, 'bulk_import', path='import', detail=False)
class VirtualDeviceContextBulkImportView(generic.BulkImportView):
queryset = VirtualDeviceContext.objects.all()
model_form = forms.VirtualDeviceContextImportForm
@@ -4114,7 +4117,7 @@ class MACAddressDeleteView(generic.ObjectDeleteView):
queryset = MACAddress.objects.all()
@register_model_view(MACAddress, 'bulk_import', detail=False)
@register_model_view(MACAddress, 'bulk_import', path='import', detail=False)
class MACAddressBulkImportView(generic.BulkImportView):
queryset = MACAddress.objects.all()
model_form = forms.MACAddressImportForm