1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00
Files
netbox-community-netbox/netbox/dcim/forms/bulk_edit.py

1425 lines
40 KiB
Python
Raw Normal View History

2021-09-27 17:00:13 -04:00
from django import forms
from django.contrib.auth.models import User
from django.utils.translation import gettext as _
2021-09-27 17:00:13 -04:00
from timezone_field import TimeZoneFormField
from dcim.choices import *
from dcim.constants import *
from dcim.models import *
from extras.models import ConfigTemplate
from ipam.models import ASN, VLAN, VLANGroup, VRF
from netbox.forms import NetBoxModelBulkEditForm
2021-09-27 17:00:13 -04:00
from tenancy.models import Tenant
from utilities.forms import BulkEditForm, add_blank_choice, form_from_model
from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField
from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions
2021-09-27 17:00:13 -04:00
__all__ = (
'CableBulkEditForm',
'ConsolePortBulkEditForm',
'ConsolePortTemplateBulkEditForm',
'ConsoleServerPortBulkEditForm',
'ConsoleServerPortTemplateBulkEditForm',
'DeviceBayBulkEditForm',
'DeviceBayTemplateBulkEditForm',
'DeviceBulkEditForm',
'DeviceRoleBulkEditForm',
'DeviceTypeBulkEditForm',
'FrontPortBulkEditForm',
'FrontPortTemplateBulkEditForm',
'InterfaceBulkEditForm',
'InterfaceTemplateBulkEditForm',
'InventoryItemBulkEditForm',
2021-12-27 10:18:39 -05:00
'InventoryItemRoleBulkEditForm',
2021-12-29 15:02:25 -05:00
'InventoryItemTemplateBulkEditForm',
2021-09-27 17:00:13 -04:00
'LocationBulkEditForm',
'ManufacturerBulkEditForm',
2021-12-17 16:12:03 -05:00
'ModuleBulkEditForm',
'ModuleBayBulkEditForm',
'ModuleBayTemplateBulkEditForm',
2021-12-17 12:18:37 -05:00
'ModuleTypeBulkEditForm',
2021-09-27 17:00:13 -04:00
'PlatformBulkEditForm',
'PowerFeedBulkEditForm',
'PowerOutletBulkEditForm',
'PowerOutletTemplateBulkEditForm',
'PowerPanelBulkEditForm',
'PowerPortBulkEditForm',
'PowerPortTemplateBulkEditForm',
'RackBulkEditForm',
'RackReservationBulkEditForm',
'RackRoleBulkEditForm',
'RearPortBulkEditForm',
'RearPortTemplateBulkEditForm',
'RegionBulkEditForm',
'SiteBulkEditForm',
'SiteGroupBulkEditForm',
'VirtualChassisBulkEditForm',
Closes: #7854 - Add VDC/Instances/etc (#10787) * Work on #7854 * Move to new URL scheme. * Fix PEP8 errors * Fix PEP8 errors * Add GraphQL and fix primary_ip missing * Fix PEP8 on GQL Type * Fix missing NestedSerializer. * Fix missing NestedSerializer & rename VDC to VDCs * Fix migration * Change Validation for identifier * Fix missing migration * Rebase to feature * Post-review changes * Remove VDC Type * Remove M2M Enforcement logic * Interface related changes * Add filter fields to filterset for Interface filter * Add form field to filterset form for Interface filter * Add VDC display to interface detail template * Remove VirtualDeviceContextTypeChoices * Accommodate recent changes in feature branch * Add tests Add missing search() * Update tests, and fix model form * Update test_api * Update test_api.InterfaceTest create_data * Fix issue with tests * Update interface serializer * Update serializer and tests * Update status to be required * Remove error message for constraint * Remove extraneous import * Re-ordered devices menu to place VDC below virtual chassis * Add helptext for `identifier` field * Fix breadcrumb link * Remove add interface link * Add missing tenant and status fields * Changes to tests as per Jeremy * Change for #9623 Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update filterset form for status field * Remove Rename View * Change tabs to spaces * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Fix tenant in bulk_edit * Apply suggestions from code review Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Add status field to table. * Re-order table fields. Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-11-11 06:55:49 -06:00
'VirtualDeviceContextBulkEditForm'
2021-09-27 17:00:13 -04:00
)
class RegionBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
parent = DynamicModelChoiceField(
queryset=Region.objects.all(),
required=False
)
description = forms.CharField(
max_length=200,
required=False
)
model = Region
fieldsets = (
(None, ('parent', 'description')),
)
nullable_fields = ('parent', 'description')
2021-09-27 17:00:13 -04:00
class SiteGroupBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
parent = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False
)
description = forms.CharField(
max_length=200,
required=False
)
model = SiteGroup
fieldsets = (
(None, ('parent', 'description')),
)
nullable_fields = ('parent', 'description')
2021-09-27 17:00:13 -04:00
class SiteBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
status = forms.ChoiceField(
choices=add_blank_choice(SiteStatusChoices),
required=False,
initial=''
2021-09-27 17:00:13 -04:00
)
region = DynamicModelChoiceField(
queryset=Region.objects.all(),
required=False
)
group = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
asns = DynamicModelMultipleChoiceField(
2021-10-24 23:42:47 -05:00
queryset=ASN.objects.all(),
label=_('ASNs'),
required=False
2021-09-27 17:00:13 -04:00
)
contact_name = forms.CharField(
max_length=50,
required=False
)
contact_phone = forms.CharField(
max_length=20,
required=False
)
contact_email = forms.EmailField(
required=False,
label=_('Contact E-mail')
)
2021-09-27 17:00:13 -04:00
time_zone = TimeZoneFormField(
choices=add_blank_choice(TimeZoneFormField().choices),
required=False
2021-09-27 17:00:13 -04:00
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
label='Comments'
)
2021-09-27 17:00:13 -04:00
model = Site
fieldsets = (
(None, ('status', 'region', 'group', 'tenant', 'asns', 'time_zone', 'description')),
)
nullable_fields = (
'region', 'group', 'tenant', 'asns', 'time_zone', 'description', 'comments',
)
2021-09-27 17:00:13 -04:00
class LocationBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False
)
parent = DynamicModelChoiceField(
queryset=Location.objects.all(),
required=False,
query_params={
'site_id': '$site'
}
)
status = forms.ChoiceField(
choices=add_blank_choice(LocationStatusChoices),
required=False,
initial=''
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
2021-09-27 17:00:13 -04:00
description = forms.CharField(
max_length=200,
required=False
)
model = Location
fieldsets = (
(None, ('site', 'parent', 'status', 'tenant', 'description')),
)
nullable_fields = ('parent', 'tenant', 'description')
2021-09-27 17:00:13 -04:00
class RackRoleBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
color = ColorField(
required=False
)
description = forms.CharField(
max_length=200,
required=False
)
model = RackRole
fieldsets = (
(None, ('color', 'description')),
)
nullable_fields = ('color', 'description')
2021-09-27 17:00:13 -04:00
class RackBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
region = DynamicModelChoiceField(
queryset=Region.objects.all(),
required=False,
initial_params={
'sites': '$site'
}
)
site_group = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
initial_params={
'sites': '$site'
}
)
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False,
query_params={
'region_id': '$region',
'group_id': '$site_group',
}
)
location = DynamicModelChoiceField(
queryset=Location.objects.all(),
required=False,
query_params={
'site_id': '$site'
}
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
status = forms.ChoiceField(
choices=add_blank_choice(RackStatusChoices),
required=False,
initial=''
2021-09-27 17:00:13 -04:00
)
role = DynamicModelChoiceField(
queryset=RackRole.objects.all(),
required=False
)
serial = forms.CharField(
max_length=50,
required=False,
label=_('Serial Number')
2021-09-27 17:00:13 -04:00
)
asset_tag = forms.CharField(
max_length=50,
required=False
)
type = forms.ChoiceField(
choices=add_blank_choice(RackTypeChoices),
required=False
2021-09-27 17:00:13 -04:00
)
width = forms.ChoiceField(
choices=add_blank_choice(RackWidthChoices),
required=False
2021-09-27 17:00:13 -04:00
)
u_height = forms.IntegerField(
required=False,
label=_('Height (U)')
2021-09-27 17:00:13 -04:00
)
desc_units = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect,
label=_('Descending units')
2021-09-27 17:00:13 -04:00
)
outer_width = forms.IntegerField(
required=False,
min_value=1
)
outer_depth = forms.IntegerField(
required=False,
min_value=1
)
outer_unit = forms.ChoiceField(
choices=add_blank_choice(RackDimensionUnitChoices),
required=False
2021-09-27 17:00:13 -04:00
)
mounting_depth = forms.IntegerField(
required=False,
min_value=1
)
weight = forms.DecimalField(
min_value=0,
required=False
)
max_weight = forms.IntegerField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial=''
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
label='Comments'
)
2021-09-27 17:00:13 -04:00
model = Rack
fieldsets = (
('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag', 'description')),
('Location', ('region', 'site_group', 'site', 'location')),
('Hardware', (
'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth',
)),
('Weight', ('weight', 'max_weight', 'weight_unit')),
)
nullable_fields = (
'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'weight',
'max_weight', 'weight_unit', 'description', 'comments',
)
2021-09-27 17:00:13 -04:00
class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
user = forms.ModelChoiceField(
queryset=User.objects.order_by(
'username'
),
required=False
2021-09-27 17:00:13 -04:00
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
description = forms.CharField(
max_length=200,
2021-09-27 17:00:13 -04:00
required=False
)
comments = CommentField(
label='Comments'
)
2021-09-27 17:00:13 -04:00
model = RackReservation
fieldsets = (
(None, ('user', 'tenant', 'description')),
)
nullable_fields = ('comments',)
2021-09-27 17:00:13 -04:00
class ManufacturerBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
description = forms.CharField(
max_length=200,
required=False
)
model = Manufacturer
fieldsets = (
(None, ('description',)),
)
nullable_fields = ('description',)
2021-09-27 17:00:13 -04:00
class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
manufacturer = DynamicModelChoiceField(
queryset=Manufacturer.objects.all(),
required=False
)
default_platform = DynamicModelChoiceField(
queryset=Platform.objects.all(),
required=False
)
2021-12-17 12:18:37 -05:00
part_number = forms.CharField(
required=False
)
2021-09-27 17:00:13 -04:00
u_height = forms.IntegerField(
min_value=1,
required=False
)
is_full_depth = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect(),
label=_('Is full depth')
2021-09-27 17:00:13 -04:00
)
2021-10-14 15:38:29 -04:00
airflow = forms.ChoiceField(
choices=add_blank_choice(DeviceAirflowChoices),
required=False
2021-10-14 15:38:29 -04:00
)
weight = forms.DecimalField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial=''
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
label='Comments'
)
2021-09-27 17:00:13 -04:00
model = DeviceType
fieldsets = (
('Device Type', ('manufacturer', 'default_platform', 'part_number', 'u_height', 'is_full_depth', 'airflow', 'description')),
('Weight', ('weight', 'weight_unit')),
)
nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments')
2021-09-27 17:00:13 -04:00
class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
2021-12-17 12:18:37 -05:00
manufacturer = DynamicModelChoiceField(
queryset=Manufacturer.objects.all(),
required=False
2021-09-27 17:00:13 -04:00
)
2021-12-17 12:18:37 -05:00
part_number = forms.CharField(
required=False
)
weight = forms.DecimalField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial=''
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
label='Comments'
)
2021-12-17 12:18:37 -05:00
model = ModuleType
fieldsets = (
('Module Type', ('manufacturer', 'part_number', 'description')),
('Weight', ('weight', 'weight_unit')),
)
nullable_fields = ('part_number', 'weight', 'weight_unit', 'description', 'comments')
2021-09-27 17:00:13 -04:00
class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
color = ColorField(
required=False
)
vm_role = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect,
label=_('VM role')
2021-09-27 17:00:13 -04:00
)
config_template = DynamicModelChoiceField(
queryset=ConfigTemplate.objects.all(),
required=False
)
2021-09-27 17:00:13 -04:00
description = forms.CharField(
max_length=200,
required=False
)
model = DeviceRole
fieldsets = (
(None, ('color', 'vm_role', 'config_template', 'description')),
)
nullable_fields = ('color', 'config_template', 'description')
2021-09-27 17:00:13 -04:00
class PlatformBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
manufacturer = DynamicModelChoiceField(
queryset=Manufacturer.objects.all(),
required=False
)
napalm_driver = forms.CharField(
max_length=50,
required=False
)
config_template = DynamicModelChoiceField(
queryset=ConfigTemplate.objects.all(),
required=False
)
2021-09-27 17:00:13 -04:00
description = forms.CharField(
max_length=200,
required=False
)
model = Platform
fieldsets = (
(None, ('manufacturer', 'config_template', 'napalm_driver', 'description')),
)
nullable_fields = ('manufacturer', 'config_template', 'napalm_driver', 'description')
2021-09-27 17:00:13 -04:00
class DeviceBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
manufacturer = DynamicModelChoiceField(
queryset=Manufacturer.objects.all(),
required=False
)
device_type = DynamicModelChoiceField(
queryset=DeviceType.objects.all(),
required=False,
query_params={
'manufacturer_id': '$manufacturer'
}
)
device_role = DynamicModelChoiceField(
queryset=DeviceRole.objects.all(),
required=False
)
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False
)
location = DynamicModelChoiceField(
queryset=Location.objects.all(),
required=False,
query_params={
'site_id': '$site'
}
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
platform = DynamicModelChoiceField(
queryset=Platform.objects.all(),
required=False
)
status = forms.ChoiceField(
choices=add_blank_choice(DeviceStatusChoices),
required=False
2021-09-27 17:00:13 -04:00
)
2021-10-14 16:04:42 -04:00
airflow = forms.ChoiceField(
choices=add_blank_choice(DeviceAirflowChoices),
required=False
2021-10-14 16:04:42 -04:00
)
2021-09-27 17:00:13 -04:00
serial = forms.CharField(
max_length=50,
required=False,
label=_('Serial Number')
2021-09-27 17:00:13 -04:00
)
description = forms.CharField(
max_length=200,
required=False
)
config_template = DynamicModelChoiceField(
queryset=ConfigTemplate.objects.all(),
required=False
)
comments = CommentField(
label='Comments'
)
2021-09-27 17:00:13 -04:00
model = Device
fieldsets = (
('Device', ('device_role', 'status', 'tenant', 'platform', 'description')),
('Location', ('site', 'location')),
('Hardware', ('manufacturer', 'device_type', 'airflow', 'serial')),
('Configuration', ('config_template',)),
)
nullable_fields = (
'location', 'tenant', 'platform', 'serial', 'airflow', 'description', 'comments',
)
2021-09-27 17:00:13 -04:00
class ModuleBulkEditForm(NetBoxModelBulkEditForm):
2021-12-17 16:12:03 -05:00
manufacturer = DynamicModelChoiceField(
queryset=Manufacturer.objects.all(),
required=False
)
module_type = DynamicModelChoiceField(
queryset=ModuleType.objects.all(),
required=False,
query_params={
'manufacturer_id': '$manufacturer'
}
)
status = forms.ChoiceField(
choices=add_blank_choice(ModuleStatusChoices),
required=False,
initial=''
)
2021-12-17 16:12:03 -05:00
serial = forms.CharField(
max_length=50,
required=False,
label=_('Serial Number')
2021-12-17 16:12:03 -05:00
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
label='Comments'
)
2021-12-17 16:12:03 -05:00
model = Module
fieldsets = (
(None, ('manufacturer', 'module_type', 'status', 'serial', 'description')),
2021-09-27 17:00:13 -04:00
)
nullable_fields = ('serial', 'description', 'comments')
2021-12-17 16:12:03 -05:00
class CableBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
type = forms.ChoiceField(
choices=add_blank_choice(CableTypeChoices),
required=False,
initial=''
2021-09-27 17:00:13 -04:00
)
status = forms.ChoiceField(
2021-10-13 14:31:30 -04:00
choices=add_blank_choice(LinkStatusChoices),
2021-09-27 17:00:13 -04:00
required=False,
initial=''
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
2021-09-27 17:00:13 -04:00
label = forms.CharField(
max_length=100,
required=False
)
color = ColorField(
required=False
)
length = forms.DecimalField(
min_value=0,
required=False
)
length_unit = forms.ChoiceField(
choices=add_blank_choice(CableLengthUnitChoices),
required=False,
initial=''
2021-09-27 17:00:13 -04:00
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
label='Comments'
)
2021-09-27 17:00:13 -04:00
model = Cable
fieldsets = (
(None, ('type', 'status', 'tenant', 'label', 'description')),
('Attributes', ('color', 'length', 'length_unit')),
)
nullable_fields = (
'type', 'status', 'tenant', 'label', 'color', 'length', 'description', 'comments',
)
2021-09-27 17:00:13 -04:00
class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
domain = forms.CharField(
max_length=30,
required=False
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
label='Comments'
)
2021-09-27 17:00:13 -04:00
model = VirtualChassis
fieldsets = (
(None, ('domain', 'description')),
)
nullable_fields = ('domain', 'description', 'comments')
2021-09-27 17:00:13 -04:00
class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
region = DynamicModelChoiceField(
queryset=Region.objects.all(),
required=False,
initial_params={
'sites': '$site'
}
)
site_group = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
initial_params={
'sites': '$site'
}
)
site = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False,
query_params={
'region_id': '$region',
'group_id': '$site_group',
}
)
location = DynamicModelChoiceField(
queryset=Location.objects.all(),
required=False,
query_params={
'site_id': '$site'
}
)
description = forms.CharField(
max_length=200,
required=False
)
comments = CommentField(
label='Comments'
)
2021-09-27 17:00:13 -04:00
model = PowerPanel
fieldsets = (
(None, ('region', 'site_group', 'site', 'location', 'description')),
)
nullable_fields = ('location', 'description', 'comments')
2021-09-27 17:00:13 -04:00
class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
2021-09-27 17:00:13 -04:00
power_panel = DynamicModelChoiceField(
queryset=PowerPanel.objects.all(),
required=False
)
rack = DynamicModelChoiceField(
queryset=Rack.objects.all(),
required=False,
)
status = forms.ChoiceField(
choices=add_blank_choice(PowerFeedStatusChoices),
required=False,
initial=''
2021-09-27 17:00:13 -04:00
)
type = forms.ChoiceField(
choices=add_blank_choice(PowerFeedTypeChoices),
required=False,
initial=''
2021-09-27 17:00:13 -04:00
)
supply = forms.ChoiceField(
choices=add_blank_choice(PowerFeedSupplyChoices),
required=False,
initial=''
2021-09-27 17:00:13 -04:00
)
phase = forms.ChoiceField(
choices=add_blank_choice(PowerFeedPhaseChoices),
required=False,
initial=''
2021-09-27 17:00:13 -04:00
)
voltage = forms.IntegerField(
required=False
)
amperage = forms.IntegerField(
required=False
)
max_utilization = forms.IntegerField(
required=False
)
mark_connected = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
description = forms.CharField(
max_length=200,
required=False
)
2021-09-27 17:00:13 -04:00
comments = CommentField(
label=_('Comments')
2021-09-27 17:00:13 -04:00
)
model = PowerFeed
fieldsets = (
(None, ('power_panel', 'rack', 'status', 'type', 'mark_connected', 'description')),
('Power', ('supply', 'phase', 'voltage', 'amperage', 'max_utilization'))
)
nullable_fields = ('location', 'description', 'comments')
2021-09-27 17:00:13 -04:00
#
# Device component templates
#
2021-11-18 16:23:26 -05:00
class ConsolePortTemplateBulkEditForm(BulkEditForm):
2021-09-27 17:00:13 -04:00
pk = forms.ModelMultipleChoiceField(
queryset=ConsolePortTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
type = forms.ChoiceField(
choices=add_blank_choice(ConsolePortTypeChoices),
required=False
2021-09-27 17:00:13 -04:00
)
nullable_fields = ('label', 'type', 'description')
2021-09-27 17:00:13 -04:00
2021-11-18 16:23:26 -05:00
class ConsoleServerPortTemplateBulkEditForm(BulkEditForm):
2021-09-27 17:00:13 -04:00
pk = forms.ModelMultipleChoiceField(
queryset=ConsoleServerPortTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
type = forms.ChoiceField(
choices=add_blank_choice(ConsolePortTypeChoices),
required=False
2021-09-27 17:00:13 -04:00
)
description = forms.CharField(
required=False
)
nullable_fields = ('label', 'type', 'description')
2021-09-27 17:00:13 -04:00
2021-11-18 16:23:26 -05:00
class PowerPortTemplateBulkEditForm(BulkEditForm):
2021-09-27 17:00:13 -04:00
pk = forms.ModelMultipleChoiceField(
queryset=PowerPortTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
type = forms.ChoiceField(
choices=add_blank_choice(PowerPortTypeChoices),
required=False
2021-09-27 17:00:13 -04:00
)
maximum_draw = forms.IntegerField(
min_value=1,
required=False,
help_text=_("Maximum power draw (watts)")
2021-09-27 17:00:13 -04:00
)
allocated_draw = forms.IntegerField(
min_value=1,
required=False,
help_text=_("Allocated power draw (watts)")
2021-09-27 17:00:13 -04:00
)
description = forms.CharField(
required=False
)
nullable_fields = ('label', 'type', 'maximum_draw', 'allocated_draw', 'description')
2021-09-27 17:00:13 -04:00
2021-11-18 16:23:26 -05:00
class PowerOutletTemplateBulkEditForm(BulkEditForm):
2021-09-27 17:00:13 -04:00
pk = forms.ModelMultipleChoiceField(
queryset=PowerOutletTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
device_type = forms.ModelChoiceField(
queryset=DeviceType.objects.all(),
required=False,
disabled=True,
widget=forms.HiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
type = forms.ChoiceField(
choices=add_blank_choice(PowerOutletTypeChoices),
required=False
2021-09-27 17:00:13 -04:00
)
power_port = forms.ModelChoiceField(
queryset=PowerPortTemplate.objects.all(),
required=False
)
feed_leg = forms.ChoiceField(
choices=add_blank_choice(PowerOutletFeedLegChoices),
required=False
2021-09-27 17:00:13 -04:00
)
description = forms.CharField(
required=False
)
nullable_fields = ('label', 'type', 'power_port', 'feed_leg', 'description')
2021-09-27 17:00:13 -04:00
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Limit power_port queryset to PowerPortTemplates which belong to the parent DeviceType
if 'device_type' in self.initial:
device_type = DeviceType.objects.filter(pk=self.initial['device_type']).first()
self.fields['power_port'].queryset = PowerPortTemplate.objects.filter(device_type=device_type)
else:
self.fields['power_port'].choices = ()
self.fields['power_port'].widget.attrs['disabled'] = True
2021-11-18 16:23:26 -05:00
class InterfaceTemplateBulkEditForm(BulkEditForm):
2021-09-27 17:00:13 -04:00
pk = forms.ModelMultipleChoiceField(
queryset=InterfaceTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
type = forms.ChoiceField(
choices=add_blank_choice(InterfaceTypeChoices),
required=False
2021-09-27 17:00:13 -04:00
)
enabled = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
2021-09-27 17:00:13 -04:00
mgmt_only = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect,
label=_('Management only')
2021-09-27 17:00:13 -04:00
)
description = forms.CharField(
required=False
)
poe_mode = forms.ChoiceField(
choices=add_blank_choice(InterfacePoEModeChoices),
required=False,
initial='',
label=_('PoE mode')
)
poe_type = forms.ChoiceField(
choices=add_blank_choice(InterfacePoETypeChoices),
required=False,
initial='',
label=_('PoE type')
)
2021-09-27 17:00:13 -04:00
nullable_fields = ('label', 'description', 'poe_mode', 'poe_type')
2021-09-27 17:00:13 -04:00
2021-11-18 16:23:26 -05:00
class FrontPortTemplateBulkEditForm(BulkEditForm):
2021-09-27 17:00:13 -04:00
pk = forms.ModelMultipleChoiceField(
queryset=FrontPortTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
type = forms.ChoiceField(
choices=add_blank_choice(PortTypeChoices),
required=False
2021-09-27 17:00:13 -04:00
)
color = ColorField(
required=False
)
description = forms.CharField(
required=False
)
nullable_fields = ('description',)
2021-09-27 17:00:13 -04:00
2021-11-18 16:23:26 -05:00
class RearPortTemplateBulkEditForm(BulkEditForm):
2021-09-27 17:00:13 -04:00
pk = forms.ModelMultipleChoiceField(
queryset=RearPortTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
type = forms.ChoiceField(
choices=add_blank_choice(PortTypeChoices),
required=False
2021-09-27 17:00:13 -04:00
)
color = ColorField(
required=False
)
description = forms.CharField(
required=False
)
nullable_fields = ('description',)
2021-09-27 17:00:13 -04:00
class ModuleBayTemplateBulkEditForm(BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=ModuleBayTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
description = forms.CharField(
required=False
)
nullable_fields = ('label', 'position', 'description')
2021-09-27 17:00:13 -04:00
2021-11-18 16:23:26 -05:00
class DeviceBayTemplateBulkEditForm(BulkEditForm):
2021-09-27 17:00:13 -04:00
pk = forms.ModelMultipleChoiceField(
queryset=DeviceBayTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
description = forms.CharField(
required=False
)
nullable_fields = ('label', 'description')
2021-09-27 17:00:13 -04:00
2021-12-29 15:02:25 -05:00
class InventoryItemTemplateBulkEditForm(BulkEditForm):
pk = forms.ModelMultipleChoiceField(
queryset=InventoryItemTemplate.objects.all(),
widget=forms.MultipleHiddenInput()
)
label = forms.CharField(
max_length=64,
required=False
)
description = forms.CharField(
required=False
)
role = DynamicModelChoiceField(
queryset=InventoryItemRole.objects.all(),
required=False
)
manufacturer = DynamicModelChoiceField(
queryset=Manufacturer.objects.all(),
required=False
)
nullable_fields = ('label', 'role', 'manufacturer', 'part_id', 'description')
2021-09-27 17:00:13 -04:00
#
# Device components
#
class ComponentBulkEditForm(NetBoxModelBulkEditForm):
device = forms.ModelChoiceField(
queryset=Device.objects.all(),
required=False,
disabled=True,
widget=forms.HiddenInput()
)
module = forms.ModelChoiceField(
queryset=Module.objects.all(),
required=False
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Limit module queryset to Modules which belong to the parent Device
if 'device' in self.initial:
device = Device.objects.filter(pk=self.initial['device']).first()
self.fields['module'].queryset = Module.objects.filter(device=device)
else:
self.fields['module'].choices = ()
self.fields['module'].widget.attrs['disabled'] = True
2021-09-27 17:00:13 -04:00
class ConsolePortBulkEditForm(
form_from_model(ConsolePort, ['label', 'type', 'speed', 'mark_connected', 'description']),
ComponentBulkEditForm
2021-09-27 17:00:13 -04:00
):
mark_connected = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
model = ConsolePort
fieldsets = (
(None, ('module', 'type', 'label', 'speed', 'description', 'mark_connected')),
)
nullable_fields = ('module', 'label', 'description')
2021-09-27 17:00:13 -04:00
class ConsoleServerPortBulkEditForm(
form_from_model(ConsoleServerPort, ['label', 'type', 'speed', 'mark_connected', 'description']),
ComponentBulkEditForm
2021-09-27 17:00:13 -04:00
):
mark_connected = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
model = ConsoleServerPort
fieldsets = (
(None, ('module', 'type', 'label', 'speed', 'description', 'mark_connected')),
)
nullable_fields = ('module', 'label', 'description')
2021-09-27 17:00:13 -04:00
class PowerPortBulkEditForm(
form_from_model(PowerPort, ['label', 'type', 'maximum_draw', 'allocated_draw', 'mark_connected', 'description']),
ComponentBulkEditForm
2021-09-27 17:00:13 -04:00
):
mark_connected = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
model = PowerPort
fieldsets = (
(None, ('module', 'type', 'label', 'description', 'mark_connected')),
('Power', ('maximum_draw', 'allocated_draw')),
)
nullable_fields = ('module', 'label', 'description')
2021-09-27 17:00:13 -04:00
class PowerOutletBulkEditForm(
form_from_model(PowerOutlet, ['label', 'type', 'feed_leg', 'power_port', 'mark_connected', 'description']),
ComponentBulkEditForm
2021-09-27 17:00:13 -04:00
):
mark_connected = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
model = PowerOutlet
fieldsets = (
(None, ('module', 'type', 'label', 'description', 'mark_connected')),
('Power', ('feed_leg', 'power_port')),
)
nullable_fields = ('module', 'label', 'type', 'feed_leg', 'power_port', 'description')
2021-09-27 17:00:13 -04:00
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Limit power_port queryset to PowerPorts which belong to the parent Device
if 'device' in self.initial:
device = Device.objects.filter(pk=self.initial['device']).first()
self.fields['power_port'].queryset = PowerPort.objects.filter(device=device)
else:
self.fields['power_port'].choices = ()
self.fields['power_port'].widget.attrs['disabled'] = True
class InterfaceBulkEditForm(
form_from_model(Interface, [
'label', 'type', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'mtu', 'mgmt_only',
'mark_connected', 'description', 'mode', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width',
'tx_power',
2021-09-27 17:00:13 -04:00
]),
ComponentBulkEditForm
2021-09-27 17:00:13 -04:00
):
enabled = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
parent = DynamicModelChoiceField(
queryset=Interface.objects.all(),
required=False
)
bridge = DynamicModelChoiceField(
queryset=Interface.objects.all(),
required=False
)
2021-09-27 17:00:13 -04:00
lag = DynamicModelChoiceField(
queryset=Interface.objects.all(),
required=False,
query_params={
'type': 'lag',
},
label=_('LAG')
2021-09-27 17:00:13 -04:00
)
vdcs = DynamicModelMultipleChoiceField(
queryset=VirtualDeviceContext.objects.all(),
required=False,
label='Virtual Device Contexts',
query_params={
'device_id': '$device',
}
)
speed = forms.IntegerField(
required=False,
widget=NumberWithOptions(
options=InterfaceSpeedChoices
)
2021-09-27 17:00:13 -04:00
)
mgmt_only = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect,
label=_('Management only')
2021-09-27 17:00:13 -04:00
)
poe_mode = forms.ChoiceField(
choices=add_blank_choice(InterfacePoEModeChoices),
required=False,
initial='',
label=_('PoE mode')
)
poe_type = forms.ChoiceField(
choices=add_blank_choice(InterfacePoETypeChoices),
required=False,
initial='',
label=_('PoE type')
)
2021-09-27 17:00:13 -04:00
mark_connected = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
mode = forms.ChoiceField(
choices=add_blank_choice(InterfaceModeChoices),
required=False,
initial=''
)
vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(),
required=False,
label=_('VLAN group')
)
2021-09-27 17:00:13 -04:00
untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(),
required=False,
query_params={
'group_id': '$vlan_group',
},
label=_('Untagged VLAN')
2021-09-27 17:00:13 -04:00
)
tagged_vlans = DynamicModelMultipleChoiceField(
queryset=VLAN.objects.all(),
required=False,
query_params={
'group_id': '$vlan_group',
},
label=_('Tagged VLANs')
2021-09-27 17:00:13 -04:00
)
vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(),
required=False,
label=_('VRF')
)
2021-09-27 17:00:13 -04:00
model = Interface
fieldsets = (
(None, ('module', 'type', 'label', 'speed', 'duplex', 'description')),
('Addressing', ('vrf', 'mac_address', 'wwn')),
('Operation', ('vdcs', 'mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')),
('PoE', ('poe_mode', 'poe_type')),
('Related Interfaces', ('parent', 'bridge', 'lag')),
('802.1Q Switching', ('mode', 'vlan_group', 'untagged_vlan', 'tagged_vlans')),
('Wireless', ('rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width')),
)
nullable_fields = (
'module', 'label', 'parent', 'bridge', 'lag', 'speed', 'duplex', 'mac_address', 'wwn', 'vdcs', 'mtu', 'description',
'poe_mode', 'poe_type', 'mode', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
'vlan_group', 'untagged_vlan', 'tagged_vlans', 'vrf',
)
2021-09-27 17:00:13 -04:00
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if 'device' in self.initial:
device = Device.objects.filter(pk=self.initial['device']).first()
# Restrict parent/bridge/LAG interface assignment by device
2021-09-27 17:00:13 -04:00
self.fields['parent'].widget.add_query_param('device_id', device.pk)
self.fields['bridge'].widget.add_query_param('device_id', device.pk)
2021-09-27 17:00:13 -04:00
self.fields['lag'].widget.add_query_param('device_id', device.pk)
# Limit VLAN choices by device
self.fields['untagged_vlan'].widget.add_query_param('available_on_device', device.pk)
self.fields['tagged_vlans'].widget.add_query_param('available_on_device', device.pk)
else:
# See #4523
if 'pk' in self.initial:
site = None
interfaces = Interface.objects.filter(pk__in=self.initial['pk']).prefetch_related('device__site')
# Check interface sites. First interface should set site, further interfaces will either continue the
# loop or reset back to no site and break the loop.
for interface in interfaces:
if site is None:
site = interface.device.site
elif interface.device.site is not site:
site = None
break
if site is not None:
self.fields['untagged_vlan'].widget.add_query_param('site_id', site.pk)
self.fields['tagged_vlans'].widget.add_query_param('site_id', site.pk)
self.fields['parent'].choices = ()
self.fields['parent'].widget.attrs['disabled'] = True
self.fields['bridge'].choices = ()
self.fields['bridge'].widget.attrs['disabled'] = True
2021-09-27 17:00:13 -04:00
self.fields['lag'].choices = ()
self.fields['lag'].widget.attrs['disabled'] = True
def clean(self):
super().clean()
if not self.cleaned_data['mode']:
if self.cleaned_data['untagged_vlan']:
raise forms.ValidationError({'untagged_vlan': "Interface mode must be specified to assign VLANs"})
elif self.cleaned_data['tagged_vlans']:
raise forms.ValidationError({'tagged_vlans': "Interface mode must be specified to assign VLANs"})
2021-09-27 17:00:13 -04:00
# Untagged interfaces cannot be assigned tagged VLANs
elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_ACCESS and self.cleaned_data['tagged_vlans']:
2021-09-27 17:00:13 -04:00
raise forms.ValidationError({
'mode': "An access interface cannot have tagged VLANs assigned."
})
# Remove all tagged VLAN assignments from "tagged all" interfaces
elif self.cleaned_data['mode'] == InterfaceModeChoices.MODE_TAGGED_ALL:
self.cleaned_data['tagged_vlans'] = []
class FrontPortBulkEditForm(
form_from_model(FrontPort, ['label', 'type', 'color', 'mark_connected', 'description']),
ComponentBulkEditForm
2021-09-27 17:00:13 -04:00
):
mark_connected = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
model = FrontPort
fieldsets = (
(None, ('module', 'type', 'label', 'color', 'description', 'mark_connected')),
2021-09-27 17:00:13 -04:00
)
nullable_fields = ('module', 'label', 'description', 'color')
2021-09-27 17:00:13 -04:00
class RearPortBulkEditForm(
form_from_model(RearPort, ['label', 'type', 'color', 'mark_connected', 'description']),
ComponentBulkEditForm
2021-09-27 17:00:13 -04:00
):
mark_connected = forms.NullBooleanField(
required=False,
widget=BulkEditNullBooleanSelect
)
model = RearPort
fieldsets = (
(None, ('module', 'type', 'label', 'color', 'description', 'mark_connected')),
2021-09-27 17:00:13 -04:00
)
nullable_fields = ('module', 'label', 'description', 'color')
2021-09-27 17:00:13 -04:00
class ModuleBayBulkEditForm(
form_from_model(ModuleBay, ['label', 'position', 'description']),
NetBoxModelBulkEditForm
):
model = ModuleBay
fieldsets = (
(None, ('label', 'position', 'description')),
)
nullable_fields = ('label', 'position', 'description')
2021-09-27 17:00:13 -04:00
class DeviceBayBulkEditForm(
form_from_model(DeviceBay, ['label', 'description']),
NetBoxModelBulkEditForm
2021-09-27 17:00:13 -04:00
):
model = DeviceBay
fieldsets = (
(None, ('label', 'description')),
2021-09-27 17:00:13 -04:00
)
nullable_fields = ('label', 'description')
2021-09-27 17:00:13 -04:00
class InventoryItemBulkEditForm(
2021-12-27 10:45:33 -05:00
form_from_model(InventoryItem, ['label', 'role', 'manufacturer', 'part_id', 'description']),
NetBoxModelBulkEditForm
2021-09-27 17:00:13 -04:00
):
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
required=False
)
2021-12-27 10:45:33 -05:00
role = DynamicModelChoiceField(
queryset=InventoryItemRole.objects.all(),
required=False
2021-09-27 17:00:13 -04:00
)
manufacturer = DynamicModelChoiceField(
queryset=Manufacturer.objects.all(),
required=False
)
model = InventoryItem
fieldsets = (
(None, ('device', 'label', 'role', 'manufacturer', 'part_id', 'description')),
)
nullable_fields = ('label', 'role', 'manufacturer', 'part_id', 'description')
2021-12-27 10:18:39 -05:00
#
# Device component roles
#
class InventoryItemRoleBulkEditForm(NetBoxModelBulkEditForm):
2021-12-27 10:18:39 -05:00
color = ColorField(
required=False
)
description = forms.CharField(
max_length=200,
required=False
)
model = InventoryItemRole
fieldsets = (
(None, ('color', 'description')),
)
nullable_fields = ('color', 'description')
Closes: #7854 - Add VDC/Instances/etc (#10787) * Work on #7854 * Move to new URL scheme. * Fix PEP8 errors * Fix PEP8 errors * Add GraphQL and fix primary_ip missing * Fix PEP8 on GQL Type * Fix missing NestedSerializer. * Fix missing NestedSerializer & rename VDC to VDCs * Fix migration * Change Validation for identifier * Fix missing migration * Rebase to feature * Post-review changes * Remove VDC Type * Remove M2M Enforcement logic * Interface related changes * Add filter fields to filterset for Interface filter * Add form field to filterset form for Interface filter * Add VDC display to interface detail template * Remove VirtualDeviceContextTypeChoices * Accommodate recent changes in feature branch * Add tests Add missing search() * Update tests, and fix model form * Update test_api * Update test_api.InterfaceTest create_data * Fix issue with tests * Update interface serializer * Update serializer and tests * Update status to be required * Remove error message for constraint * Remove extraneous import * Re-ordered devices menu to place VDC below virtual chassis * Add helptext for `identifier` field * Fix breadcrumb link * Remove add interface link * Add missing tenant and status fields * Changes to tests as per Jeremy * Change for #9623 Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update filterset form for status field * Remove Rename View * Change tabs to spaces * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Fix tenant in bulk_edit * Apply suggestions from code review Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Add status field to table. * Re-order table fields. Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-11-11 06:55:49 -06:00
class VirtualDeviceContextBulkEditForm(NetBoxModelBulkEditForm):
device = DynamicModelChoiceField(
queryset=Device.objects.all(),
required=False
)
status = forms.ChoiceField(
required=False,
choices=add_blank_choice(VirtualDeviceContextStatusChoices)
Closes: #7854 - Add VDC/Instances/etc (#10787) * Work on #7854 * Move to new URL scheme. * Fix PEP8 errors * Fix PEP8 errors * Add GraphQL and fix primary_ip missing * Fix PEP8 on GQL Type * Fix missing NestedSerializer. * Fix missing NestedSerializer & rename VDC to VDCs * Fix migration * Change Validation for identifier * Fix missing migration * Rebase to feature * Post-review changes * Remove VDC Type * Remove M2M Enforcement logic * Interface related changes * Add filter fields to filterset for Interface filter * Add form field to filterset form for Interface filter * Add VDC display to interface detail template * Remove VirtualDeviceContextTypeChoices * Accommodate recent changes in feature branch * Add tests Add missing search() * Update tests, and fix model form * Update test_api * Update test_api.InterfaceTest create_data * Fix issue with tests * Update interface serializer * Update serializer and tests * Update status to be required * Remove error message for constraint * Remove extraneous import * Re-ordered devices menu to place VDC below virtual chassis * Add helptext for `identifier` field * Fix breadcrumb link * Remove add interface link * Add missing tenant and status fields * Changes to tests as per Jeremy * Change for #9623 Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update filterset form for status field * Remove Rename View * Change tabs to spaces * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Update netbox/dcim/tables/devices.py Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Fix tenant in bulk_edit * Apply suggestions from code review Co-authored-by: Jeremy Stretch <jstretch@ns1.com> * Add status field to table. * Re-order table fields. Co-authored-by: Jeremy Stretch <jstretch@ns1.com>
2022-11-11 06:55:49 -06:00
)
tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(),
required=False
)
model = VirtualDeviceContext
fieldsets = (
(None, ('device', 'status', 'tenant')),
)
nullable_fields = ('device', 'tenant', )