Răsfoiți Sursa

Closes #5894: Use primary keys when filtering object lists by related objects in the UI

Jeremy Stretch 5 ani în urmă
părinte
comite
6ed2e7b636

+ 1 - 0
docs/release-notes/version-2.11.md

@@ -9,6 +9,7 @@
 * [#5370](https://github.com/netbox-community/netbox/issues/5370) - Extend custom field support to organizational models
 * [#5370](https://github.com/netbox-community/netbox/issues/5370) - Extend custom field support to organizational models
 * [#5401](https://github.com/netbox-community/netbox/issues/5401) - Extend custom field support to device component models
 * [#5401](https://github.com/netbox-community/netbox/issues/5401) - Extend custom field support to device component models
 * [#5451](https://github.com/netbox-community/netbox/issues/5451) - Add support for multiple-selection custom fields
 * [#5451](https://github.com/netbox-community/netbox/issues/5451) - Add support for multiple-selection custom fields
+* [#5894](https://github.com/netbox-community/netbox/issues/5894) - Use primary keys when filtering object lists by related objects in the UI
 * [#5901](https://github.com/netbox-community/netbox/issues/5901) - Add `created` and `last_updated` fields to device component models
 * [#5901](https://github.com/netbox-community/netbox/issues/5901) - Add `created` and `last_updated` fields to device component models
 
 
 ### Other Changes
 ### Other Changes

+ 27 - 26
netbox/circuits/forms.py

@@ -1,4 +1,5 @@
 from django import forms
 from django import forms
+from django.utils.translation import gettext as _
 
 
 from dcim.models import Region, Site
 from dcim.models import Region, Site
 from extras.forms import (
 from extras.forms import (
@@ -8,7 +9,7 @@ from extras.models import Tag
 from tenancy.forms import TenancyFilterForm, TenancyForm
 from tenancy.forms import TenancyFilterForm, TenancyForm
 from tenancy.models import Tenant
 from tenancy.models import Tenant
 from utilities.forms import (
 from utilities.forms import (
-    add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, CSVModelChoiceField, CSVModelForm, DatePicker,
+    add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, CSVModelChoiceField, DatePicker,
     DynamicModelChoiceField, DynamicModelMultipleChoiceField, SelectSpeedWidget, SmallTextarea, SlugField,
     DynamicModelChoiceField, DynamicModelMultipleChoiceField, SelectSpeedWidget, SmallTextarea, SlugField,
     StaticSelect2, StaticSelect2Multiple, TagFilterField,
     StaticSelect2, StaticSelect2Multiple, TagFilterField,
 )
 )
@@ -105,24 +106,24 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Provider
     model = Provider
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     asn = forms.IntegerField(
     asn = forms.IntegerField(
         required=False,
         required=False,
-        label='ASN'
+        label=_('ASN')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -265,44 +266,44 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
 class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Circuit
     model = Circuit
     field_order = [
     field_order = [
-        'q', 'type', 'provider', 'status', 'region', 'site', 'tenant_group', 'tenant', 'commit_rate',
+        'q', 'type_id', 'provider_id', 'status', 'region_id', 'site_id', 'tenant_group_id', 'tenant_id', 'commit_rate',
     ]
     ]
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    type = DynamicModelMultipleChoiceField(
+    type_id = DynamicModelMultipleChoiceField(
         queryset=CircuitType.objects.all(),
         queryset=CircuitType.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Type')
     )
     )
-    provider = DynamicModelMultipleChoiceField(
+    provider_id = DynamicModelMultipleChoiceField(
         queryset=Provider.objects.all(),
         queryset=Provider.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Provider')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=CircuitStatusChoices,
         choices=CircuitStatusChoices,
         required=False,
         required=False,
         widget=StaticSelect2Multiple()
         widget=StaticSelect2Multiple()
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     commit_rate = forms.IntegerField(
     commit_rate = forms.IntegerField(
         required=False,
         required=False,
         min_value=0,
         min_value=0,
-        label='Commit rate (Kbps)'
+        label=_('Commit rate (Kbps)')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 

+ 168 - 184
netbox/dcim/forms.py

@@ -6,6 +6,7 @@ from django.contrib.contenttypes.models import ContentType
 from django.contrib.postgres.forms.array import SimpleArrayField
 from django.contrib.postgres.forms.array import SimpleArrayField
 from django.core.exceptions import ObjectDoesNotExist
 from django.core.exceptions import ObjectDoesNotExist
 from django.utils.safestring import mark_safe
 from django.utils.safestring import mark_safe
+from django.utils.translation import gettext as _
 from netaddr import EUI
 from netaddr import EUI
 from netaddr.core import AddrFormatError
 from netaddr.core import AddrFormatError
 from timezone_field import TimeZoneFormField
 from timezone_field import TimeZoneFormField
@@ -19,7 +20,7 @@ from extras.models import Tag
 from ipam.constants import BGP_ASN_MAX, BGP_ASN_MIN
 from ipam.constants import BGP_ASN_MAX, BGP_ASN_MIN
 from ipam.models import IPAddress, VLAN
 from ipam.models import IPAddress, VLAN
 from tenancy.forms import TenancyFilterForm, TenancyForm
 from tenancy.forms import TenancyFilterForm, TenancyForm
-from tenancy.models import Tenant, TenantGroup
+from tenancy.models import Tenant
 from utilities.forms import (
 from utilities.forms import (
     APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
     APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
     ColorSelect, CommentField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, DynamicModelChoiceField,
     ColorSelect, CommentField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, DynamicModelChoiceField,
@@ -59,32 +60,32 @@ def get_device_by_name_or_pk(name):
 
 
 class DeviceComponentFilterForm(BootstrapMixin, CustomFieldFilterForm):
 class DeviceComponentFilterForm(BootstrapMixin, CustomFieldFilterForm):
     field_order = [
     field_order = [
-        'q', 'region', 'site'
+        'q', 'region_id', 'site_id'
     ]
     ]
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     device_id = DynamicModelMultipleChoiceField(
     device_id = DynamicModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,
-        label='Device',
         query_params={
         query_params={
-            'site': '$site'
-        }
+            'site_id': '$site_id'
+        },
+        label=_('Device')
     )
     )
 
 
 
 
@@ -203,7 +204,7 @@ class RegionFilterForm(BootstrapMixin, forms.Form):
     model = Site
     model = Site
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
 
 
 
 
@@ -337,20 +338,20 @@ class SiteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
 
 
 class SiteFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class SiteFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Site
     model = Site
-    field_order = ['q', 'status', 'region', 'tenant_group', 'tenant']
+    field_order = ['q', 'status', 'region_id', 'tenant_group_id', 'tenant_id']
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=SiteStatusChoices,
         choices=SiteStatusChoices,
         required=False,
         required=False,
         widget=StaticSelect2Multiple()
         widget=StaticSelect2Multiple()
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -411,27 +412,27 @@ class RackGroupCSVForm(CustomFieldModelCSVForm):
 
 
 
 
 class RackGroupFilterForm(BootstrapMixin, forms.Form):
 class RackGroupFilterForm(BootstrapMixin, forms.Form):
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     parent = DynamicModelMultipleChoiceField(
     parent = DynamicModelMultipleChoiceField(
         queryset=RackGroup.objects.all(),
         queryset=RackGroup.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region',
-            'site': '$site',
-        }
+            'region_id': '$region_id',
+            'site_id': '$site_id',
+        },
+        label=_('Parent')
     )
     )
 
 
 
 
@@ -666,32 +667,32 @@ class RackBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
 
 
 class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Rack
     model = Rack
-    field_order = ['q', 'region', 'site', 'group_id', 'status', 'role', 'tenant_group', 'tenant']
+    field_order = ['q', 'region_id', 'site_id', 'group_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id']
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     group_id = DynamicModelMultipleChoiceField(
     group_id = DynamicModelMultipleChoiceField(
         queryset=RackGroup.objects.all(),
         queryset=RackGroup.objects.all(),
         required=False,
         required=False,
-        label='Rack group',
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'site': '$site'
-        }
+            'site_id': '$site_id'
+        },
+        label=_('Rack group')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=RackStatusChoices,
         choices=RackStatusChoices,
@@ -708,11 +709,11 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
         required=False,
         required=False,
         widget=StaticSelect2Multiple()
         widget=StaticSelect2Multiple()
     )
     )
-    role = DynamicModelMultipleChoiceField(
+    role_id = DynamicModelMultipleChoiceField(
         queryset=RackRole.objects.all(),
         queryset=RackRole.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Role')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -722,15 +723,15 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 #
 #
 
 
 class RackElevationFilterForm(RackFilterForm):
 class RackElevationFilterForm(RackFilterForm):
-    field_order = ['q', 'region', 'site', 'group_id', 'id', 'status', 'role', 'tenant_group', 'tenant']
+    field_order = ['q', 'region_id', 'site_id', 'group_id', 'id', 'status', 'role_id', 'tenant_group_id', 'tenant_id']
     id = DynamicModelMultipleChoiceField(
     id = DynamicModelMultipleChoiceField(
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
-        label='Rack',
+        label=_('Rack'),
         required=False,
         required=False,
         display_field='display_name',
         display_field='display_name',
         query_params={
         query_params={
-            'site': '$site',
-            'group_id': '$group_id',
+            'site_id': '$site_id',
+            'group_id_id': '$group_id_id',
         }
         }
     )
     )
 
 
@@ -872,23 +873,23 @@ class RackReservationBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomField
 
 
 class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm):
 class RackReservationFilterForm(BootstrapMixin, TenancyFilterForm):
     model = RackReservation
     model = RackReservation
-    field_order = ['q', 'region', 'site', 'group_id', 'user_id', 'tenant_group', 'tenant']
+    field_order = ['q', 'region_id', 'site_id', 'group_id', 'user_id', 'tenant_group_id', 'tenant_id']
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Region')
     )
     )
     group_id = DynamicModelMultipleChoiceField(
     group_id = DynamicModelMultipleChoiceField(
         queryset=RackGroup.objects.prefetch_related('site'),
         queryset=RackGroup.objects.prefetch_related('site'),
@@ -1011,12 +1012,12 @@ class DeviceTypeFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = DeviceType
     model = DeviceType
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    manufacturer = DynamicModelMultipleChoiceField(
+    manufacturer_id = DynamicModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Manufacturer')
     )
     )
     subdevice_role = forms.MultipleChoiceField(
     subdevice_role = forms.MultipleChoiceField(
         choices=add_blank_choice(SubdeviceRoleChoices),
         choices=add_blank_choice(SubdeviceRoleChoices),
@@ -2133,69 +2134,66 @@ class DeviceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
 class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilterForm, CustomFieldFilterForm):
 class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilterForm, CustomFieldFilterForm):
     model = Device
     model = Device
     field_order = [
     field_order = [
-        'q', 'region', 'site', 'rack_group_id', 'rack_id', 'status', 'role', 'tenant_group', 'tenant',
+        'q', 'region_id', 'site_id', 'rack_group_id', 'rack_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id',
         'manufacturer_id', 'device_type_id', 'mac_address', 'has_primary_ip',
         'manufacturer_id', 'device_type_id', 'mac_address', 'has_primary_ip',
     ]
     ]
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
         required=False
         required=False
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
+            'region_id': '$region_id'
         }
         }
     )
     )
     rack_group_id = DynamicModelMultipleChoiceField(
     rack_group_id = DynamicModelMultipleChoiceField(
         queryset=RackGroup.objects.all(),
         queryset=RackGroup.objects.all(),
         required=False,
         required=False,
-        label='Rack group',
+        label=_('Rack group'),
         query_params={
         query_params={
-            'site': '$site'
+            'site_id': '$site_id'
         }
         }
     )
     )
     rack_id = DynamicModelMultipleChoiceField(
     rack_id = DynamicModelMultipleChoiceField(
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
         required=False,
         required=False,
-        label='Rack',
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'site': '$site',
+            'site_id': '$site_id',
             'group_id': '$rack_group_id',
             'group_id': '$rack_group_id',
-        }
+        },
+        label=_('Rack')
     )
     )
-    role = DynamicModelMultipleChoiceField(
+    role_id = DynamicModelMultipleChoiceField(
         queryset=DeviceRole.objects.all(),
         queryset=DeviceRole.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Role')
     )
     )
-    manufacturer = DynamicModelMultipleChoiceField(
+    manufacturer_id = DynamicModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        label='Manufacturer'
+        label=_('Manufacturer')
     )
     )
     device_type_id = DynamicModelMultipleChoiceField(
     device_type_id = DynamicModelMultipleChoiceField(
         queryset=DeviceType.objects.all(),
         queryset=DeviceType.objects.all(),
         required=False,
         required=False,
-        label='Model',
         display_field='model',
         display_field='model',
         query_params={
         query_params={
-            'manufacturer': '$manufacturer'
-        }
+            'manufacturer_id': '$manufacturer_id'
+        },
+        label=_('Model')
     )
     )
-    platform = DynamicModelMultipleChoiceField(
+    platform_id = DynamicModelMultipleChoiceField(
         queryset=Platform.objects.all(),
         queryset=Platform.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Platform')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=DeviceStatusChoices,
         choices=DeviceStatusChoices,
@@ -3540,10 +3538,10 @@ class InventoryItemBulkEditForm(
 
 
 class InventoryItemFilterForm(DeviceComponentFilterForm):
 class InventoryItemFilterForm(DeviceComponentFilterForm):
     model = InventoryItem
     model = InventoryItem
-    manufacturer = DynamicModelMultipleChoiceField(
+    manufacturer_id = DynamicModelMultipleChoiceField(
         queryset=Manufacturer.objects.all(),
         queryset=Manufacturer.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Manufacturer')
     )
     )
     serial = forms.CharField(
     serial = forms.CharField(
         required=False
         required=False
@@ -3988,25 +3986,25 @@ class CableFilterForm(BootstrapMixin, forms.Form):
     model = Cable
     model = Cable
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
-    tenant = DynamicModelMultipleChoiceField(
+    tenant_id = DynamicModelMultipleChoiceField(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Tenant')
     )
     )
     rack_id = DynamicModelMultipleChoiceField(
     rack_id = DynamicModelMultipleChoiceField(
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
@@ -4014,7 +4012,7 @@ class CableFilterForm(BootstrapMixin, forms.Form):
         label='Rack',
         label='Rack',
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'site': '$site'
+            'site_id': '$site_id'
         }
         }
     )
     )
     type = forms.MultipleChoiceField(
     type = forms.MultipleChoiceField(
@@ -4035,12 +4033,12 @@ class CableFilterForm(BootstrapMixin, forms.Form):
     device_id = DynamicModelMultipleChoiceField(
     device_id = DynamicModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,
-        label='Device',
         query_params={
         query_params={
-            'site': '$site',
-            'tenant': '$tenant',
+            'site_id': '$site_id',
+            'tenant_id': '$tenant_id',
             'rack_id': '$rack_id',
             'rack_id': '$rack_id',
-        }
+        },
+        label=_('Device')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -4050,74 +4048,74 @@ class CableFilterForm(BootstrapMixin, forms.Form):
 #
 #
 
 
 class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
 class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     device_id = DynamicModelMultipleChoiceField(
     device_id = DynamicModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,
-        label='Device',
         query_params={
         query_params={
-            'site': '$site'
-        }
+            'site_id': '$site_id'
+        },
+        label=_('Device')
     )
     )
 
 
 
 
 class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
 class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     device_id = DynamicModelMultipleChoiceField(
     device_id = DynamicModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,
-        label='Device',
         query_params={
         query_params={
-            'site': '$site'
-        }
+            'site_id': '$site_id'
+        },
+        label=_('Device')
     )
     )
 
 
 
 
 class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
 class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     device_id = DynamicModelMultipleChoiceField(
     device_id = DynamicModelMultipleChoiceField(
         queryset=Device.objects.all(),
         queryset=Device.objects.all(),
         required=False,
         required=False,
-        label='Device',
         query_params={
         query_params={
-            'site': '$site'
-        }
+            'site_id': '$site_id'
+        },
+        label=_('Device')
     )
     )
 
 
 
 
@@ -4344,39 +4342,25 @@ class VirtualChassisCSVForm(CustomFieldModelCSVForm):
         fields = VirtualChassis.csv_headers
         fields = VirtualChassis.csv_headers
 
 
 
 
-class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm):
+class VirtualChassisFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VirtualChassis
     model = VirtualChassis
+    field_order = ['q', 'region_id', 'site_id', 'tenant_group_id', 'tenant_id']
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
-    )
-    site = DynamicModelMultipleChoiceField(
-        queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        query_params={
-            'region': '$region'
-        }
+        label=_('Region')
     )
     )
-    tenant_group = DynamicModelMultipleChoiceField(
-        queryset=TenantGroup.objects.all(),
-        to_field_name='slug',
-        required=False,
-        null_option='None'
-    )
-    tenant = DynamicModelMultipleChoiceField(
-        queryset=Tenant.objects.all(),
-        to_field_name='slug',
+    site_id = DynamicModelMultipleChoiceField(
+        queryset=Site.objects.all(),
         required=False,
         required=False,
-        null_option='None',
         query_params={
         query_params={
-            'group': '$tenant_group'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -4482,29 +4466,29 @@ class PowerPanelFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = PowerPanel
     model = PowerPanel
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     rack_group_id = DynamicModelMultipleChoiceField(
     rack_group_id = DynamicModelMultipleChoiceField(
         queryset=RackGroup.objects.all(),
         queryset=RackGroup.objects.all(),
         required=False,
         required=False,
-        label='Rack group (ID)',
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'site': '$site'
-        }
+            'site_id': '$site_id'
+        },
+        label=_('Rack group')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -4701,38 +4685,38 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = PowerFeed
     model = PowerFeed
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
     power_panel_id = DynamicModelMultipleChoiceField(
     power_panel_id = DynamicModelMultipleChoiceField(
         queryset=PowerPanel.objects.all(),
         queryset=PowerPanel.objects.all(),
         required=False,
         required=False,
-        label='Power panel',
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'site': '$site'
-        }
+            'site_id': '$site_id'
+        },
+        label=_('Power panel')
     )
     )
     rack_id = DynamicModelMultipleChoiceField(
     rack_id = DynamicModelMultipleChoiceField(
         queryset=Rack.objects.all(),
         queryset=Rack.objects.all(),
         required=False,
         required=False,
-        label='Rack',
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'site': '$site'
-        }
+            'site_id': '$site_id'
+        },
+        label=_('Rack')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=PowerFeedStatusChoices,
         choices=PowerFeedStatusChoices,

+ 37 - 31
netbox/extras/forms.py

@@ -2,6 +2,7 @@ from django import forms
 from django.contrib.auth.models import User
 from django.contrib.auth.models import User
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.utils.safestring import mark_safe
 from django.utils.safestring import mark_safe
+from django.utils.translation import gettext as _
 
 
 from dcim.models import DeviceRole, Platform, Region, Site
 from dcim.models import DeviceRole, Platform, Region, Site
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
@@ -177,7 +178,7 @@ class TagFilterForm(BootstrapMixin, forms.Form):
     model = Tag
     model = Tag
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
 
 
 
 
@@ -278,54 +279,59 @@ class ConfigContextBulkEditForm(BootstrapMixin, BulkEditForm):
 
 
 
 
 class ConfigContextFilterForm(BootstrapMixin, forms.Form):
 class ConfigContextFilterForm(BootstrapMixin, forms.Form):
+    field_order = [
+        'q', 'region_id', 'site_id', 'role_id', 'platform_id', 'cluster_group_id', 'cluster_id', 'tenant_group_id',
+        'tenant_id',
+    ]
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Regions')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Sites')
     )
     )
-    role = DynamicModelMultipleChoiceField(
+    role_id = DynamicModelMultipleChoiceField(
         queryset=DeviceRole.objects.all(),
         queryset=DeviceRole.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Roles')
     )
     )
-    platform = DynamicModelMultipleChoiceField(
+    platform_id = DynamicModelMultipleChoiceField(
         queryset=Platform.objects.all(),
         queryset=Platform.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Platforms')
     )
     )
-    cluster_group = DynamicModelMultipleChoiceField(
+    cluster_group_id = DynamicModelMultipleChoiceField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Cluster groups')
     )
     )
     cluster_id = DynamicModelMultipleChoiceField(
     cluster_id = DynamicModelMultipleChoiceField(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
         required=False,
         required=False,
-        label='Cluster'
+        label=_('Clusters')
     )
     )
-    tenant_group = DynamicModelMultipleChoiceField(
+    tenant_group_id = DynamicModelMultipleChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Tenant groups')
     )
     )
-    tenant = DynamicModelMultipleChoiceField(
+    tenant_id = DynamicModelMultipleChoiceField(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Tenant')
     )
     )
     tag = DynamicModelMultipleChoiceField(
     tag = DynamicModelMultipleChoiceField(
         queryset=Tag.objects.all(),
         queryset=Tag.objects.all(),
         to_field_name='slug',
         to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Tags')
     )
     )
 
 
 
 
@@ -336,7 +342,7 @@ class ConfigContextFilterForm(BootstrapMixin, forms.Form):
 class LocalConfigContextFilterForm(forms.Form):
 class LocalConfigContextFilterForm(forms.Form):
     local_context_data = forms.NullBooleanField(
     local_context_data = forms.NullBooleanField(
         required=False,
         required=False,
-        label='Has local config context data',
+        label=_('Has local config context data'),
         widget=StaticSelect2(
         widget=StaticSelect2(
             choices=BOOLEAN_WITH_BLANK_CHOICES
             choices=BOOLEAN_WITH_BLANK_CHOICES
         )
         )
@@ -364,16 +370,16 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
     model = ObjectChange
     model = ObjectChange
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
     time_after = forms.DateTimeField(
     time_after = forms.DateTimeField(
-        label='After',
         required=False,
         required=False,
+        label=_('After'),
         widget=DateTimePicker()
         widget=DateTimePicker()
     )
     )
     time_before = forms.DateTimeField(
     time_before = forms.DateTimeField(
-        label='Before',
         required=False,
         required=False,
+        label=_('Before'),
         widget=DateTimePicker()
         widget=DateTimePicker()
     )
     )
     action = forms.ChoiceField(
     action = forms.ChoiceField(
@@ -385,7 +391,7 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
         queryset=User.objects.all(),
         queryset=User.objects.all(),
         required=False,
         required=False,
         display_field='username',
         display_field='username',
-        label='User',
+        label=_('User'),
         widget=APISelectMultiple(
         widget=APISelectMultiple(
             api_url='/api/users/users/',
             api_url='/api/users/users/',
         )
         )
@@ -394,7 +400,7 @@ class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
         queryset=ContentType.objects.all(),
         queryset=ContentType.objects.all(),
         required=False,
         required=False,
         display_field='display_name',
         display_field='display_name',
-        label='Object Type',
+        label=_('Object Type'),
         widget=APISelectMultiple(
         widget=APISelectMultiple(
             api_url='/api/extras/content-types/',
             api_url='/api/extras/content-types/',
         )
         )

+ 69 - 70
netbox/ipam/forms.py

@@ -1,4 +1,5 @@
 from django import forms
 from django import forms
+from django.utils.translation import gettext as _
 
 
 from dcim.models import Device, Interface, Rack, Region, Site
 from dcim.models import Device, Interface, Rack, Region, Site
 from extras.forms import (
 from extras.forms import (
@@ -103,20 +104,20 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm
 
 
 class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VRF
     model = VRF
-    field_order = ['q', 'import_target', 'export_target', 'tenant_group', 'tenant']
+    field_order = ['q', 'import_target_id', 'export_target_id', 'tenant_group_id', 'tenant_id']
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    import_target = DynamicModelMultipleChoiceField(
+    import_target_id = DynamicModelMultipleChoiceField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
-        to_field_name='name',
-        required=False
+        required=False,
+        label=_('Import targets')
     )
     )
-    export_target = DynamicModelMultipleChoiceField(
+    export_target_id = DynamicModelMultipleChoiceField(
         queryset=RouteTarget.objects.all(),
         queryset=RouteTarget.objects.all(),
-        to_field_name='name',
-        required=False
+        required=False,
+        label=_('Export targets')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -173,20 +174,20 @@ class RouteTargetBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulk
 
 
 class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = RouteTarget
     model = RouteTarget
-    field_order = ['q', 'name', 'tenant_group', 'tenant', 'importing_vrfs', 'exporting_vrfs']
+    field_order = ['q', 'name', 'tenant_group_id', 'tenant_id', 'importing_vrfs', 'exporting_vrfs']
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
     importing_vrf_id = DynamicModelMultipleChoiceField(
     importing_vrf_id = DynamicModelMultipleChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
-        label='Imported by VRF'
+        label=_('Imported by VRF')
     )
     )
     exporting_vrf_id = DynamicModelMultipleChoiceField(
     exporting_vrf_id = DynamicModelMultipleChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
-        label='Exported by VRF'
+        label=_('Exported by VRF')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -219,7 +220,7 @@ class RIRCSVForm(CustomFieldModelCSVForm):
 class RIRFilterForm(BootstrapMixin, forms.Form):
 class RIRFilterForm(BootstrapMixin, forms.Form):
     is_private = forms.NullBooleanField(
     is_private = forms.NullBooleanField(
         required=False,
         required=False,
-        label='Private',
+        label=_('Private'),
         widget=StaticSelect2(
         widget=StaticSelect2(
             choices=BOOLEAN_WITH_BLANK_CHOICES
             choices=BOOLEAN_WITH_BLANK_CHOICES
         )
         )
@@ -309,21 +310,21 @@ class AggregateBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEd
 
 
 class AggregateFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class AggregateFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Aggregate
     model = Aggregate
+    field_order = ['q', 'family', 'rir', 'tenant_group_id', 'tenant_id']
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
     family = forms.ChoiceField(
     family = forms.ChoiceField(
         required=False,
         required=False,
         choices=add_blank_choice(IPAddressFamilyChoices),
         choices=add_blank_choice(IPAddressFamilyChoices),
-        label='Address family',
+        label=_('Address family'),
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
-    rir = DynamicModelMultipleChoiceField(
+    rir_id = DynamicModelMultipleChoiceField(
         queryset=RIR.objects.all(),
         queryset=RIR.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        label='RIR'
+        label=_('RIR')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -494,14 +495,13 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
     )
     )
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        required=False,
-        to_field_name='slug'
+        required=False
     )
     )
     site = DynamicModelChoiceField(
     site = DynamicModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
+            'region_id': '$region'
         }
         }
     )
     )
     vrf = DynamicModelChoiceField(
     vrf = DynamicModelChoiceField(
@@ -547,15 +547,15 @@ class PrefixBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditF
 class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Prefix
     model = Prefix
     field_order = [
     field_order = [
-        'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'region', 'site',
-        'role', 'tenant_group', 'tenant', 'is_pool', 'expand',
+        'q', 'within_include', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'region_id', 'site_id',
+        'role_id', 'tenant_group_id', 'tenant_id', 'is_pool',
     ]
     ]
     mask_length__lte = forms.IntegerField(
     mask_length__lte = forms.IntegerField(
         widget=forms.HiddenInput()
         widget=forms.HiddenInput()
     )
     )
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
     within_include = forms.CharField(
     within_include = forms.CharField(
         required=False,
         required=False,
@@ -564,59 +564,59 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
                 'placeholder': 'Prefix',
                 'placeholder': 'Prefix',
             }
             }
         ),
         ),
-        label='Search within'
+        label=_('Search within')
     )
     )
     family = forms.ChoiceField(
     family = forms.ChoiceField(
         required=False,
         required=False,
         choices=add_blank_choice(IPAddressFamilyChoices),
         choices=add_blank_choice(IPAddressFamilyChoices),
-        label='Address family',
+        label=_('Address family'),
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
     mask_length = forms.ChoiceField(
     mask_length = forms.ChoiceField(
         required=False,
         required=False,
         choices=PREFIX_MASK_LENGTH_CHOICES,
         choices=PREFIX_MASK_LENGTH_CHOICES,
-        label='Mask length',
+        label=_('Mask length'),
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
     vrf_id = DynamicModelMultipleChoiceField(
     vrf_id = DynamicModelMultipleChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
-        label='Assigned VRF',
+        label=_('Assigned VRF'),
         null_option='Global'
         null_option='Global'
     )
     )
     present_in_vrf_id = DynamicModelChoiceField(
     present_in_vrf_id = DynamicModelChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
-        label='Present in VRF'
+        label=_('Present in VRF')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=PrefixStatusChoices,
         choices=PrefixStatusChoices,
         required=False,
         required=False,
         widget=StaticSelect2Multiple()
         widget=StaticSelect2Multiple()
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
-    role = DynamicModelMultipleChoiceField(
+    role_id = DynamicModelMultipleChoiceField(
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Role')
     )
     )
     is_pool = forms.NullBooleanField(
     is_pool = forms.NullBooleanField(
         required=False,
         required=False,
-        label='Is a pool',
+        label=_('Is a pool'),
         widget=StaticSelect2(
         widget=StaticSelect2(
             choices=BOOLEAN_WITH_BLANK_CHOICES
             choices=BOOLEAN_WITH_BLANK_CHOICES
         )
         )
@@ -1019,11 +1019,11 @@ class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterFo
     model = IPAddress
     model = IPAddress
     field_order = [
     field_order = [
         'q', 'parent', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'role',
         'q', 'parent', 'family', 'mask_length', 'vrf_id', 'present_in_vrf_id', 'status', 'role',
-        'assigned_to_interface', 'tenant_group', 'tenant',
+        'assigned_to_interface', 'tenant_group_id', 'tenant_id',
     ]
     ]
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
     parent = forms.CharField(
     parent = forms.CharField(
         required=False,
         required=False,
@@ -1037,25 +1037,25 @@ class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterFo
     family = forms.ChoiceField(
     family = forms.ChoiceField(
         required=False,
         required=False,
         choices=add_blank_choice(IPAddressFamilyChoices),
         choices=add_blank_choice(IPAddressFamilyChoices),
-        label='Address family',
+        label=_('Address family'),
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
     mask_length = forms.ChoiceField(
     mask_length = forms.ChoiceField(
         required=False,
         required=False,
         choices=IPADDRESS_MASK_LENGTH_CHOICES,
         choices=IPADDRESS_MASK_LENGTH_CHOICES,
-        label='Mask length',
+        label=_('Mask length'),
         widget=StaticSelect2()
         widget=StaticSelect2()
     )
     )
     vrf_id = DynamicModelMultipleChoiceField(
     vrf_id = DynamicModelMultipleChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
-        label='Assigned VRF',
+        label=_('Assigned VRF'),
         null_option='Global'
         null_option='Global'
     )
     )
     present_in_vrf_id = DynamicModelChoiceField(
     present_in_vrf_id = DynamicModelChoiceField(
         queryset=VRF.objects.all(),
         queryset=VRF.objects.all(),
         required=False,
         required=False,
-        label='Present in VRF'
+        label=_('Present in VRF')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=IPAddressStatusChoices,
         choices=IPAddressStatusChoices,
@@ -1069,7 +1069,7 @@ class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterFo
     )
     )
     assigned_to_interface = forms.NullBooleanField(
     assigned_to_interface = forms.NullBooleanField(
         required=False,
         required=False,
-        label='Assigned to an interface',
+        label=_('Assigned to an interface'),
         widget=StaticSelect2(
         widget=StaticSelect2(
             choices=BOOLEAN_WITH_BLANK_CHOICES
             choices=BOOLEAN_WITH_BLANK_CHOICES
         )
         )
@@ -1120,19 +1120,19 @@ class VLANGroupCSVForm(CustomFieldModelCSVForm):
 
 
 
 
 class VLANGroupFilterForm(BootstrapMixin, forms.Form):
 class VLANGroupFilterForm(BootstrapMixin, forms.Form):
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
 
 
 
 
@@ -1250,14 +1250,13 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
     )
     )
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        required=False,
-        to_field_name='slug'
+        required=False
     )
     )
     site = DynamicModelChoiceField(
     site = DynamicModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
+            'region_id': '$region'
         }
         }
     )
     )
     group = DynamicModelChoiceField(
     group = DynamicModelChoiceField(
@@ -1293,44 +1292,44 @@ class VLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditFor
 
 
 class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VLAN
     model = VLAN
-    field_order = ['q', 'region', 'site', 'group_id', 'status', 'role', 'tenant_group', 'tenant']
+    field_order = ['q', 'region_id', 'site_id', 'group_id', 'status', 'role_id', 'tenant_group_id', 'tenant_id']
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
         label='Search'
         label='Search'
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         null_option='None',
         null_option='None',
         query_params={
         query_params={
             'region': '$region'
             'region': '$region'
-        }
+        },
+        label=_('Site')
     )
     )
     group_id = DynamicModelMultipleChoiceField(
     group_id = DynamicModelMultipleChoiceField(
         queryset=VLANGroup.objects.all(),
         queryset=VLANGroup.objects.all(),
         required=False,
         required=False,
-        label='VLAN group',
         null_option='None',
         null_option='None',
         query_params={
         query_params={
             'region': '$region'
             'region': '$region'
-        }
+        },
+        label=_('VLAN group')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=VLANStatusChoices,
         choices=VLANStatusChoices,
         required=False,
         required=False,
         widget=StaticSelect2Multiple()
         widget=StaticSelect2Multiple()
     )
     )
-    role = DynamicModelMultipleChoiceField(
+    role_id = DynamicModelMultipleChoiceField(
         queryset=Role.objects.all(),
         queryset=Role.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Role')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -1386,7 +1385,7 @@ class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Service
     model = Service
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
     protocol = forms.ChoiceField(
     protocol = forms.ChoiceField(
         choices=add_blank_choice(ServiceProtocolChoices),
         choices=add_blank_choice(ServiceProtocolChoices),

+ 6 - 6
netbox/secrets/forms.py

@@ -1,7 +1,7 @@
 from Crypto.Cipher import PKCS1_OAEP
 from Crypto.Cipher import PKCS1_OAEP
 from Crypto.PublicKey import RSA
 from Crypto.PublicKey import RSA
 from django import forms
 from django import forms
-from django.contrib.contenttypes.models import ContentType
+from django.utils.translation import gettext as _
 
 
 from dcim.models import Device
 from dcim.models import Device
 from extras.forms import (
 from extras.forms import (
@@ -9,7 +9,7 @@ from extras.forms import (
 )
 )
 from extras.models import Tag
 from extras.models import Tag
 from utilities.forms import (
 from utilities.forms import (
-    BootstrapMixin, CSVModelChoiceField, CSVModelForm, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
+    BootstrapMixin, CSVModelChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
     SlugField, TagFilterField,
     SlugField, TagFilterField,
 )
 )
 from virtualization.models import VirtualMachine
 from virtualization.models import VirtualMachine
@@ -221,12 +221,12 @@ class SecretFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Secret
     model = Secret
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    role = DynamicModelMultipleChoiceField(
+    role_id = DynamicModelMultipleChoiceField(
         queryset=SecretRole.objects.all(),
         queryset=SecretRole.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Role')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 

+ 14 - 13
netbox/tenancy/forms.py

@@ -1,12 +1,13 @@
 from django import forms
 from django import forms
+from django.utils.translation import gettext as _
 
 
 from extras.forms import (
 from extras.forms import (
     AddRemoveTagsForm, CustomFieldModelForm, CustomFieldBulkEditForm, CustomFieldFilterForm, CustomFieldModelCSVForm,
     AddRemoveTagsForm, CustomFieldModelForm, CustomFieldBulkEditForm, CustomFieldFilterForm, CustomFieldModelCSVForm,
 )
 )
 from extras.models import Tag
 from extras.models import Tag
 from utilities.forms import (
 from utilities.forms import (
-    BootstrapMixin, CommentField, CSVModelChoiceField, CSVModelForm, DynamicModelChoiceField,
-    DynamicModelMultipleChoiceField, SlugField, TagFilterField,
+    BootstrapMixin, CommentField, CSVModelChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
+    SlugField, TagFilterField,
 )
 )
 from .models import Tenant, TenantGroup
 from .models import Tenant, TenantGroup
 
 
@@ -103,13 +104,13 @@ class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
     model = Tenant
     model = Tenant
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    group = DynamicModelMultipleChoiceField(
+    group_id = DynamicModelMultipleChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Group')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -137,18 +138,18 @@ class TenancyForm(forms.Form):
 
 
 
 
 class TenancyFilterForm(forms.Form):
 class TenancyFilterForm(forms.Form):
-    tenant_group = DynamicModelMultipleChoiceField(
+    tenant_group_id = DynamicModelMultipleChoiceField(
         queryset=TenantGroup.objects.all(),
         queryset=TenantGroup.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Tenant group')
     )
     )
-    tenant = DynamicModelMultipleChoiceField(
+    tenant_id = DynamicModelMultipleChoiceField(
         queryset=Tenant.objects.all(),
         queryset=Tenant.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'group': '$tenant_group'
-        }
+            'group_id': '$tenant_group_id'
+        },
+        label=_('Tenant')
     )
     )

+ 47 - 44
netbox/virtualization/forms.py

@@ -1,6 +1,7 @@
 from django import forms
 from django import forms
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
+from django.utils.translation import gettext as _
 
 
 from dcim.choices import InterfaceModeChoices
 from dcim.choices import InterfaceModeChoices
 from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
 from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
@@ -160,13 +161,12 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
     region = DynamicModelChoiceField(
     region = DynamicModelChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
         required=False,
         required=False,
-        to_field_name='slug'
     )
     )
     site = DynamicModelChoiceField(
     site = DynamicModelChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
         required=False,
         required=False,
         query_params={
         query_params={
-            'region': '$region'
+            'region_id': '$region'
         }
         }
     )
     )
     comments = CommentField(
     comments = CommentField(
@@ -183,33 +183,36 @@ class ClusterBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
 class ClusterFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class ClusterFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = Cluster
     model = Cluster
     field_order = [
     field_order = [
-        'q', 'type', 'region', 'site', 'group', 'tenant_group', 'tenant'
+        'q', 'type_id', 'region_id', 'site_id', 'group_id', 'tenant_group_id', 'tenant_id',
     ]
     ]
-    q = forms.CharField(required=False, label='Search')
-    type = DynamicModelMultipleChoiceField(
+    q = forms.CharField(
+        required=False,
+        label=_('Search')
+    )
+    type_id = DynamicModelMultipleChoiceField(
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Type')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Site')
     )
     )
-    group = DynamicModelMultipleChoiceField(
+    group_id = DynamicModelMultipleChoiceField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Group')
     )
     )
     tag = TagFilterField(model)
     tag = TagFilterField(model)
 
 
@@ -478,63 +481,63 @@ class VirtualMachineBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldB
 class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
 class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
     model = VirtualMachine
     model = VirtualMachine
     field_order = [
     field_order = [
-        'q', 'cluster_group', 'cluster_type', 'cluster_id', 'status', 'role', 'region', 'site', 'tenant_group',
-        'tenant', 'platform', 'mac_address',
+        'q', 'cluster_group_id', 'cluster_type_id', 'cluster_id', 'status', 'role_id', 'region_id', 'site_id',
+        'tenant_group_id', 'tenant_id', 'platform_id', 'mac_address',
     ]
     ]
     q = forms.CharField(
     q = forms.CharField(
         required=False,
         required=False,
-        label='Search'
+        label=_('Search')
     )
     )
-    cluster_group = DynamicModelMultipleChoiceField(
+    cluster_group_id = DynamicModelMultipleChoiceField(
         queryset=ClusterGroup.objects.all(),
         queryset=ClusterGroup.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Cluster group')
     )
     )
-    cluster_type = DynamicModelMultipleChoiceField(
+    cluster_type_id = DynamicModelMultipleChoiceField(
         queryset=ClusterType.objects.all(),
         queryset=ClusterType.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Cluster type')
     )
     )
     cluster_id = DynamicModelMultipleChoiceField(
     cluster_id = DynamicModelMultipleChoiceField(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
         required=False,
         required=False,
-        label='Cluster'
+        label=_('Cluster')
     )
     )
-    region = DynamicModelMultipleChoiceField(
+    region_id = DynamicModelMultipleChoiceField(
         queryset=Region.objects.all(),
         queryset=Region.objects.all(),
-        to_field_name='slug',
-        required=False
+        required=False,
+        label=_('Region')
     )
     )
-    site = DynamicModelMultipleChoiceField(
+    site_id = DynamicModelMultipleChoiceField(
         queryset=Site.objects.all(),
         queryset=Site.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
         null_option='None',
         null_option='None',
         query_params={
         query_params={
-            'region': '$region'
-        }
+            'region_id': '$region_id'
+        },
+        label=_('Cluster')
     )
     )
-    role = DynamicModelMultipleChoiceField(
-        queryset=DeviceRole.objects.filter(vm_role=True),
-        to_field_name='slug',
+    role_id = DynamicModelMultipleChoiceField(
+        queryset=DeviceRole.objects.all(),
         required=False,
         required=False,
         null_option='None',
         null_option='None',
         query_params={
         query_params={
             'vm_role': "True"
             'vm_role': "True"
-        }
+        },
+        label=_('Role')
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
         choices=VirtualMachineStatusChoices,
         choices=VirtualMachineStatusChoices,
         required=False,
         required=False,
         widget=StaticSelect2Multiple()
         widget=StaticSelect2Multiple()
     )
     )
-    platform = DynamicModelMultipleChoiceField(
+    platform_id = DynamicModelMultipleChoiceField(
         queryset=Platform.objects.all(),
         queryset=Platform.objects.all(),
-        to_field_name='slug',
         required=False,
         required=False,
-        null_option='None'
+        null_option='None',
+        label=_('Platform')
     )
     )
     mac_address = forms.CharField(
     mac_address = forms.CharField(
         required=False,
         required=False,
@@ -781,15 +784,15 @@ class VMInterfaceFilterForm(forms.Form):
     cluster_id = DynamicModelMultipleChoiceField(
     cluster_id = DynamicModelMultipleChoiceField(
         queryset=Cluster.objects.all(),
         queryset=Cluster.objects.all(),
         required=False,
         required=False,
-        label='Cluster'
+        label=_('Cluster')
     )
     )
     virtual_machine_id = DynamicModelMultipleChoiceField(
     virtual_machine_id = DynamicModelMultipleChoiceField(
         queryset=VirtualMachine.objects.all(),
         queryset=VirtualMachine.objects.all(),
         required=False,
         required=False,
-        label='Virtual machine',
         query_params={
         query_params={
             'cluster_id': '$cluster_id'
             'cluster_id': '$cluster_id'
-        }
+        },
+        label=_('Virtual machine')
     )
     )
     enabled = forms.NullBooleanField(
     enabled = forms.NullBooleanField(
         required=False,
         required=False,