diff --git a/netbox/dcim/forms/filtersets.py b/netbox/dcim/forms/filtersets.py index 41d426e8627..9728a1135b3 100644 --- a/netbox/dcim/forms/filtersets.py +++ b/netbox/dcim/forms/filtersets.py @@ -1435,7 +1435,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): tx_power = forms.IntegerField( required=False, label=_('Transmit power (dBm)'), - min_value=0, + min_value=-127, max_value=127 ) vrf_id = DynamicModelMultipleChoiceField( diff --git a/netbox/dcim/migrations/0201_alter_interface_tx_power.py b/netbox/dcim/migrations/0201_alter_interface_tx_power.py new file mode 100644 index 00000000000..c626f5731f0 --- /dev/null +++ b/netbox/dcim/migrations/0201_alter_interface_tx_power.py @@ -0,0 +1,21 @@ +# Generated by Django 5.1.8 on 2025-04-17 03:36 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0200_populate_mac_addresses'), + ] + + operations = [ + migrations.AlterField( + model_name='interface', + name='tx_power', + field=models.SmallIntegerField(blank=True, null=True, validators=[ + django.core.validators.MinValueValidator(-127), django.core.validators.MaxValueValidator(127) + ]), + ), + ] diff --git a/netbox/dcim/models/device_components.py b/netbox/dcim/models/device_components.py index 632121dc2e6..50228058ce1 100644 --- a/netbox/dcim/models/device_components.py +++ b/netbox/dcim/models/device_components.py @@ -710,10 +710,13 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd verbose_name=('channel width (MHz)'), help_text=_("Populated by selected channel (if set)") ) - tx_power = models.PositiveSmallIntegerField( + tx_power = models.SmallIntegerField( blank=True, null=True, - validators=(MaxValueValidator(127),), + validators=[ + MinValueValidator(-127), + MaxValueValidator(127) + ], verbose_name=_('transmit power (dBm)') ) poe_mode = models.CharField( diff --git a/netbox/dcim/tests/test_api.py b/netbox/dcim/tests/test_api.py index b1ed4aca33f..ccbdcee16c5 100644 --- a/netbox/dcim/tests/test_api.py +++ b/netbox/dcim/tests/test_api.py @@ -1743,7 +1743,7 @@ def setUpTestData(cls): 'name': 'Interface 8', 'type': InterfaceTypeChoices.TYPE_80211A, 'mode': InterfaceModeChoices.MODE_Q_IN_Q, - 'tx_power': 10, + 'tx_power': -10, 'wireless_lans': [wireless_lans[0].pk, wireless_lans[1].pk], 'rf_channel': "", 'qinq_svlan': vlans[3].pk, diff --git a/netbox/dcim/tests/test_filtersets.py b/netbox/dcim/tests/test_filtersets.py index 727389ef1bf..cc877733c41 100644 --- a/netbox/dcim/tests/test_filtersets.py +++ b/netbox/dcim/tests/test_filtersets.py @@ -4072,7 +4072,7 @@ def setUpTestData(cls): type=InterfaceTypeChoices.TYPE_OTHER, enabled=False, mgmt_only=False, - tx_power=40, + tx_power=-40, mode=InterfaceModeChoices.MODE_Q_IN_Q, qinq_svlan=vlans[2] ), @@ -4340,7 +4340,10 @@ def test_rf_channel_width(self): def test_tx_power(self): params = {'tx_power': [40]} - self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) + + params = {'tx_power': [-40]} + self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) def test_vrf(self): vrfs = VRF.objects.all()[:2] diff --git a/netbox/dcim/tests/test_views.py b/netbox/dcim/tests/test_views.py index b8421788291..068be6df975 100644 --- a/netbox/dcim/tests/test_views.py +++ b/netbox/dcim/tests/test_views.py @@ -2660,7 +2660,7 @@ def setUpTestData(cls): 'poe_mode': InterfacePoEModeChoices.MODE_PD, 'poe_type': InterfacePoETypeChoices.TYPE_2_8023AT, 'mode': InterfaceModeChoices.MODE_TAGGED, - 'tx_power': 10, + 'tx_power': -10, 'untagged_vlan': vlans[0].pk, 'tagged_vlans': [v.pk for v in vlans[1:4]], 'vrf': vrfs[1].pk,