diff --git a/netbox/circuits/forms/filtersets.py b/netbox/circuits/forms/filtersets.py
index c71f5c65c..ec754f697 100644
--- a/netbox/circuits/forms/filtersets.py
+++ b/netbox/circuits/forms/filtersets.py
@@ -34,9 +34,10 @@ __all__ = (
class ProviderFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
model = Provider
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
FieldSet('asn_id', name=_('ASN')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
region_id = DynamicModelMultipleChoiceField(
@@ -69,8 +70,9 @@ class ProviderFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
class ProviderAccountFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
model = ProviderAccount
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('provider_id', 'account', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
provider_id = DynamicModelMultipleChoiceField(
@@ -88,8 +90,9 @@ class ProviderAccountFilterForm(ContactModelFilterForm, PrimaryModelFilterSetFor
class ProviderNetworkFilterForm(PrimaryModelFilterSetForm):
model = ProviderNetwork
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('provider_id', 'service_id', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
provider_id = DynamicModelMultipleChoiceField(
queryset=Provider.objects.all(),
@@ -107,8 +110,9 @@ class ProviderNetworkFilterForm(PrimaryModelFilterSetForm):
class CircuitTypeFilterForm(OrganizationalModelFilterSetForm):
model = CircuitType
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('color', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
tag = TagFilterField(model)
@@ -121,7 +125,7 @@ class CircuitTypeFilterForm(OrganizationalModelFilterSetForm):
class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
model = Circuit
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')),
FieldSet(
'type_id', 'status', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit',
@@ -129,6 +133,7 @@ class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelF
),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
selector_fields = ('filter_id', 'q', 'region_id', 'site_group_id', 'site_id', 'provider_id', 'provider_network_id')
@@ -274,8 +279,9 @@ class CircuitTerminationFilterForm(NetBoxModelFilterSetForm):
class CircuitGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
model = CircuitGroup
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
tag = TagFilterField(model)
@@ -312,8 +318,9 @@ class CircuitGroupAssignmentFilterForm(NetBoxModelFilterSetForm):
class VirtualCircuitTypeFilterForm(OrganizationalModelFilterSetForm):
model = VirtualCircuitType
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('color', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
tag = TagFilterField(model)
@@ -326,10 +333,11 @@ class VirtualCircuitTypeFilterForm(OrganizationalModelFilterSetForm):
class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
model = VirtualCircuit
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')),
FieldSet('type_id', 'status', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q', 'provider_id', 'provider_network_id')
provider_id = DynamicModelMultipleChoiceField(
diff --git a/netbox/core/forms/filtersets.py b/netbox/core/forms/filtersets.py
index 69e6a4fbb..90908e479 100644
--- a/netbox/core/forms/filtersets.py
+++ b/netbox/core/forms/filtersets.py
@@ -26,8 +26,9 @@ __all__ = (
class DataSourceFilterForm(PrimaryModelFilterSetForm):
model = DataSource
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('type', 'status', 'enabled', 'sync_interval', name=_('Data Source')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
type = forms.MultipleChoiceField(
label=_('Type'),
diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py
index 63f59c6c8..34cefc6b5 100644
--- a/netbox/dcim/forms/filtersets.py
+++ b/netbox/dcim/forms/filtersets.py
@@ -14,9 +14,9 @@ from netbox.forms import (
)
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
from tenancy.models import Tenant
-from users.models import Owner, User
+from users.models import OwnerGroup, Owner, User
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
-from utilities.forms.fields import ColorField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField
+from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, TagFilterField
from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import NumberWithOptions
from virtualization.models import Cluster, ClusterGroup, VirtualMachine
@@ -70,7 +70,7 @@ __all__ = (
'SiteFilterForm',
'SiteGroupFilterForm',
'VirtualChassisFilterForm',
- 'VirtualDeviceContextFilterForm'
+ 'VirtualDeviceContextFilterForm',
)
@@ -157,9 +157,19 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
required=False,
label=_('Device Status'),
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
@@ -167,8 +177,9 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
class RegionFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
model = Region
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('parent_id', name=_('Region')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
)
parent_id = DynamicModelMultipleChoiceField(
@@ -182,8 +193,9 @@ class RegionFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
class SiteGroupFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
model = SiteGroup
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('parent_id', name=_('Site Group')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
)
parent_id = DynamicModelMultipleChoiceField(
@@ -197,9 +209,10 @@ class SiteGroupFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm)
class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
model = Site
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('status', 'region_id', 'group_id', 'asn_id', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
selector_fields = ('filter_id', 'q', 'region_id', 'group_id')
@@ -229,9 +242,10 @@ class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilt
class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NestedGroupModelFilterSetForm):
model = Location
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', 'parent_id', 'status', 'facility', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
region_id = DynamicModelMultipleChoiceField(
@@ -277,7 +291,8 @@ class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NestedGroupM
class RackRoleFilterForm(OrganizationalModelFilterSetForm):
model = RackRole
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
tag = TagFilterField(model)
@@ -328,10 +343,11 @@ class RackBaseFilterForm(PrimaryModelFilterSetForm):
class RackTypeFilterForm(RackBaseFilterForm):
model = RackType
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('manufacturer_id', 'form_factor', 'width', 'u_height', 'rack_count', name=_('Rack Type')),
FieldSet('starting_unit', 'desc_units', name=_('Numbering')),
FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q', 'manufacturer_id')
manufacturer_id = DynamicModelMultipleChoiceField(
@@ -350,13 +366,14 @@ class RackTypeFilterForm(RackBaseFilterForm):
class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, RackBaseFilterForm):
model = Rack
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
- FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('status', 'role_id', 'manufacturer_id', 'rack_type_id', 'serial', 'asset_tag', name=_('Rack')),
FieldSet('form_factor', 'width', 'u_height', 'airflow', name=_('Hardware')),
FieldSet('starting_unit', 'desc_units', name=_('Numbering')),
FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
+ FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
selector_fields = ('filter_id', 'q', 'region_id', 'site_group_id', 'site_id', 'location_id')
@@ -433,9 +450,10 @@ class RackElevationFilterForm(RackFilterForm):
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'id', name=_('Location')),
FieldSet('status', 'role_id', name=_('Function')),
FieldSet('type', 'width', 'serial', 'asset_tag', name=_('Hardware')),
- FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
- FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
+ FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
+ FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
id = DynamicModelMultipleChoiceField(
queryset=Rack.objects.all(),
@@ -451,10 +469,11 @@ class RackElevationFilterForm(RackFilterForm):
class RackReservationFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = RackReservation
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('status', 'user_id', name=_('Reservation')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Rack')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
@@ -509,7 +528,8 @@ class RackReservationFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
class ManufacturerFilterForm(ContactModelFilterForm, OrganizationalModelFilterSetForm):
model = Manufacturer
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
)
tag = TagFilterField(model)
@@ -518,7 +538,7 @@ class ManufacturerFilterForm(ContactModelFilterForm, OrganizationalModelFilterSe
class DeviceTypeFilterForm(PrimaryModelFilterSetForm):
model = DeviceType
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet(
'manufacturer_id', 'default_platform_id', 'part_number', 'device_count',
'subdevice_role', 'airflow', name=_('Hardware')
@@ -529,6 +549,7 @@ class DeviceTypeFilterForm(PrimaryModelFilterSetForm):
'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items', name=_('Components')
),
FieldSet('weight', 'weight_unit', name=_('Weight')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q', 'manufacturer_id')
manufacturer_id = DynamicModelMultipleChoiceField(
@@ -652,7 +673,8 @@ class DeviceTypeFilterForm(PrimaryModelFilterSetForm):
class ModuleTypeProfileFilterForm(PrimaryModelFilterSetForm):
model = ModuleTypeProfile
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q')
tag = TagFilterField(model)
@@ -661,7 +683,7 @@ class ModuleTypeProfileFilterForm(PrimaryModelFilterSetForm):
class ModuleTypeFilterForm(PrimaryModelFilterSetForm):
model = ModuleType
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet(
'profile_id', 'manufacturer_id', 'part_number', 'module_count',
'airflow', name=_('Hardware')
@@ -671,6 +693,7 @@ class ModuleTypeFilterForm(PrimaryModelFilterSetForm):
'pass_through_ports', name=_('Components')
),
FieldSet('weight', 'weight_unit', name=_('Weight')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q', 'manufacturer_id')
profile_id = DynamicModelMultipleChoiceField(
@@ -754,8 +777,9 @@ class ModuleTypeFilterForm(PrimaryModelFilterSetForm):
class DeviceRoleFilterForm(NestedGroupModelFilterSetForm):
model = DeviceRole
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
- FieldSet('parent_id', 'config_template_id', name=_('Device Role'))
+ FieldSet('q', 'filter_id', 'tag'),
+ FieldSet('parent_id', 'config_template_id', name=_('Device Role')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
config_template_id = DynamicModelMultipleChoiceField(
queryset=ConfigTemplate.objects.all(),
@@ -773,8 +797,9 @@ class DeviceRoleFilterForm(NestedGroupModelFilterSetForm):
class PlatformFilterForm(NestedGroupModelFilterSetForm):
model = Platform
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
- FieldSet('manufacturer_id', 'parent_id', 'config_template_id', name=_('Platform'))
+ FieldSet('q', 'filter_id', 'tag'),
+ FieldSet('manufacturer_id', 'parent_id', 'config_template_id', name=_('Platform')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q', 'manufacturer_id')
parent_id = DynamicModelMultipleChoiceField(
@@ -803,11 +828,12 @@ class DeviceFilterForm(
):
model = Device
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address', name=_('Operation')),
FieldSet('manufacturer_id', 'device_type_id', 'platform_id', name=_('Hardware')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
FieldSet(
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports',
@@ -996,9 +1022,10 @@ class DeviceFilterForm(
class VirtualDeviceContextFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = VirtualDeviceContext
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('device', 'status', 'has_primary_ip', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
device = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
@@ -1023,9 +1050,10 @@ class VirtualDeviceContextFilterForm(TenancyFilterForm, PrimaryModelFilterSetFor
class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = Module
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ 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')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
device_id = DynamicModelMultipleChoiceField(
queryset=Device.objects.all(),
@@ -1106,9 +1134,10 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, PrimaryM
class VirtualChassisFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = VirtualChassis
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
- FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
@@ -1135,10 +1164,11 @@ class VirtualChassisFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
class CableFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = Cable
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')),
FieldSet('type', 'status', 'profile', 'color', 'length', 'length_unit', 'unterminated', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
@@ -1224,8 +1254,9 @@ class CableFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
class PowerPanelFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
model = PowerPanel
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
selector_fields = ('filter_id', 'q', 'site_id', 'location_id')
@@ -1263,10 +1294,11 @@ class PowerPanelFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
class PowerFeedFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = PowerFeed
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id', name=_('Location')),
- FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization', name=_('Attributes')),
+ FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
@@ -1390,7 +1422,7 @@ class PathEndpointFilterForm(CabledFilterForm):
class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = ConsolePort
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet(
@@ -1398,6 +1430,7 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
name=_('Device')
),
FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
type = forms.MultipleChoiceField(
label=_('Type'),
@@ -1429,7 +1462,7 @@ class ConsolePortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = ConsoleServerPort
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet(
@@ -1437,6 +1470,7 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF
name=_('Device')
),
FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
type = forms.MultipleChoiceField(
label=_('Type'),
@@ -1468,7 +1502,7 @@ class ConsoleServerPortTemplateFilterForm(ModularDeviceComponentTemplateFilterFo
class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = PowerPort
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', 'type', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet(
@@ -1476,6 +1510,7 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
name=_('Device')
),
FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
type = forms.MultipleChoiceField(
label=_('Type'),
@@ -1502,7 +1537,7 @@ class PowerPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = PowerOutlet
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', 'type', 'color', 'status', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet(
@@ -1510,6 +1545,7 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
name=_('Device')
),
FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
type = forms.MultipleChoiceField(
label=_('Type'),
@@ -1545,7 +1581,7 @@ class PowerOutletTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = Interface
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only', name=_('Attributes')),
FieldSet('vrf_id', 'l2vpn_id', 'mac_address', 'wwn', name=_('Addressing')),
FieldSet('poe_mode', 'poe_type', name=_('PoE')),
@@ -1558,6 +1594,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
name=_('Device')
),
FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q', 'device_id')
vdc_id = DynamicModelMultipleChoiceField(
@@ -1716,7 +1753,7 @@ class InterfaceTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', 'type', 'color', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet(
@@ -1724,6 +1761,7 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
name=_('Device')
),
FieldSet('cabled', 'occupied', name=_('Cable')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
model = FrontPort
type = forms.MultipleChoiceField(
@@ -1759,7 +1797,7 @@ class FrontPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
model = RearPort
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', 'type', 'color', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet(
@@ -1767,6 +1805,7 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
name=_('Device')
),
FieldSet('cabled', 'occupied', name=_('Cable')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
type = forms.MultipleChoiceField(
label=_('Type'),
@@ -1801,13 +1840,14 @@ class RearPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
class ModuleBayFilterForm(DeviceComponentFilterForm):
model = ModuleBay
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', 'position', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet(
'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
name=_('Device')
),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
tag = TagFilterField(model)
position = forms.CharField(
@@ -1832,13 +1872,14 @@ class ModuleBayTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
class DeviceBayFilterForm(DeviceComponentFilterForm):
model = DeviceBay
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'label', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet(
'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
name=_('Device')
),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
tag = TagFilterField(model)
@@ -1855,7 +1896,7 @@ class DeviceBayTemplateFilterForm(DeviceComponentTemplateFilterForm):
class InventoryItemFilterForm(DeviceComponentFilterForm):
model = InventoryItem
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet(
'name', 'label', 'status', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered',
name=_('Attributes')
@@ -1865,6 +1906,7 @@ class InventoryItemFilterForm(DeviceComponentFilterForm):
'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
name=_('Device')
),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
role_id = DynamicModelMultipleChoiceField(
queryset=InventoryItemRole.objects.all(),
@@ -1925,7 +1967,8 @@ class InventoryItemTemplateFilterForm(DeviceComponentTemplateFilterForm):
class InventoryItemRoleFilterForm(OrganizationalModelFilterSetForm):
model = InventoryItemRole
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
tag = TagFilterField(model)
@@ -1937,9 +1980,10 @@ class InventoryItemRoleFilterForm(OrganizationalModelFilterSetForm):
class MACAddressFilterForm(PrimaryModelFilterSetForm):
model = MACAddress
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('mac_address', name=_('Attributes')),
FieldSet('device_id', 'virtual_machine_id', 'assigned', 'primary', name=_('Assignments')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q', 'device_id', 'virtual_machine_id')
mac_address = forms.CharField(
diff --git a/netbox/dcim/forms/object_create.py b/netbox/dcim/forms/object_create.py
index 8e0818326..2354ee5c5 100644
--- a/netbox/dcim/forms/object_create.py
+++ b/netbox/dcim/forms/object_create.py
@@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _
from dcim.models import *
from netbox.forms import NetBoxModelForm
+from netbox.forms.mixins import OwnerMixin
from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField
from utilities.forms.rendering import FieldSet, TabbedGroups
from utilities.forms.widgets import APISelect
@@ -271,7 +272,7 @@ class InventoryItemCreateForm(ComponentCreateForm, model_forms.InventoryItemForm
# Virtual chassis
#
-class VirtualChassisCreateForm(NetBoxModelForm):
+class VirtualChassisCreateForm(OwnerMixin, NetBoxModelForm):
region = DynamicModelChoiceField(
label=_('Region'),
queryset=Region.objects.all(),
diff --git a/netbox/extras/forms/filtersets.py b/netbox/extras/forms/filtersets.py
index 0a3036597..b40742758 100644
--- a/netbox/extras/forms/filtersets.py
+++ b/netbox/extras/forms/filtersets.py
@@ -9,11 +9,10 @@ from netbox.events import get_event_type_choices
from netbox.forms import NetBoxModelFilterSetForm, PrimaryModelFilterSetForm
from netbox.forms.mixins import SavedFiltersMixin
from tenancy.models import Tenant, TenantGroup
-from users.models import Group, Owner, User
+from users.models import Group, OwnerGroup, Owner, User
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
from utilities.forms.fields import (
- ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
- TagFilterField,
+ ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, TagFilterField,
)
from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import DateTimePicker
@@ -47,6 +46,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
FieldSet('choice_set_id', 'related_object_type_id', name=_('Type Options')),
FieldSet('ui_visible', 'ui_editable', 'is_cloneable', name=_('Behavior')),
FieldSet('validation_minimum', 'validation_maximum', 'validation_regex', name=_('Validation')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
object_type_id = ContentTypeMultipleChoiceField(
queryset=ObjectType.objects.with_feature('custom_fields'),
@@ -119,9 +119,19 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
label=_('Validation regex'),
required=False
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
@@ -131,6 +141,7 @@ class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = (
FieldSet('q', 'filter_id'),
FieldSet('base_choices', 'choice', name=_('Choices')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
base_choices = forms.MultipleChoiceField(
choices=CustomFieldChoiceSetBaseChoices,
@@ -139,9 +150,19 @@ class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm):
choice = forms.CharField(
required=False
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
@@ -151,6 +172,7 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = (
FieldSet('q', 'filter_id'),
FieldSet('object_type_id', 'enabled', 'new_window', 'weight', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
object_type_id = ContentTypeMultipleChoiceField(
label=_('Object types'),
@@ -175,9 +197,19 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
label=_('Weight'),
required=False
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
@@ -188,6 +220,7 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
FieldSet('q', 'filter_id', 'object_type_id'),
FieldSet('data_source_id', 'data_file_id', name=_('Data')),
FieldSet('mime_type', 'file_name', 'file_extension', 'as_attachment', name=_('Rendering')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
data_source_id = DynamicModelMultipleChoiceField(
queryset=DataSource.objects.all(),
@@ -226,9 +259,19 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
@@ -255,6 +298,7 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = (
FieldSet('q', 'filter_id'),
FieldSet('object_type_id', 'enabled', 'shared', 'weight', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
object_type_id = ContentTypeMultipleChoiceField(
label=_('Object types'),
@@ -279,9 +323,19 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
label=_('Weight'),
required=False
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
@@ -320,8 +374,9 @@ class TableConfigFilterForm(SavedFiltersMixin, FilterForm):
class WebhookFilterForm(NetBoxModelFilterSetForm):
model = Webhook
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('payload_url', 'http_method', 'http_content_type', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
http_content_type = forms.CharField(
label=_('HTTP content type'),
@@ -336,9 +391,19 @@ class WebhookFilterForm(NetBoxModelFilterSetForm):
required=False,
label=_('HTTP method')
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
tag = TagFilterField(model)
@@ -347,8 +412,9 @@ class WebhookFilterForm(NetBoxModelFilterSetForm):
class EventRuleFilterForm(NetBoxModelFilterSetForm):
model = EventRule
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('object_type_id', 'event_type', 'action_type', 'enabled', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
object_type_id = ContentTypeMultipleChoiceField(
queryset=ObjectType.objects.with_feature('event_rules'),
@@ -372,9 +438,19 @@ class EventRuleFilterForm(NetBoxModelFilterSetForm):
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
tag = TagFilterField(model)
@@ -382,6 +458,11 @@ class EventRuleFilterForm(NetBoxModelFilterSetForm):
class TagFilterForm(SavedFiltersMixin, FilterForm):
model = Tag
+ fieldsets = (
+ FieldSet('q', 'filter_id'),
+ FieldSet('content_type_id', 'for_object_type_id', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
+ )
content_type_id = ContentTypeMultipleChoiceField(
queryset=ObjectType.objects.with_feature('tags'),
required=False,
@@ -392,9 +473,19 @@ class TagFilterForm(SavedFiltersMixin, FilterForm):
required=False,
label=_('Allowed object type')
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
@@ -404,6 +495,7 @@ class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm):
fieldsets = (
FieldSet('q', 'filter_id'),
FieldSet('data_source_id', 'data_file_id', name=_('Data')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
data_source_id = DynamicModelMultipleChoiceField(
queryset=DataSource.objects.all(),
@@ -418,18 +510,34 @@ class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm):
'source_id': '$data_source_id'
}
)
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
+ queryset=Owner.objects.all(),
+ required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
+ label=_('Owner'),
+ )
class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
model = ConfigContext
fieldsets = (
FieldSet('q', 'filter_id', 'tag_id'),
- FieldSet('profile', name=_('Config Context')),
+ FieldSet('profile_id', name=_('Config Context')),
FieldSet('data_source_id', 'data_file_id', name=_('Data')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
FieldSet('device_type_id', 'platform_id', 'device_role_id', name=_('Device')),
FieldSet('cluster_type_id', 'cluster_group_id', 'cluster_id', name=_('Cluster')),
- FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant'))
+ FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
profile_id = DynamicModelMultipleChoiceField(
queryset=ConfigContextProfile.objects.all(),
@@ -514,9 +622,19 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
required=False,
label=_('Tags')
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
@@ -526,7 +644,8 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('data_source_id', 'data_file_id', 'auto_sync_enabled', name=_('Data')),
- FieldSet('mime_type', 'file_name', 'file_extension', 'as_attachment', name=_('Rendering'))
+ FieldSet('mime_type', 'file_name', 'file_extension', 'as_attachment', name=_('Rendering')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
data_source_id = DynamicModelMultipleChoiceField(
queryset=DataSource.objects.all(),
@@ -568,9 +687,19 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
choices=BOOLEAN_WITH_BLANK_CHOICES
)
)
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
diff --git a/netbox/extras/forms/model_forms.py b/netbox/extras/forms/model_forms.py
index 68151c80b..b0252962e 100644
--- a/netbox/extras/forms/model_forms.py
+++ b/netbox/extras/forms/model_forms.py
@@ -178,6 +178,13 @@ class CustomFieldChoiceSetForm(ChangelogMessageMixin, OwnerMixin, forms.ModelFor
) + ' choice1:First Choice')
)
+ fieldsets = (
+ FieldSet(
+ 'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically',
+ name=_('Custom Field Choice Set')
+ ),
+ )
+
class Meta:
model = CustomFieldChoiceSet
fields = ('name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'owner')
diff --git a/netbox/ipam/forms/filtersets.py b/netbox/ipam/forms/filtersets.py
index dd2987f28..e37d17d4b 100644
--- a/netbox/ipam/forms/filtersets.py
+++ b/netbox/ipam/forms/filtersets.py
@@ -45,9 +45,10 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([
class VRFFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = VRF
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('import_target_id', 'export_target_id', name=_('Route Targets')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
import_target_id = DynamicModelMultipleChoiceField(
queryset=RouteTarget.objects.all(),
@@ -65,9 +66,10 @@ class VRFFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
class RouteTargetFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = RouteTarget
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('importing_vrf_id', 'exporting_vrf_id', name=_('VRF')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
importing_vrf_id = DynamicModelMultipleChoiceField(
queryset=VRF.objects.all(),
@@ -85,8 +87,9 @@ class RouteTargetFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
class RIRFilterForm(OrganizationalModelFilterSetForm):
model = RIR
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('is_private', name=_('RIR')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
is_private = forms.NullBooleanField(
required=False,
@@ -101,9 +104,10 @@ class RIRFilterForm(OrganizationalModelFilterSetForm):
class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = Aggregate
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('family', 'rir_id', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
family = forms.ChoiceField(
@@ -122,9 +126,10 @@ class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryMode
class ASNRangeFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
model = ASNRange
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('rir_id', 'start', 'end', name=_('Range')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
rir_id = DynamicModelMultipleChoiceField(
queryset=RIR.objects.all(),
@@ -145,9 +150,10 @@ class ASNRangeFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
class ASNFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = ASN
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('rir_id', 'site_group_id', 'site_id', name=_('Assignment')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
rir_id = DynamicModelMultipleChoiceField(
queryset=RIR.objects.all(),
@@ -170,7 +176,8 @@ class ASNFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
class RoleFilterForm(OrganizationalModelFilterSetForm):
model = Role
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
tag = TagFilterField(model)
@@ -178,7 +185,7 @@ class RoleFilterForm(OrganizationalModelFilterSetForm):
class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = Prefix
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet(
'within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized',
name=_('Addressing')
@@ -187,6 +194,7 @@ class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFi
FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
mask_length__lte = forms.IntegerField(
@@ -284,9 +292,10 @@ class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFi
class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = IPRange
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_populated', 'mark_utilized', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
family = forms.ChoiceField(
@@ -331,14 +340,15 @@ class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelF
class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = IPAddress
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet(
'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface', 'dns_name',
name=_('Attributes')
),
FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')),
- FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('device_id', 'virtual_machine_id', name=_('Device/VM')),
+ FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
selector_fields = ('filter_id', 'q', 'region_id', 'group_id', 'parent', 'status', 'role')
@@ -409,9 +419,10 @@ class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryMode
class FHRPGroupFilterForm(PrimaryModelFilterSetForm):
model = FHRPGroup
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', 'protocol', 'group_id', name=_('Attributes')),
FieldSet('auth_type', 'auth_key', name=_('Authentication')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
name = forms.CharField(
label=_('Name'),
@@ -441,11 +452,12 @@ class FHRPGroupFilterForm(PrimaryModelFilterSetForm):
class VLANGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region', 'site_group', 'site', 'location', 'rack', name=_('Location')),
FieldSet('cluster_group', 'cluster', name=_('Cluster')),
FieldSet('contains_vid', name=_('VLANs')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
model = VLANGroup
region = DynamicModelMultipleChoiceField(
@@ -495,8 +507,9 @@ class VLANGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
class VLANTranslationPolicyFilterForm(PrimaryModelFilterSetForm):
model = VLANTranslationPolicy
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('name', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
name = forms.CharField(
required=False,
@@ -532,11 +545,12 @@ class VLANTranslationRuleFilterForm(NetBoxModelFilterSetForm):
class VLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = VLAN
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
FieldSet('group_id', 'status', 'role_id', 'vid', 'l2vpn_id', name=_('Attributes')),
FieldSet('qinq_role', 'qinq_svlan_id', name=_('Q-in-Q/802.1ad')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
selector_fields = ('filter_id', 'q', 'group_id')
region_id = DynamicModelMultipleChoiceField(
@@ -604,8 +618,9 @@ class VLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
class ServiceTemplateFilterForm(PrimaryModelFilterSetForm):
model = ServiceTemplate
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('protocol', 'port', name=_('Attributes')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
)
protocol = forms.ChoiceField(
label=_('Protocol'),
@@ -622,9 +637,10 @@ class ServiceTemplateFilterForm(PrimaryModelFilterSetForm):
class ServiceFilterForm(ContactModelFilterForm, ServiceTemplateFilterForm):
model = Service
fieldsets = (
- FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+ FieldSet('q', 'filter_id', 'tag'),
FieldSet('protocol', 'port', name=_('Attributes')),
FieldSet('device_id', 'virtual_machine_id', 'fhrpgroup_id', name=_('Assignment')),
+ FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
)
device_id = DynamicModelMultipleChoiceField(
diff --git a/netbox/netbox/forms/filtersets.py b/netbox/netbox/forms/filtersets.py
index d334ee914..156fdc11c 100644
--- a/netbox/netbox/forms/filtersets.py
+++ b/netbox/netbox/forms/filtersets.py
@@ -3,8 +3,8 @@ from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from extras.choices import *
-from users.models import Owner
-from utilities.forms.fields import DynamicModelChoiceField, QueryField
+from users.models import OwnerGroup, Owner
+from utilities.forms.fields import DynamicModelMultipleChoiceField, QueryField
from utilities.forms.mixins import FilterModifierMixin
from .mixins import CustomFieldsMixin, SavedFiltersMixin
@@ -48,9 +48,19 @@ class NetBoxModelFilterSetForm(FilterModifierMixin, CustomFieldsMixin, SavedFilt
class OwnerFilterMixin(forms.Form):
- owner_id = DynamicModelChoiceField(
+ owner_group_id = DynamicModelMultipleChoiceField(
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ label=_('Owner Group'),
+ )
+ owner_id = DynamicModelMultipleChoiceField(
queryset=Owner.objects.all(),
required=False,
+ null_option='None',
+ query_params={
+ 'group_id': '$owner_group_id'
+ },
label=_('Owner'),
)
diff --git a/netbox/netbox/forms/mixins.py b/netbox/netbox/forms/mixins.py
index 4ee11b0bb..b960424a0 100644
--- a/netbox/netbox/forms/mixins.py
+++ b/netbox/netbox/forms/mixins.py
@@ -4,7 +4,7 @@ from django.utils.translation import gettext as _
from core.models import ObjectType
from extras.choices import *
from extras.models import *
-from users.models import Owner
+from users.models import OwnerGroup, Owner
from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField
__all__ = (
@@ -126,8 +126,17 @@ class OwnerMixin(forms.Form):
"""
Add an `owner` field to forms for models which support Owner assignment.
"""
+
+ owner_group = DynamicModelChoiceField(
+ label=_('Owner group'),
+ queryset=OwnerGroup.objects.all(),
+ required=False,
+ null_option='None',
+ initial_params={'members': '$owner'},
+ )
owner = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
+ query_params={'group_id': '$owner_group'},
label=_('Owner'),
)
diff --git a/netbox/netbox/tables/tables.py b/netbox/netbox/tables/tables.py
index a2ba13480..264e1fb05 100644
--- a/netbox/netbox/tables/tables.py
+++ b/netbox/netbox/tables/tables.py
@@ -271,9 +271,14 @@ class NetBoxTable(BaseTable):
class PrimaryModelTable(NetBoxTable):
+ owner_group = tables.Column(
+ accessor='owner__group',
+ linkify=True,
+ verbose_name=_('Owner Group'),
+ )
owner = tables.Column(
linkify=True,
- verbose_name=_('Owner')
+ verbose_name=_('Owner'),
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
@@ -281,9 +286,14 @@ class PrimaryModelTable(NetBoxTable):
class OrganizationalModelTable(NetBoxTable):
+ owner_group = tables.Column(
+ accessor='owner__group',
+ linkify=True,
+ verbose_name=_('Owner Group'),
+ )
owner = tables.Column(
linkify=True,
- verbose_name=_('Owner')
+ verbose_name=_('Owner'),
)
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
@@ -291,9 +301,14 @@ class OrganizationalModelTable(NetBoxTable):
class NestedGroupModelTable(NetBoxTable):
+ owner_group = tables.Column(
+ accessor='owner__group',
+ linkify=True,
+ verbose_name=_('Owner Group'),
+ )
owner = tables.Column(
linkify=True,
- verbose_name=_('Owner')
+ verbose_name=_('Owner'),
)
name = columns.MPTTColumn(
verbose_name=_('Name'),
diff --git a/netbox/templates/dcim/device_edit.html b/netbox/templates/dcim/device_edit.html
index 454faf8fb..e0d6b30f6 100644
--- a/netbox/templates/dcim/device_edit.html
+++ b/netbox/templates/dcim/device_edit.html
@@ -101,8 +101,9 @@