Browse Source

feat(forms): Add Owner Group support to Filter Forms

Introduces support for `owner_group` in various filter forms, improving
ownership granularity.
Updates DynamicModel fields to handle relationships
between `owner_group` and `owner` effectively.

Fixes #21081
Martin Hauser 2 tuần trước cách đây
mục cha
commit
3a33df0e43

+ 16 - 8
netbox/circuits/forms/filtersets.py

@@ -34,9 +34,10 @@ __all__ = (
 class ProviderFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
 class ProviderFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
     model = Provider
     model = Provider
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
         FieldSet('asn_id', name=_('ASN')),
         FieldSet('asn_id', name=_('ASN')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     region_id = DynamicModelMultipleChoiceField(
     region_id = DynamicModelMultipleChoiceField(
@@ -69,8 +70,9 @@ class ProviderFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
 class ProviderAccountFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
 class ProviderAccountFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
     model = ProviderAccount
     model = ProviderAccount
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('provider_id', 'account', name=_('Attributes')),
         FieldSet('provider_id', 'account', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     provider_id = DynamicModelMultipleChoiceField(
     provider_id = DynamicModelMultipleChoiceField(
@@ -88,8 +90,9 @@ class ProviderAccountFilterForm(ContactModelFilterForm, PrimaryModelFilterSetFor
 class ProviderNetworkFilterForm(PrimaryModelFilterSetForm):
 class ProviderNetworkFilterForm(PrimaryModelFilterSetForm):
     model = ProviderNetwork
     model = ProviderNetwork
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('provider_id', 'service_id', name=_('Attributes')),
         FieldSet('provider_id', 'service_id', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     provider_id = DynamicModelMultipleChoiceField(
     provider_id = DynamicModelMultipleChoiceField(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
@@ -107,8 +110,9 @@ class ProviderNetworkFilterForm(PrimaryModelFilterSetForm):
 class CircuitTypeFilterForm(OrganizationalModelFilterSetForm):
 class CircuitTypeFilterForm(OrganizationalModelFilterSetForm):
     model = CircuitType
     model = CircuitType
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('color', name=_('Attributes')),
         FieldSet('color', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -121,7 +125,7 @@ class CircuitTypeFilterForm(OrganizationalModelFilterSetForm):
 class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
 class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
     model = Circuit
     model = Circuit
     fieldsets = (
     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('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')),
         FieldSet(
         FieldSet(
             'type_id', 'status', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit',
             '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('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     selector_fields = ('filter_id', 'q', 'region_id', 'site_group_id', 'site_id', 'provider_id', 'provider_network_id')
     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):
 class CircuitGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
     model = CircuitGroup
     model = CircuitGroup
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -312,8 +318,9 @@ class CircuitGroupAssignmentFilterForm(NetBoxModelFilterSetForm):
 class VirtualCircuitTypeFilterForm(OrganizationalModelFilterSetForm):
 class VirtualCircuitTypeFilterForm(OrganizationalModelFilterSetForm):
     model = VirtualCircuitType
     model = VirtualCircuitType
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('color', name=_('Attributes')),
         FieldSet('color', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -326,10 +333,11 @@ class VirtualCircuitTypeFilterForm(OrganizationalModelFilterSetForm):
 class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
 class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
     model = VirtualCircuit
     model = VirtualCircuit
     fieldsets = (
     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('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')),
         FieldSet('type_id', 'status', name=_('Attributes')),
         FieldSet('type_id', 'status', name=_('Attributes')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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')
     selector_fields = ('filter_id', 'q', 'provider_id', 'provider_network_id')
     provider_id = DynamicModelMultipleChoiceField(
     provider_id = DynamicModelMultipleChoiceField(

+ 2 - 1
netbox/core/forms/filtersets.py

@@ -26,8 +26,9 @@ __all__ = (
 class DataSourceFilterForm(PrimaryModelFilterSetForm):
 class DataSourceFilterForm(PrimaryModelFilterSetForm):
     model = DataSource
     model = DataSource
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('type', 'status', 'enabled', 'sync_interval', name=_('Data Source')),
         FieldSet('type', 'status', 'enabled', 'sync_interval', name=_('Data Source')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     type = forms.MultipleChoiceField(
     type = forms.MultipleChoiceField(
         label=_('Type'),
         label=_('Type'),

+ 78 - 48
netbox/dcim/forms/filtersets.py

@@ -12,11 +12,12 @@ from netbox.forms import (
     NestedGroupModelFilterSetForm, NetBoxModelFilterSetForm, OrganizationalModelFilterSetForm,
     NestedGroupModelFilterSetForm, NetBoxModelFilterSetForm, OrganizationalModelFilterSetForm,
     PrimaryModelFilterSetForm,
     PrimaryModelFilterSetForm,
 )
 )
+from netbox.forms.mixins import OwnerFilterMixin
 from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
 from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
-from users.models import Owner, User
+from users.models import User
 from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
 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.rendering import FieldSet
 from utilities.forms.widgets import NumberWithOptions
 from utilities.forms.widgets import NumberWithOptions
 from virtualization.models import Cluster, ClusterGroup, VirtualMachine
 from virtualization.models import Cluster, ClusterGroup, VirtualMachine
@@ -70,11 +71,11 @@ __all__ = (
     'SiteFilterForm',
     'SiteFilterForm',
     'SiteGroupFilterForm',
     'SiteGroupFilterForm',
     'VirtualChassisFilterForm',
     'VirtualChassisFilterForm',
-    'VirtualDeviceContextFilterForm'
+    'VirtualDeviceContextFilterForm',
 )
 )
 
 
 
 
-class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
+class DeviceComponentFilterForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
     name = forms.CharField(
     name = forms.CharField(
         label=_('Name'),
         label=_('Name'),
         required=False
         required=False
@@ -157,18 +158,14 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
         required=False,
         required=False,
         label=_('Device Status'),
         label=_('Device Status'),
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
 class RegionFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
 class RegionFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
     model = Region
     model = Region
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('parent_id', name=_('Region')),
         FieldSet('parent_id', name=_('Region')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
     )
     )
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
@@ -182,8 +179,9 @@ class RegionFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
 class SiteGroupFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
 class SiteGroupFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
     model = SiteGroup
     model = SiteGroup
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('parent_id', name=_('Site Group')),
         FieldSet('parent_id', name=_('Site Group')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
     )
     )
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
@@ -197,9 +195,10 @@ class SiteGroupFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm)
 class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
 class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
     model = Site
     model = Site
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('status', 'region_id', 'group_id', 'asn_id', name=_('Attributes')),
         FieldSet('status', 'region_id', 'group_id', 'asn_id', name=_('Attributes')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     selector_fields = ('filter_id', 'q', 'region_id', 'group_id')
     selector_fields = ('filter_id', 'q', 'region_id', 'group_id')
@@ -229,9 +228,10 @@ class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilt
 class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NestedGroupModelFilterSetForm):
 class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NestedGroupModelFilterSetForm):
     model = Location
     model = Location
     fieldsets = (
     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('region_id', 'site_group_id', 'site_id', 'parent_id', 'status', 'facility', name=_('Attributes')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     region_id = DynamicModelMultipleChoiceField(
     region_id = DynamicModelMultipleChoiceField(
@@ -277,7 +277,8 @@ class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NestedGroupM
 class RackRoleFilterForm(OrganizationalModelFilterSetForm):
 class RackRoleFilterForm(OrganizationalModelFilterSetForm):
     model = RackRole
     model = RackRole
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -328,10 +329,11 @@ class RackBaseFilterForm(PrimaryModelFilterSetForm):
 class RackTypeFilterForm(RackBaseFilterForm):
 class RackTypeFilterForm(RackBaseFilterForm):
     model = RackType
     model = RackType
     fieldsets = (
     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('manufacturer_id', 'form_factor', 'width', 'u_height', 'rack_count', name=_('Rack Type')),
         FieldSet('starting_unit', 'desc_units', name=_('Numbering')),
         FieldSet('starting_unit', 'desc_units', name=_('Numbering')),
         FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
         FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     selector_fields = ('filter_id', 'q', 'manufacturer_id')
     selector_fields = ('filter_id', 'q', 'manufacturer_id')
     manufacturer_id = DynamicModelMultipleChoiceField(
     manufacturer_id = DynamicModelMultipleChoiceField(
@@ -350,13 +352,14 @@ class RackTypeFilterForm(RackBaseFilterForm):
 class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, RackBaseFilterForm):
 class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, RackBaseFilterForm):
     model = Rack
     model = Rack
     fieldsets = (
     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('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('status', 'role_id', 'manufacturer_id', 'rack_type_id', 'serial', 'asset_tag', name=_('Rack')),
         FieldSet('form_factor', 'width', 'u_height', 'airflow', name=_('Hardware')),
         FieldSet('form_factor', 'width', 'u_height', 'airflow', name=_('Hardware')),
         FieldSet('starting_unit', 'desc_units', name=_('Numbering')),
         FieldSet('starting_unit', 'desc_units', name=_('Numbering')),
         FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
         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')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     selector_fields = ('filter_id', 'q', 'region_id', 'site_group_id', 'site_id', 'location_id')
     selector_fields = ('filter_id', 'q', 'region_id', 'site_group_id', 'site_id', 'location_id')
@@ -433,9 +436,10 @@ class RackElevationFilterForm(RackFilterForm):
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'id', name=_('Location')),
         FieldSet('status', 'role_id', name=_('Function')),
         FieldSet('status', 'role_id', name=_('Function')),
         FieldSet('type', 'width', 'serial', 'asset_tag', name=_('Hardware')),
         FieldSet('type', 'width', 'serial', 'asset_tag', name=_('Hardware')),
+        FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
-        FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
     )
     )
     id = DynamicModelMultipleChoiceField(
     id = DynamicModelMultipleChoiceField(
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
@@ -451,10 +455,11 @@ class RackElevationFilterForm(RackFilterForm):
 class RackReservationFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class RackReservationFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = RackReservation
     model = RackReservation
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('status', 'user_id', name=_('Reservation')),
         FieldSet('status', 'user_id', name=_('Reservation')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Rack')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Rack')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     region_id = DynamicModelMultipleChoiceField(
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
@@ -509,7 +514,8 @@ class RackReservationFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class ManufacturerFilterForm(ContactModelFilterForm, OrganizationalModelFilterSetForm):
 class ManufacturerFilterForm(ContactModelFilterForm, OrganizationalModelFilterSetForm):
     model = Manufacturer
     model = Manufacturer
     fieldsets = (
     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'))
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
@@ -518,7 +524,7 @@ class ManufacturerFilterForm(ContactModelFilterForm, OrganizationalModelFilterSe
 class DeviceTypeFilterForm(PrimaryModelFilterSetForm):
 class DeviceTypeFilterForm(PrimaryModelFilterSetForm):
     model = DeviceType
     model = DeviceType
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet(
         FieldSet(
             'manufacturer_id', 'default_platform_id', 'part_number', 'device_count',
             'manufacturer_id', 'default_platform_id', 'part_number', 'device_count',
             'subdevice_role', 'airflow', name=_('Hardware')
             'subdevice_role', 'airflow', name=_('Hardware')
@@ -529,6 +535,7 @@ class DeviceTypeFilterForm(PrimaryModelFilterSetForm):
             'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items', name=_('Components')
             'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items', name=_('Components')
         ),
         ),
         FieldSet('weight', 'weight_unit', name=_('Weight')),
         FieldSet('weight', 'weight_unit', name=_('Weight')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     selector_fields = ('filter_id', 'q', 'manufacturer_id')
     selector_fields = ('filter_id', 'q', 'manufacturer_id')
     manufacturer_id = DynamicModelMultipleChoiceField(
     manufacturer_id = DynamicModelMultipleChoiceField(
@@ -652,7 +659,8 @@ class DeviceTypeFilterForm(PrimaryModelFilterSetForm):
 class ModuleTypeProfileFilterForm(PrimaryModelFilterSetForm):
 class ModuleTypeProfileFilterForm(PrimaryModelFilterSetForm):
     model = ModuleTypeProfile
     model = ModuleTypeProfile
     fieldsets = (
     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')
     selector_fields = ('filter_id', 'q')
     tag = TagFilterField(model)
     tag = TagFilterField(model)
@@ -661,7 +669,7 @@ class ModuleTypeProfileFilterForm(PrimaryModelFilterSetForm):
 class ModuleTypeFilterForm(PrimaryModelFilterSetForm):
 class ModuleTypeFilterForm(PrimaryModelFilterSetForm):
     model = ModuleType
     model = ModuleType
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet(
         FieldSet(
             'profile_id', 'manufacturer_id', 'part_number', 'module_count',
             'profile_id', 'manufacturer_id', 'part_number', 'module_count',
             'airflow', name=_('Hardware')
             'airflow', name=_('Hardware')
@@ -671,6 +679,7 @@ class ModuleTypeFilterForm(PrimaryModelFilterSetForm):
             'pass_through_ports', name=_('Components')
             'pass_through_ports', name=_('Components')
         ),
         ),
         FieldSet('weight', 'weight_unit', name=_('Weight')),
         FieldSet('weight', 'weight_unit', name=_('Weight')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     selector_fields = ('filter_id', 'q', 'manufacturer_id')
     selector_fields = ('filter_id', 'q', 'manufacturer_id')
     profile_id = DynamicModelMultipleChoiceField(
     profile_id = DynamicModelMultipleChoiceField(
@@ -754,8 +763,9 @@ class ModuleTypeFilterForm(PrimaryModelFilterSetForm):
 class DeviceRoleFilterForm(NestedGroupModelFilterSetForm):
 class DeviceRoleFilterForm(NestedGroupModelFilterSetForm):
     model = DeviceRole
     model = DeviceRole
     fieldsets = (
     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(
     config_template_id = DynamicModelMultipleChoiceField(
         queryset=ConfigTemplate.objects.all(),
         queryset=ConfigTemplate.objects.all(),
@@ -773,8 +783,9 @@ class DeviceRoleFilterForm(NestedGroupModelFilterSetForm):
 class PlatformFilterForm(NestedGroupModelFilterSetForm):
 class PlatformFilterForm(NestedGroupModelFilterSetForm):
     model = Platform
     model = Platform
     fieldsets = (
     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')
     selector_fields = ('filter_id', 'q', 'manufacturer_id')
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
@@ -803,11 +814,12 @@ class DeviceFilterForm(
 ):
 ):
     model = Device
     model = Device
     fieldsets = (
     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('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('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address', name=_('Operation')),
         FieldSet('manufacturer_id', 'device_type_id', 'platform_id', name=_('Hardware')),
         FieldSet('manufacturer_id', 'device_type_id', 'platform_id', name=_('Hardware')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
         FieldSet(
         FieldSet(
             'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports',
             'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'pass_through_ports',
@@ -996,9 +1008,10 @@ class DeviceFilterForm(
 class VirtualDeviceContextFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class VirtualDeviceContextFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = VirtualDeviceContext
     model = VirtualDeviceContext
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('device', 'status', 'has_primary_ip', name=_('Attributes')),
         FieldSet('device', 'status', 'has_primary_ip', name=_('Attributes')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     device = DynamicModelMultipleChoiceField(
     device = DynamicModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
@@ -1023,9 +1036,10 @@ class VirtualDeviceContextFilterForm(TenancyFilterForm, PrimaryModelFilterSetFor
 class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
 class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
     model = Module
     model = Module
     fieldsets = (
     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('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('manufacturer_id', 'module_type_id', 'status', 'serial', 'asset_tag', name=_('Hardware')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     device_id = DynamicModelMultipleChoiceField(
     device_id = DynamicModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
@@ -1106,9 +1120,10 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, PrimaryM
 class VirtualChassisFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class VirtualChassisFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = VirtualChassis
     model = VirtualChassis
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
         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(
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
@@ -1135,10 +1150,11 @@ class VirtualChassisFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class CableFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class CableFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = Cable
     model = Cable
     fieldsets = (
     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('site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')),
         FieldSet('type', 'status', 'profile', 'color', 'length', 'length_unit', 'unterminated', name=_('Attributes')),
         FieldSet('type', 'status', 'profile', 'color', 'length', 'length_unit', 'unterminated', name=_('Attributes')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     region_id = DynamicModelMultipleChoiceField(
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
@@ -1224,8 +1240,9 @@ class CableFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class PowerPanelFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
 class PowerPanelFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
     model = PowerPanel
     model = PowerPanel
     fieldsets = (
     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('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')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     selector_fields = ('filter_id', 'q', 'site_id', 'location_id')
     selector_fields = ('filter_id', 'q', 'site_id', 'location_id')
@@ -1263,10 +1280,11 @@ class PowerPanelFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
 class PowerFeedFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class PowerFeedFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = PowerFeed
     model = PowerFeed
     fieldsets = (
     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('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('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(
     region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
@@ -1390,7 +1408,7 @@ class PathEndpointFilterForm(CabledFilterForm):
 class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = ConsolePort
     model = ConsolePort
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')),
         FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet(
         FieldSet(
@@ -1398,6 +1416,7 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
             name=_('Device')
             name=_('Device')
         ),
         ),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     type = forms.MultipleChoiceField(
     type = forms.MultipleChoiceField(
         label=_('Type'),
         label=_('Type'),
@@ -1429,7 +1448,7 @@ class ConsolePortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
 class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = ConsoleServerPort
     model = ConsoleServerPort
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')),
         FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet(
         FieldSet(
@@ -1437,6 +1456,7 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF
             name=_('Device')
             name=_('Device')
         ),
         ),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     type = forms.MultipleChoiceField(
     type = forms.MultipleChoiceField(
         label=_('Type'),
         label=_('Type'),
@@ -1468,7 +1488,7 @@ class ConsoleServerPortTemplateFilterForm(ModularDeviceComponentTemplateFilterFo
 class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = PowerPort
     model = PowerPort
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'label', 'type', name=_('Attributes')),
         FieldSet('name', 'label', 'type', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet(
         FieldSet(
@@ -1476,6 +1496,7 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
             name=_('Device')
             name=_('Device')
         ),
         ),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     type = forms.MultipleChoiceField(
     type = forms.MultipleChoiceField(
         label=_('Type'),
         label=_('Type'),
@@ -1502,7 +1523,7 @@ class PowerPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
 class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = PowerOutlet
     model = PowerOutlet
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'label', 'type', 'color', 'status', name=_('Attributes')),
         FieldSet('name', 'label', 'type', 'color', 'status', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet(
         FieldSet(
@@ -1510,6 +1531,7 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
             name=_('Device')
             name=_('Device')
         ),
         ),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     type = forms.MultipleChoiceField(
     type = forms.MultipleChoiceField(
         label=_('Type'),
         label=_('Type'),
@@ -1545,7 +1567,7 @@ class PowerOutletTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
 class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
 class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
     model = Interface
     model = Interface
     fieldsets = (
     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('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only', name=_('Attributes')),
         FieldSet('vrf_id', 'l2vpn_id', 'mac_address', 'wwn', name=_('Addressing')),
         FieldSet('vrf_id', 'l2vpn_id', 'mac_address', 'wwn', name=_('Addressing')),
         FieldSet('poe_mode', 'poe_type', name=_('PoE')),
         FieldSet('poe_mode', 'poe_type', name=_('PoE')),
@@ -1558,6 +1580,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
             name=_('Device')
             name=_('Device')
         ),
         ),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
         FieldSet('cabled', 'connected', 'occupied', name=_('Connection')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     selector_fields = ('filter_id', 'q', 'device_id')
     selector_fields = ('filter_id', 'q', 'device_id')
     vdc_id = DynamicModelMultipleChoiceField(
     vdc_id = DynamicModelMultipleChoiceField(
@@ -1716,7 +1739,7 @@ class InterfaceTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
 
 
 class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
 class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'label', 'type', 'color', name=_('Attributes')),
         FieldSet('name', 'label', 'type', 'color', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet(
         FieldSet(
@@ -1724,6 +1747,7 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
             name=_('Device')
             name=_('Device')
         ),
         ),
         FieldSet('cabled', 'occupied', name=_('Cable')),
         FieldSet('cabled', 'occupied', name=_('Cable')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     model = FrontPort
     model = FrontPort
     type = forms.MultipleChoiceField(
     type = forms.MultipleChoiceField(
@@ -1759,7 +1783,7 @@ class FrontPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
 class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
 class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
     model = RearPort
     model = RearPort
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'label', 'type', 'color', name=_('Attributes')),
         FieldSet('name', 'label', 'type', 'color', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet(
         FieldSet(
@@ -1767,6 +1791,7 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
             name=_('Device')
             name=_('Device')
         ),
         ),
         FieldSet('cabled', 'occupied', name=_('Cable')),
         FieldSet('cabled', 'occupied', name=_('Cable')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     type = forms.MultipleChoiceField(
     type = forms.MultipleChoiceField(
         label=_('Type'),
         label=_('Type'),
@@ -1801,13 +1826,14 @@ class RearPortTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
 class ModuleBayFilterForm(DeviceComponentFilterForm):
 class ModuleBayFilterForm(DeviceComponentFilterForm):
     model = ModuleBay
     model = ModuleBay
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'label', 'position', name=_('Attributes')),
         FieldSet('name', 'label', 'position', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet(
         FieldSet(
             'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
             'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
             name=_('Device')
             name=_('Device')
         ),
         ),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
     position = forms.CharField(
     position = forms.CharField(
@@ -1832,13 +1858,14 @@ class ModuleBayTemplateFilterForm(ModularDeviceComponentTemplateFilterForm):
 class DeviceBayFilterForm(DeviceComponentFilterForm):
 class DeviceBayFilterForm(DeviceComponentFilterForm):
     model = DeviceBay
     model = DeviceBay
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'label', name=_('Attributes')),
         FieldSet('name', 'label', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
         FieldSet(
         FieldSet(
             'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
             'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
             name=_('Device')
             name=_('Device')
         ),
         ),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -1855,7 +1882,7 @@ class DeviceBayTemplateFilterForm(DeviceComponentTemplateFilterForm):
 class InventoryItemFilterForm(DeviceComponentFilterForm):
 class InventoryItemFilterForm(DeviceComponentFilterForm):
     model = InventoryItem
     model = InventoryItem
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet(
         FieldSet(
             'name', 'label', 'status', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered',
             'name', 'label', 'status', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered',
             name=_('Attributes')
             name=_('Attributes')
@@ -1865,6 +1892,7 @@ class InventoryItemFilterForm(DeviceComponentFilterForm):
             'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
             'tenant_id', 'device_type_id', 'device_role_id', 'device_id', 'device_status', 'virtual_chassis_id',
             name=_('Device')
             name=_('Device')
         ),
         ),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     role_id = DynamicModelMultipleChoiceField(
     role_id = DynamicModelMultipleChoiceField(
         queryset=InventoryItemRole.objects.all(),
         queryset=InventoryItemRole.objects.all(),
@@ -1925,7 +1953,8 @@ class InventoryItemTemplateFilterForm(DeviceComponentTemplateFilterForm):
 class InventoryItemRoleFilterForm(OrganizationalModelFilterSetForm):
 class InventoryItemRoleFilterForm(OrganizationalModelFilterSetForm):
     model = InventoryItemRole
     model = InventoryItemRole
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -1937,9 +1966,10 @@ class InventoryItemRoleFilterForm(OrganizationalModelFilterSetForm):
 class MACAddressFilterForm(PrimaryModelFilterSetForm):
 class MACAddressFilterForm(PrimaryModelFilterSetForm):
     model = MACAddress
     model = MACAddress
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('mac_address', name=_('Attributes')),
         FieldSet('mac_address', name=_('Attributes')),
         FieldSet('device_id', 'virtual_machine_id', 'assigned', 'primary', name=_('Assignments')),
         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')
     selector_fields = ('filter_id', 'q', 'device_id', 'virtual_machine_id')
     mac_address = forms.CharField(
     mac_address = forms.CharField(

+ 2 - 1
netbox/dcim/forms/object_create.py

@@ -3,6 +3,7 @@ from django.utils.translation import gettext_lazy as _
 
 
 from dcim.models import *
 from dcim.models import *
 from netbox.forms import NetBoxModelForm
 from netbox.forms import NetBoxModelForm
+from netbox.forms.mixins import OwnerMixin
 from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField
 from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField
 from utilities.forms.rendering import FieldSet, TabbedGroups
 from utilities.forms.rendering import FieldSet, TabbedGroups
 from utilities.forms.widgets import APISelect
 from utilities.forms.widgets import APISelect
@@ -271,7 +272,7 @@ class InventoryItemCreateForm(ComponentCreateForm, model_forms.InventoryItemForm
 # Virtual chassis
 # Virtual chassis
 #
 #
 
 
-class VirtualChassisCreateForm(NetBoxModelForm):
+class VirtualChassisCreateForm(OwnerMixin, NetBoxModelForm):
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         label=_('Region'),
         label=_('Region'),
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),

+ 33 - 69
netbox/extras/forms/filtersets.py

@@ -7,13 +7,12 @@ from extras.choices import *
 from extras.models import *
 from extras.models import *
 from netbox.events import get_event_type_choices
 from netbox.events import get_event_type_choices
 from netbox.forms import NetBoxModelFilterSetForm, PrimaryModelFilterSetForm
 from netbox.forms import NetBoxModelFilterSetForm, PrimaryModelFilterSetForm
-from netbox.forms.mixins import SavedFiltersMixin
+from netbox.forms.mixins import OwnerFilterMixin, SavedFiltersMixin
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
-from users.models import Group, Owner, User
+from users.models import Group, User
 from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
 from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
 from utilities.forms.fields import (
 from utilities.forms.fields import (
-    ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
-    TagFilterField,
+    ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, TagFilterField,
 )
 )
 from utilities.forms.rendering import FieldSet
 from utilities.forms.rendering import FieldSet
 from utilities.forms.widgets import DateTimePicker
 from utilities.forms.widgets import DateTimePicker
@@ -39,7 +38,7 @@ __all__ = (
 )
 )
 
 
 
 
-class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
+class CustomFieldFilterForm(OwnerFilterMixin, SavedFiltersMixin, FilterForm):
     model = CustomField
     model = CustomField
     fieldsets = (
     fieldsets = (
         FieldSet('q', 'filter_id'),
         FieldSet('q', 'filter_id'),
@@ -47,6 +46,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
         FieldSet('choice_set_id', 'related_object_type_id', name=_('Type Options')),
         FieldSet('choice_set_id', 'related_object_type_id', name=_('Type Options')),
         FieldSet('ui_visible', 'ui_editable', 'is_cloneable', name=_('Behavior')),
         FieldSet('ui_visible', 'ui_editable', 'is_cloneable', name=_('Behavior')),
         FieldSet('validation_minimum', 'validation_maximum', 'validation_regex', name=_('Validation')),
         FieldSet('validation_minimum', 'validation_maximum', 'validation_regex', name=_('Validation')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     object_type_id = ContentTypeMultipleChoiceField(
     object_type_id = ContentTypeMultipleChoiceField(
         queryset=ObjectType.objects.with_feature('custom_fields'),
         queryset=ObjectType.objects.with_feature('custom_fields'),
@@ -119,18 +119,14 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
         label=_('Validation regex'),
         label=_('Validation regex'),
         required=False
         required=False
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
-class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm):
+class CustomFieldChoiceSetFilterForm(OwnerFilterMixin, SavedFiltersMixin, FilterForm):
     model = CustomFieldChoiceSet
     model = CustomFieldChoiceSet
     fieldsets = (
     fieldsets = (
         FieldSet('q', 'filter_id'),
         FieldSet('q', 'filter_id'),
         FieldSet('base_choices', 'choice', name=_('Choices')),
         FieldSet('base_choices', 'choice', name=_('Choices')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     base_choices = forms.MultipleChoiceField(
     base_choices = forms.MultipleChoiceField(
         choices=CustomFieldChoiceSetBaseChoices,
         choices=CustomFieldChoiceSetBaseChoices,
@@ -139,18 +135,14 @@ class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm):
     choice = forms.CharField(
     choice = forms.CharField(
         required=False
         required=False
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
-class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
+class CustomLinkFilterForm(OwnerFilterMixin, SavedFiltersMixin, FilterForm):
     model = CustomLink
     model = CustomLink
     fieldsets = (
     fieldsets = (
         FieldSet('q', 'filter_id'),
         FieldSet('q', 'filter_id'),
         FieldSet('object_type_id', 'enabled', 'new_window', 'weight', name=_('Attributes')),
         FieldSet('object_type_id', 'enabled', 'new_window', 'weight', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     object_type_id = ContentTypeMultipleChoiceField(
     object_type_id = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         label=_('Object types'),
@@ -175,19 +167,15 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
         label=_('Weight'),
         label=_('Weight'),
         required=False
         required=False
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
-class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
+class ExportTemplateFilterForm(OwnerFilterMixin, SavedFiltersMixin, FilterForm):
     model = ExportTemplate
     model = ExportTemplate
     fieldsets = (
     fieldsets = (
         FieldSet('q', 'filter_id', 'object_type_id'),
         FieldSet('q', 'filter_id', 'object_type_id'),
         FieldSet('data_source_id', 'data_file_id', name=_('Data')),
         FieldSet('data_source_id', 'data_file_id', 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(
     data_source_id = DynamicModelMultipleChoiceField(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
@@ -226,11 +214,6 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
             choices=BOOLEAN_WITH_BLANK_CHOICES
             choices=BOOLEAN_WITH_BLANK_CHOICES
         )
         )
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
 class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm):
 class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm):
@@ -250,11 +233,12 @@ class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm):
     )
     )
 
 
 
 
-class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
+class SavedFilterFilterForm(OwnerFilterMixin, SavedFiltersMixin, FilterForm):
     model = SavedFilter
     model = SavedFilter
     fieldsets = (
     fieldsets = (
         FieldSet('q', 'filter_id'),
         FieldSet('q', 'filter_id'),
         FieldSet('object_type_id', 'enabled', 'shared', 'weight', name=_('Attributes')),
         FieldSet('object_type_id', 'enabled', 'shared', 'weight', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     object_type_id = ContentTypeMultipleChoiceField(
     object_type_id = ContentTypeMultipleChoiceField(
         label=_('Object types'),
         label=_('Object types'),
@@ -279,11 +263,6 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
         label=_('Weight'),
         label=_('Weight'),
         required=False
         required=False
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
 class TableConfigFilterForm(SavedFiltersMixin, FilterForm):
 class TableConfigFilterForm(SavedFiltersMixin, FilterForm):
@@ -317,11 +296,12 @@ class TableConfigFilterForm(SavedFiltersMixin, FilterForm):
     )
     )
 
 
 
 
-class WebhookFilterForm(NetBoxModelFilterSetForm):
+class WebhookFilterForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
     model = Webhook
     model = Webhook
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('payload_url', 'http_method', 'http_content_type', name=_('Attributes')),
         FieldSet('payload_url', 'http_method', 'http_content_type', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     http_content_type = forms.CharField(
     http_content_type = forms.CharField(
         label=_('HTTP content type'),
         label=_('HTTP content type'),
@@ -336,19 +316,15 @@ class WebhookFilterForm(NetBoxModelFilterSetForm):
         required=False,
         required=False,
         label=_('HTTP method')
         label=_('HTTP method')
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class EventRuleFilterForm(NetBoxModelFilterSetForm):
+class EventRuleFilterForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
     model = EventRule
     model = EventRule
     fieldsets = (
     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('object_type_id', 'event_type', 'action_type', 'enabled', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     object_type_id = ContentTypeMultipleChoiceField(
     object_type_id = ContentTypeMultipleChoiceField(
         queryset=ObjectType.objects.with_feature('event_rules'),
         queryset=ObjectType.objects.with_feature('event_rules'),
@@ -372,16 +348,16 @@ class EventRuleFilterForm(NetBoxModelFilterSetForm):
             choices=BOOLEAN_WITH_BLANK_CHOICES
             choices=BOOLEAN_WITH_BLANK_CHOICES
         )
         )
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class TagFilterForm(SavedFiltersMixin, FilterForm):
+class TagFilterForm(OwnerFilterMixin, SavedFiltersMixin, FilterForm):
     model = Tag
     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(
     content_type_id = ContentTypeMultipleChoiceField(
         queryset=ObjectType.objects.with_feature('tags'),
         queryset=ObjectType.objects.with_feature('tags'),
         required=False,
         required=False,
@@ -392,11 +368,6 @@ class TagFilterForm(SavedFiltersMixin, FilterForm):
         required=False,
         required=False,
         label=_('Allowed object type')
         label=_('Allowed object type')
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
 class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm):
 class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm):
@@ -404,6 +375,7 @@ class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm):
     fieldsets = (
     fieldsets = (
         FieldSet('q', 'filter_id'),
         FieldSet('q', 'filter_id'),
         FieldSet('data_source_id', 'data_file_id', name=_('Data')),
         FieldSet('data_source_id', 'data_file_id', name=_('Data')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     data_source_id = DynamicModelMultipleChoiceField(
     data_source_id = DynamicModelMultipleChoiceField(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
@@ -420,16 +392,17 @@ class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm):
     )
     )
 
 
 
 
-class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
+class ConfigContextFilterForm(OwnerFilterMixin, SavedFiltersMixin, FilterForm):
     model = ConfigContext
     model = ConfigContext
     fieldsets = (
     fieldsets = (
         FieldSet('q', 'filter_id', 'tag_id'),
         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('data_source_id', 'data_file_id', name=_('Data')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
         FieldSet('device_type_id', 'platform_id', 'device_role_id', name=_('Device')),
         FieldSet('device_type_id', 'platform_id', 'device_role_id', name=_('Device')),
         FieldSet('cluster_type_id', 'cluster_group_id', 'cluster_id', name=_('Cluster')),
         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(
     profile_id = DynamicModelMultipleChoiceField(
         queryset=ConfigContextProfile.objects.all(),
         queryset=ConfigContextProfile.objects.all(),
@@ -514,19 +487,15 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
         required=False,
         required=False,
         label=_('Tags')
         label=_('Tags')
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
-class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
+class ConfigTemplateFilterForm(OwnerFilterMixin, SavedFiltersMixin, FilterForm):
     model = ConfigTemplate
     model = ConfigTemplate
     fieldsets = (
     fieldsets = (
         FieldSet('q', 'filter_id', 'tag'),
         FieldSet('q', 'filter_id', 'tag'),
         FieldSet('data_source_id', 'data_file_id', 'auto_sync_enabled', name=_('Data')),
         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(
     data_source_id = DynamicModelMultipleChoiceField(
         queryset=DataSource.objects.all(),
         queryset=DataSource.objects.all(),
@@ -568,11 +537,6 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
             choices=BOOLEAN_WITH_BLANK_CHOICES
             choices=BOOLEAN_WITH_BLANK_CHOICES
         )
         )
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
 
 
 
 
 class LocalConfigContextFilterForm(forms.Form):
 class LocalConfigContextFilterForm(forms.Form):

+ 7 - 0
netbox/extras/forms/model_forms.py

@@ -178,6 +178,13 @@ class CustomFieldChoiceSetForm(ChangelogMessageMixin, OwnerMixin, forms.ModelFor
         ) + ' <code>choice1:First Choice</code>')
         ) + ' <code>choice1:First Choice</code>')
     )
     )
 
 
+    fieldsets = (
+        FieldSet(
+            'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically',
+            name=_('Custom Field Choice Set')
+        ),
+    )
+
     class Meta:
     class Meta:
         model = CustomFieldChoiceSet
         model = CustomFieldChoiceSet
         fields = ('name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'owner')
         fields = ('name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'owner')

+ 33 - 17
netbox/ipam/forms/filtersets.py

@@ -45,9 +45,10 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([
 class VRFFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class VRFFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = VRF
     model = VRF
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('import_target_id', 'export_target_id', name=_('Route Targets')),
         FieldSet('import_target_id', 'export_target_id', name=_('Route Targets')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     import_target_id = DynamicModelMultipleChoiceField(
     import_target_id = DynamicModelMultipleChoiceField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
@@ -65,9 +66,10 @@ class VRFFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class RouteTargetFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class RouteTargetFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = RouteTarget
     model = RouteTarget
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('importing_vrf_id', 'exporting_vrf_id', name=_('VRF')),
         FieldSet('importing_vrf_id', 'exporting_vrf_id', name=_('VRF')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     importing_vrf_id = DynamicModelMultipleChoiceField(
     importing_vrf_id = DynamicModelMultipleChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
@@ -85,8 +87,9 @@ class RouteTargetFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class RIRFilterForm(OrganizationalModelFilterSetForm):
 class RIRFilterForm(OrganizationalModelFilterSetForm):
     model = RIR
     model = RIR
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('is_private', name=_('RIR')),
         FieldSet('is_private', name=_('RIR')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     is_private = forms.NullBooleanField(
     is_private = forms.NullBooleanField(
         required=False,
         required=False,
@@ -101,9 +104,10 @@ class RIRFilterForm(OrganizationalModelFilterSetForm):
 class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
 class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
     model = Aggregate
     model = Aggregate
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('family', 'rir_id', name=_('Attributes')),
         FieldSet('family', 'rir_id', name=_('Attributes')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     family = forms.ChoiceField(
     family = forms.ChoiceField(
@@ -122,9 +126,10 @@ class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryMode
 class ASNRangeFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
 class ASNRangeFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
     model = ASNRange
     model = ASNRange
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('rir_id', 'start', 'end', name=_('Range')),
         FieldSet('rir_id', 'start', 'end', name=_('Range')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     rir_id = DynamicModelMultipleChoiceField(
     rir_id = DynamicModelMultipleChoiceField(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
@@ -145,9 +150,10 @@ class ASNRangeFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
 class ASNFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class ASNFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = ASN
     model = ASN
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('rir_id', 'site_group_id', 'site_id', name=_('Assignment')),
         FieldSet('rir_id', 'site_group_id', 'site_id', name=_('Assignment')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     rir_id = DynamicModelMultipleChoiceField(
     rir_id = DynamicModelMultipleChoiceField(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
@@ -170,7 +176,8 @@ class ASNFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class RoleFilterForm(OrganizationalModelFilterSetForm):
 class RoleFilterForm(OrganizationalModelFilterSetForm):
     model = Role
     model = Role
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -178,7 +185,7 @@ class RoleFilterForm(OrganizationalModelFilterSetForm):
 class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
 class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
     model = Prefix
     model = Prefix
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet(
         FieldSet(
             'within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized',
             'within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized',
             name=_('Addressing')
             name=_('Addressing')
@@ -187,6 +194,7 @@ class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFi
         FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')),
         FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     mask_length__lte = forms.IntegerField(
     mask_length__lte = forms.IntegerField(
@@ -284,9 +292,10 @@ class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFi
 class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
 class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
     model = IPRange
     model = IPRange
     fieldsets = (
     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('family', 'vrf_id', 'status', 'role_id', 'mark_populated', 'mark_utilized', name=_('Attributes')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     family = forms.ChoiceField(
     family = forms.ChoiceField(
@@ -331,14 +340,15 @@ class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelF
 class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
 class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
     model = IPAddress
     model = IPAddress
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet(
         FieldSet(
             'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface', 'dns_name',
             'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface', 'dns_name',
             name=_('Attributes')
             name=_('Attributes')
         ),
         ),
         FieldSet('vrf_id', 'present_in_vrf_id', name=_('VRF')),
         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('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')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     selector_fields = ('filter_id', 'q', 'region_id', 'group_id', 'parent', 'status', 'role')
     selector_fields = ('filter_id', 'q', 'region_id', 'group_id', 'parent', 'status', 'role')
@@ -409,9 +419,10 @@ class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryMode
 class FHRPGroupFilterForm(PrimaryModelFilterSetForm):
 class FHRPGroupFilterForm(PrimaryModelFilterSetForm):
     model = FHRPGroup
     model = FHRPGroup
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', 'protocol', 'group_id', name=_('Attributes')),
         FieldSet('name', 'protocol', 'group_id', name=_('Attributes')),
         FieldSet('auth_type', 'auth_key', name=_('Authentication')),
         FieldSet('auth_type', 'auth_key', name=_('Authentication')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     name = forms.CharField(
     name = forms.CharField(
         label=_('Name'),
         label=_('Name'),
@@ -441,11 +452,12 @@ class FHRPGroupFilterForm(PrimaryModelFilterSetForm):
 
 
 class VLANGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
 class VLANGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('region', 'site_group', 'site', 'location', 'rack', name=_('Location')),
         FieldSet('region', 'site_group', 'site', 'location', 'rack', name=_('Location')),
         FieldSet('cluster_group', 'cluster', name=_('Cluster')),
         FieldSet('cluster_group', 'cluster', name=_('Cluster')),
         FieldSet('contains_vid', name=_('VLANs')),
         FieldSet('contains_vid', name=_('VLANs')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     model = VLANGroup
     model = VLANGroup
     region = DynamicModelMultipleChoiceField(
     region = DynamicModelMultipleChoiceField(
@@ -495,8 +507,9 @@ class VLANGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
 class VLANTranslationPolicyFilterForm(PrimaryModelFilterSetForm):
 class VLANTranslationPolicyFilterForm(PrimaryModelFilterSetForm):
     model = VLANTranslationPolicy
     model = VLANTranslationPolicy
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('name', name=_('Attributes')),
         FieldSet('name', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     name = forms.CharField(
     name = forms.CharField(
         required=False,
         required=False,
@@ -532,11 +545,12 @@ class VLANTranslationRuleFilterForm(NetBoxModelFilterSetForm):
 class VLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class VLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = VLAN
     model = VLAN
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
         FieldSet('group_id', 'status', 'role_id', 'vid', 'l2vpn_id', name=_('Attributes')),
         FieldSet('group_id', 'status', 'role_id', 'vid', 'l2vpn_id', name=_('Attributes')),
         FieldSet('qinq_role', 'qinq_svlan_id', name=_('Q-in-Q/802.1ad')),
         FieldSet('qinq_role', 'qinq_svlan_id', name=_('Q-in-Q/802.1ad')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     selector_fields = ('filter_id', 'q', 'group_id')
     selector_fields = ('filter_id', 'q', 'group_id')
     region_id = DynamicModelMultipleChoiceField(
     region_id = DynamicModelMultipleChoiceField(
@@ -604,8 +618,9 @@ class VLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class ServiceTemplateFilterForm(PrimaryModelFilterSetForm):
 class ServiceTemplateFilterForm(PrimaryModelFilterSetForm):
     model = ServiceTemplate
     model = ServiceTemplate
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('protocol', 'port', name=_('Attributes')),
         FieldSet('protocol', 'port', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     protocol = forms.ChoiceField(
     protocol = forms.ChoiceField(
         label=_('Protocol'),
         label=_('Protocol'),
@@ -622,9 +637,10 @@ class ServiceTemplateFilterForm(PrimaryModelFilterSetForm):
 class ServiceFilterForm(ContactModelFilterForm, ServiceTemplateFilterForm):
 class ServiceFilterForm(ContactModelFilterForm, ServiceTemplateFilterForm):
     model = Service
     model = Service
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('protocol', 'port', name=_('Attributes')),
         FieldSet('protocol', 'port', name=_('Attributes')),
         FieldSet('device_id', 'virtual_machine_id', 'fhrpgroup_id', name=_('Assignment')),
         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')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     device_id = DynamicModelMultipleChoiceField(
     device_id = DynamicModelMultipleChoiceField(

+ 2 - 11
netbox/netbox/forms/filtersets.py

@@ -3,10 +3,9 @@ from django.db.models import Q
 from django.utils.translation import gettext_lazy as _
 from django.utils.translation import gettext_lazy as _
 
 
 from extras.choices import *
 from extras.choices import *
-from users.models import Owner
-from utilities.forms.fields import DynamicModelChoiceField, QueryField
+from utilities.forms.fields import QueryField
 from utilities.forms.mixins import FilterModifierMixin
 from utilities.forms.mixins import FilterModifierMixin
-from .mixins import CustomFieldsMixin, SavedFiltersMixin
+from .mixins import CustomFieldsMixin, OwnerFilterMixin, SavedFiltersMixin
 
 
 __all__ = (
 __all__ = (
     'NestedGroupModelFilterSetForm',
     'NestedGroupModelFilterSetForm',
@@ -47,14 +46,6 @@ class NetBoxModelFilterSetForm(FilterModifierMixin, CustomFieldsMixin, SavedFilt
         )
         )
 
 
 
 
-class OwnerFilterMixin(forms.Form):
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
-
-
 class PrimaryModelFilterSetForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
 class PrimaryModelFilterSetForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
     """
     """
     FilterSet form for models which inherit from PrimaryModel.
     FilterSet form for models which inherit from PrimaryModel.

+ 57 - 4
netbox/netbox/forms/mixins.py

@@ -4,13 +4,14 @@ from django.utils.translation import gettext as _
 from core.models import ObjectType
 from core.models import ObjectType
 from extras.choices import *
 from extras.choices import *
 from extras.models import *
 from extras.models import *
-from users.models import Owner
+from users.models import OwnerGroup, Owner
 from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField
 from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField
 
 
 __all__ = (
 __all__ = (
     'ChangelogMessageMixin',
     'ChangelogMessageMixin',
     'CustomFieldsMixin',
     'CustomFieldsMixin',
     'OwnerMixin',
     'OwnerMixin',
+    'OwnerFilterMixin',
     'SavedFiltersMixin',
     'SavedFiltersMixin',
     'TagsMixin',
     'TagsMixin',
 )
 )
@@ -22,7 +23,7 @@ class ChangelogMessageMixin(forms.Form):
     """
     """
     changelog_message = forms.CharField(
     changelog_message = forms.CharField(
         required=False,
         required=False,
-        max_length=200
+        max_length=200,
     )
     )
 
 
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
@@ -42,6 +43,7 @@ class CustomFieldsMixin:
     Attributes:
     Attributes:
         model: The model class
         model: The model class
     """
     """
+
     model = None
     model = None
 
 
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
@@ -86,13 +88,20 @@ class CustomFieldsMixin:
 
 
 
 
 class SavedFiltersMixin(forms.Form):
 class SavedFiltersMixin(forms.Form):
+    """
+    Form mixin for forms that support saved filters.
+
+    Provides a field for selecting a saved filter,
+    with options limited to those applicable to the form's model.
+    """
+
     filter_id = DynamicModelMultipleChoiceField(
     filter_id = DynamicModelMultipleChoiceField(
         queryset=SavedFilter.objects.all(),
         queryset=SavedFilter.objects.all(),
         required=False,
         required=False,
         label=_('Saved Filter'),
         label=_('Saved Filter'),
         query_params={
         query_params={
             'usable': True,
             'usable': True,
-        }
+        },
     )
     )
 
 
     def __init__(self, *args, **kwargs):
     def __init__(self, *args, **kwargs):
@@ -107,6 +116,13 @@ class SavedFiltersMixin(forms.Form):
 
 
 
 
 class TagsMixin(forms.Form):
 class TagsMixin(forms.Form):
+    """
+    Mixin for forms that support tagging.
+
+    Provides a field for selecting tags,
+    with options limited to those applicable to the form's model.
+    """
+
     tags = DynamicModelMultipleChoiceField(
     tags = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         required=False,
         required=False,
@@ -124,10 +140,47 @@ class TagsMixin(forms.Form):
 
 
 class OwnerMixin(forms.Form):
 class OwnerMixin(forms.Form):
     """
     """
-    Add an `owner` field to forms for models which support Owner assignment.
+    Mixin for forms which adds ownership fields.
+
+    Include this mixin in forms for models which
+    support owner and/or owner group assignment.
     """
     """
+
+    owner_group = DynamicModelChoiceField(
+        label=_('Owner group'),
+        queryset=OwnerGroup.objects.all(),
+        required=False,
+        null_option='None',
+        initial_params={'members': '$owner'},
+    )
     owner = DynamicModelChoiceField(
     owner = DynamicModelChoiceField(
         queryset=Owner.objects.all(),
         queryset=Owner.objects.all(),
         required=False,
         required=False,
+        query_params={'group_id': '$owner_group'},
+        label=_('Owner'),
+    )
+
+
+class OwnerFilterMixin(forms.Form):
+    """
+    Mixin for filterset forms which adds owner and owner group filtering.
+
+    Include this mixin in filterset forms for models
+    which support owner and/or owner group assignment.
+    """
+
+    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'),
         label=_('Owner'),
     )
     )

+ 18 - 3
netbox/netbox/tables/tables.py

@@ -271,9 +271,14 @@ class NetBoxTable(BaseTable):
 
 
 
 
 class PrimaryModelTable(NetBoxTable):
 class PrimaryModelTable(NetBoxTable):
+    owner_group = tables.Column(
+        accessor='owner__group',
+        linkify=True,
+        verbose_name=_('Owner Group'),
+    )
     owner = tables.Column(
     owner = tables.Column(
         linkify=True,
         linkify=True,
-        verbose_name=_('Owner')
+        verbose_name=_('Owner'),
     )
     )
     comments = columns.MarkdownColumn(
     comments = columns.MarkdownColumn(
         verbose_name=_('Comments'),
         verbose_name=_('Comments'),
@@ -281,9 +286,14 @@ class PrimaryModelTable(NetBoxTable):
 
 
 
 
 class OrganizationalModelTable(NetBoxTable):
 class OrganizationalModelTable(NetBoxTable):
+    owner_group = tables.Column(
+        accessor='owner__group',
+        linkify=True,
+        verbose_name=_('Owner Group'),
+    )
     owner = tables.Column(
     owner = tables.Column(
         linkify=True,
         linkify=True,
-        verbose_name=_('Owner')
+        verbose_name=_('Owner'),
     )
     )
     comments = columns.MarkdownColumn(
     comments = columns.MarkdownColumn(
         verbose_name=_('Comments'),
         verbose_name=_('Comments'),
@@ -291,9 +301,14 @@ class OrganizationalModelTable(NetBoxTable):
 
 
 
 
 class NestedGroupModelTable(NetBoxTable):
 class NestedGroupModelTable(NetBoxTable):
+    owner_group = tables.Column(
+        accessor='owner__group',
+        linkify=True,
+        verbose_name=_('Owner Group'),
+    )
     owner = tables.Column(
     owner = tables.Column(
         linkify=True,
         linkify=True,
-        verbose_name=_('Owner')
+        verbose_name=_('Owner'),
     )
     )
     name = columns.MPTTColumn(
     name = columns.MPTTColumn(
         verbose_name=_('Name'),
         verbose_name=_('Name'),

+ 2 - 1
netbox/templates/dcim/device_edit.html

@@ -101,8 +101,9 @@
 
 
     <div class="field-group mb-5">
     <div class="field-group mb-5">
       <div class="row">
       <div class="row">
-        <h2 class="col-9 offset-3">{% trans "Owner" %}</h2>
+        <h2 class="col-9 offset-3">{% trans "Ownership" %}</h2>
       </div>
       </div>
+      {% render_field form.owner_group %}
       {% render_field form.owner %}
       {% render_field form.owner %}
     </div>
     </div>
 
 

+ 2 - 1
netbox/templates/dcim/htmx/cable_edit.html

@@ -80,8 +80,9 @@
 
 
 <div class="field-group mb-5">
 <div class="field-group mb-5">
   <div class="row">
   <div class="row">
-    <h2 class="col-9 offset-3">{% trans "Owner" %}</h2>
+    <h2 class="col-9 offset-3">{% trans "Ownership" %}</h2>
   </div>
   </div>
+  {% render_field form.owner_group %}
   {% render_field form.owner %}
   {% render_field form.owner %}
 </div>
 </div>
 
 

+ 2 - 1
netbox/templates/dcim/virtualchassis_edit.html

@@ -36,8 +36,9 @@
 
 
       <div class="field-group mb-5">
       <div class="field-group mb-5">
         <div class="row">
         <div class="row">
-          <h2 class="col-9 offset-3">{% trans "Owner" %}</h2>
+          <h2 class="col-9 offset-3">{% trans "Ownership" %}</h2>
         </div>
         </div>
+        {% render_field vc_form.owner_group %}
         {% render_field vc_form.owner %}
         {% render_field vc_form.owner %}
       </div>
       </div>
 
 

+ 4 - 1
netbox/templates/generic/bulk_edit.html

@@ -62,8 +62,11 @@ Context:
           {% if form.owner %}
           {% if form.owner %}
             <div class="field-group mb-5">
             <div class="field-group mb-5">
               <div class="row">
               <div class="row">
-                <h2 class="col-9 offset-3">{% trans "Owner" %}</h2>
+                <h2 class="col-9 offset-3">{% trans "Ownership" %}</h2>
               </div>
               </div>
+              {% if form.owner_group %}
+                {% render_field form.owner_group %}
+              {% endif %}
               {% render_field form.owner bulk_nullable=True %}
               {% render_field form.owner bulk_nullable=True %}
             </div>
             </div>
           {% endif %}
           {% endif %}

+ 3 - 0
netbox/templates/htmx/form.html

@@ -27,6 +27,9 @@
       <div class="row">
       <div class="row">
         <h2 class="col-9 offset-3">{% trans "Ownership" %}</h2>
         <h2 class="col-9 offset-3">{% trans "Ownership" %}</h2>
       </div>
       </div>
+      {% if form.owner_group %}
+        {% render_field form.owner_group %}
+      {% endif %}
       {% render_field form.owner %}
       {% render_field form.owner %}
     </div>
     </div>
   {% endif %}
   {% endif %}

+ 2 - 1
netbox/templates/ipam/vlan_edit.html

@@ -67,8 +67,9 @@
 
 
   <div class="field-group mb-5">
   <div class="field-group mb-5">
     <div class="row">
     <div class="row">
-      <h2 class="col-9 offset-3">{% trans "Owner" %}</h2>
+      <h2 class="col-9 offset-3">{% trans "Ownership" %}</h2>
     </div>
     </div>
+    {% render_field form.owner_group %}
     {% render_field form.owner %}
     {% render_field form.owner %}
   </div>
   </div>
 
 

+ 10 - 5
netbox/tenancy/forms/filtersets.py

@@ -31,8 +31,9 @@ __all__ = (
 class TenantGroupFilterForm(NestedGroupModelFilterSetForm):
 class TenantGroupFilterForm(NestedGroupModelFilterSetForm):
     model = TenantGroup
     model = TenantGroup
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('parent_id', name=_('Tenant Group')),
         FieldSet('parent_id', name=_('Tenant Group')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
@@ -45,8 +46,9 @@ class TenantGroupFilterForm(NestedGroupModelFilterSetForm):
 class TenantFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
 class TenantFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
     model = Tenant
     model = Tenant
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('group_id', name=_('Tenant')),
         FieldSet('group_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
     )
     )
     group_id = DynamicModelMultipleChoiceField(
     group_id = DynamicModelMultipleChoiceField(
@@ -65,8 +67,9 @@ class TenantFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
 class ContactGroupFilterForm(NestedGroupModelFilterSetForm):
 class ContactGroupFilterForm(NestedGroupModelFilterSetForm):
     model = ContactGroup
     model = ContactGroup
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('parent_id', name=_('Contact Group')),
         FieldSet('parent_id', name=_('Contact Group')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),
@@ -79,7 +82,8 @@ class ContactGroupFilterForm(NestedGroupModelFilterSetForm):
 class ContactRoleFilterForm(OrganizationalModelFilterSetForm):
 class ContactRoleFilterForm(OrganizationalModelFilterSetForm):
     model = ContactRole
     model = ContactRole
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -87,8 +91,9 @@ class ContactRoleFilterForm(OrganizationalModelFilterSetForm):
 class ContactFilterForm(PrimaryModelFilterSetForm):
 class ContactFilterForm(PrimaryModelFilterSetForm):
     model = Contact
     model = Contact
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('group_id', name=_('Contact')),
         FieldSet('group_id', name=_('Contact')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     group_id = DynamicModelMultipleChoiceField(
     group_id = DynamicModelMultipleChoiceField(
         queryset=ContactGroup.objects.all(),
         queryset=ContactGroup.objects.all(),

+ 12 - 1
netbox/users/filterset_mixins.py

@@ -1,7 +1,7 @@
 import django_filters
 import django_filters
 from django.utils.translation import gettext as _
 from django.utils.translation import gettext as _
 
 
-from users.models import Owner
+from users.models import OwnerGroup, Owner
 
 
 __all__ = (
 __all__ = (
     'OwnerFilterMixin',
     'OwnerFilterMixin',
@@ -12,6 +12,17 @@ class OwnerFilterMixin(django_filters.FilterSet):
     """
     """
     Adds owner & owner_id filters for models which inherit from OwnerMixin.
     Adds owner & owner_id filters for models which inherit from OwnerMixin.
     """
     """
+    owner_group_id = django_filters.ModelMultipleChoiceFilter(
+        queryset=OwnerGroup.objects.all(),
+        field_name='owner__group',
+        label=_('Owner Group (ID)'),
+    )
+    owner_group = django_filters.ModelMultipleChoiceFilter(
+        queryset=OwnerGroup.objects.all(),
+        field_name='owner__group__name',
+        to_field_name='name',
+        label=_('Owner Group (name)'),
+    )
     owner_id = django_filters.ModelMultipleChoiceFilter(
     owner_id = django_filters.ModelMultipleChoiceFilter(
         queryset=Owner.objects.all(),
         queryset=Owner.objects.all(),
         label=_('Owner (ID)'),
         label=_('Owner (ID)'),

+ 16 - 20
netbox/virtualization/forms/filtersets.py

@@ -7,10 +7,10 @@ from extras.forms import LocalConfigContextFilterForm
 from extras.models import ConfigTemplate
 from extras.models import ConfigTemplate
 from ipam.models import VRF, VLANTranslationPolicy
 from ipam.models import VRF, VLANTranslationPolicy
 from netbox.forms import NetBoxModelFilterSetForm, OrganizationalModelFilterSetForm, PrimaryModelFilterSetForm
 from netbox.forms import NetBoxModelFilterSetForm, OrganizationalModelFilterSetForm, PrimaryModelFilterSetForm
+from netbox.forms.mixins import OwnerFilterMixin
 from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
 from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
-from users.models import Owner
 from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES
 from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES
-from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField
+from utilities.forms.fields import DynamicModelMultipleChoiceField, TagFilterField
 from utilities.forms.rendering import FieldSet
 from utilities.forms.rendering import FieldSet
 from virtualization.choices import *
 from virtualization.choices import *
 from virtualization.models import *
 from virtualization.models import *
@@ -29,7 +29,8 @@ __all__ = (
 class ClusterTypeFilterForm(OrganizationalModelFilterSetForm):
 class ClusterTypeFilterForm(OrganizationalModelFilterSetForm):
     model = ClusterType
     model = ClusterType
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -38,7 +39,8 @@ class ClusterGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSe
     model = ClusterGroup
     model = ClusterGroup
     tag = TagFilterField(model)
     tag = TagFilterField(model)
     fieldsets = (
     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')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
 
 
@@ -46,10 +48,11 @@ class ClusterGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSe
 class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
 class ClusterFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
     model = Cluster
     model = Cluster
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('group_id', 'type_id', 'status', name=_('Attributes')),
         FieldSet('group_id', 'type_id', 'status', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     selector_fields = ('filter_id', 'q', 'group_id')
     selector_fields = ('filter_id', 'q', 'group_id')
@@ -105,7 +108,7 @@ class VirtualMachineFilterForm(
 ):
 ):
     model = VirtualMachine
     model = VirtualMachine
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id', name=_('Cluster')),
         FieldSet('cluster_group_id', 'cluster_type_id', 'cluster_id', 'device_id', name=_('Cluster')),
         FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
         FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
         FieldSet(
         FieldSet(
@@ -113,6 +116,7 @@ class VirtualMachineFilterForm(
             'local_context_data', 'serial', name=_('Attributes')
             'local_context_data', 'serial', name=_('Attributes')
         ),
         ),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     cluster_group_id = DynamicModelMultipleChoiceField(
     cluster_group_id = DynamicModelMultipleChoiceField(
@@ -205,14 +209,15 @@ class VirtualMachineFilterForm(
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class VMInterfaceFilterForm(NetBoxModelFilterSetForm):
+class VMInterfaceFilterForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
     model = VMInterface
     model = VMInterface
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('cluster_id', 'virtual_machine_id', name=_('Virtual Machine')),
         FieldSet('cluster_id', 'virtual_machine_id', name=_('Virtual Machine')),
         FieldSet('enabled', name=_('Attributes')),
         FieldSet('enabled', name=_('Attributes')),
         FieldSet('vrf_id', 'l2vpn_id', 'mac_address', name=_('Addressing')),
         FieldSet('vrf_id', 'l2vpn_id', 'mac_address', name=_('Addressing')),
         FieldSet('mode', 'vlan_translation_policy_id', name=_('802.1Q Switching')),
         FieldSet('mode', 'vlan_translation_policy_id', name=_('802.1Q Switching')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     selector_fields = ('filter_id', 'q', 'virtual_machine_id')
     selector_fields = ('filter_id', 'q', 'virtual_machine_id')
     cluster_id = DynamicModelMultipleChoiceField(
     cluster_id = DynamicModelMultipleChoiceField(
@@ -259,20 +264,16 @@ class VMInterfaceFilterForm(NetBoxModelFilterSetForm):
         required=False,
         required=False,
         label=_('VLAN Translation Policy')
         label=_('VLAN Translation Policy')
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
 
 
-class VirtualDiskFilterForm(NetBoxModelFilterSetForm):
+class VirtualDiskFilterForm(OwnerFilterMixin, NetBoxModelFilterSetForm):
     model = VirtualDisk
     model = VirtualDisk
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('virtual_machine_id', name=_('Virtual Machine')),
         FieldSet('virtual_machine_id', name=_('Virtual Machine')),
         FieldSet('size', name=_('Attributes')),
         FieldSet('size', name=_('Attributes')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     virtual_machine_id = DynamicModelMultipleChoiceField(
     virtual_machine_id = DynamicModelMultipleChoiceField(
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
@@ -284,9 +285,4 @@ class VirtualDiskFilterForm(NetBoxModelFilterSetForm):
         required=False,
         required=False,
         min_value=1
         min_value=1
     )
     )
-    owner_id = DynamicModelChoiceField(
-        queryset=Owner.objects.all(),
-        required=False,
-        label=_('Owner'),
-    )
     tag = TagFilterField(model)
     tag = TagFilterField(model)

+ 16 - 8
netbox/vpn/forms/filtersets.py

@@ -33,7 +33,8 @@ __all__ = (
 class TunnelGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSetForm):
 class TunnelGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSetForm):
     model = TunnelGroup
     model = TunnelGroup
     fieldsets = (
     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')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
@@ -42,10 +43,11 @@ class TunnelGroupFilterForm(ContactModelFilterForm, OrganizationalModelFilterSet
 class TunnelFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
 class TunnelFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
     model = Tunnel
     model = Tunnel
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('status', 'encapsulation', 'tunnel_id', name=_('Tunnel')),
         FieldSet('status', 'encapsulation', 'tunnel_id', name=_('Tunnel')),
         FieldSet('ipsec_profile_id', name=_('Security')),
         FieldSet('ipsec_profile_id', name=_('Security')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenancy')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenancy')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
         FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
@@ -97,10 +99,11 @@ class TunnelTerminationFilterForm(NetBoxModelFilterSetForm):
 class IKEProposalFilterForm(PrimaryModelFilterSetForm):
 class IKEProposalFilterForm(PrimaryModelFilterSetForm):
     model = IKEProposal
     model = IKEProposal
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet(
         FieldSet(
             'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group', name=_('Parameters')
             'authentication_method', 'encryption_algorithm', 'authentication_algorithm', 'group', name=_('Parameters')
         ),
         ),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     authentication_method = forms.MultipleChoiceField(
     authentication_method = forms.MultipleChoiceField(
         label=_('Authentication method'),
         label=_('Authentication method'),
@@ -128,8 +131,9 @@ class IKEProposalFilterForm(PrimaryModelFilterSetForm):
 class IKEPolicyFilterForm(PrimaryModelFilterSetForm):
 class IKEPolicyFilterForm(PrimaryModelFilterSetForm):
     model = IKEPolicy
     model = IKEPolicy
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('version', 'mode', 'proposal_id', name=_('Parameters')),
         FieldSet('version', 'mode', 'proposal_id', name=_('Parameters')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     version = forms.MultipleChoiceField(
     version = forms.MultipleChoiceField(
         label=_('IKE version'),
         label=_('IKE version'),
@@ -152,8 +156,9 @@ class IKEPolicyFilterForm(PrimaryModelFilterSetForm):
 class IPSecProposalFilterForm(PrimaryModelFilterSetForm):
 class IPSecProposalFilterForm(PrimaryModelFilterSetForm):
     model = IPSecProposal
     model = IPSecProposal
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('encryption_algorithm', 'authentication_algorithm', name=_('Parameters')),
         FieldSet('encryption_algorithm', 'authentication_algorithm', name=_('Parameters')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     encryption_algorithm = forms.MultipleChoiceField(
     encryption_algorithm = forms.MultipleChoiceField(
         label=_('Encryption algorithm'),
         label=_('Encryption algorithm'),
@@ -171,8 +176,9 @@ class IPSecProposalFilterForm(PrimaryModelFilterSetForm):
 class IPSecPolicyFilterForm(PrimaryModelFilterSetForm):
 class IPSecPolicyFilterForm(PrimaryModelFilterSetForm):
     model = IPSecPolicy
     model = IPSecPolicy
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('proposal_id', 'pfs_group', name=_('Parameters')),
         FieldSet('proposal_id', 'pfs_group', name=_('Parameters')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     proposal_id = DynamicModelMultipleChoiceField(
     proposal_id = DynamicModelMultipleChoiceField(
         queryset=IKEProposal.objects.all(),
         queryset=IKEProposal.objects.all(),
@@ -190,8 +196,9 @@ class IPSecPolicyFilterForm(PrimaryModelFilterSetForm):
 class IPSecProfileFilterForm(PrimaryModelFilterSetForm):
 class IPSecProfileFilterForm(PrimaryModelFilterSetForm):
     model = IPSecProfile
     model = IPSecProfile
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('mode', 'ike_policy_id', 'ipsec_policy_id', name=_('Profile')),
         FieldSet('mode', 'ike_policy_id', 'ipsec_policy_id', name=_('Profile')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     mode = forms.MultipleChoiceField(
     mode = forms.MultipleChoiceField(
         label=_('Mode'),
         label=_('Mode'),
@@ -214,9 +221,10 @@ class IPSecProfileFilterForm(PrimaryModelFilterSetForm):
 class L2VPNFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
 class L2VPNFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
     model = L2VPN
     model = L2VPN
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('type', 'status', 'import_target_id', 'export_target_id', name=_('Attributes')),
         FieldSet('type', 'status', 'import_target_id', 'export_target_id', name=_('Attributes')),
         FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         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('contact', 'contact_role', 'contact_group', name=_('Contacts')),
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(

+ 8 - 5
netbox/wireless/forms/filtersets.py

@@ -22,8 +22,9 @@ __all__ = (
 class WirelessLANGroupFilterForm(NestedGroupModelFilterSetForm):
 class WirelessLANGroupFilterForm(NestedGroupModelFilterSetForm):
     model = WirelessLANGroup
     model = WirelessLANGroup
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('parent_id', name=_('Wireless LAN group')),
         FieldSet('parent_id', name=_('Wireless LAN group')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     parent_id = DynamicModelMultipleChoiceField(
     parent_id = DynamicModelMultipleChoiceField(
         queryset=WirelessLANGroup.objects.all(),
         queryset=WirelessLANGroup.objects.all(),
@@ -36,11 +37,12 @@ class WirelessLANGroupFilterForm(NestedGroupModelFilterSetForm):
 class WirelessLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class WirelessLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = WirelessLAN
     model = WirelessLAN
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('ssid', 'group_id', 'status', name=_('Attributes')),
         FieldSet('ssid', 'group_id', 'status', name=_('Attributes')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
         FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Scope')),
-        FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')),
         FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')),
+        FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     ssid = forms.CharField(
     ssid = forms.CharField(
         required=False,
         required=False,
@@ -102,10 +104,11 @@ class WirelessLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class WirelessLinkFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
 class WirelessLinkFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
     model = WirelessLink
     model = WirelessLink
     fieldsets = (
     fieldsets = (
-        FieldSet('q', 'filter_id', 'tag', 'owner_id'),
+        FieldSet('q', 'filter_id', 'tag'),
         FieldSet('ssid', 'status', 'distance', 'distance_unit', name=_('Attributes')),
         FieldSet('ssid', 'status', 'distance', 'distance_unit', name=_('Attributes')),
-        FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
         FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')),
         FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')),
+        FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
+        FieldSet('owner_group_id', 'owner_id', name=_('Ownership')),
     )
     )
     ssid = forms.CharField(
     ssid = forms.CharField(
         required=False,
         required=False,