feat(dcim): Change Interface speed field to BigInteger

Converts the Interface speed field from PositiveIntegerField to
PositiveBigIntegerField to support higher speed values. Updates
filters, GraphQL types, and test fixtures accordingly.

Fixes #21542
This commit is contained in:
Martin Hauser
2026-04-03 15:47:01 +02:00
parent f058ee3d60
commit e83e2f85fc
10 changed files with 69 additions and 9 deletions

View File

@@ -26,6 +26,7 @@ from tenancy.models import *
from users.filterset_mixins import OwnerFilterMixin
from users.models import User
from utilities.filters import (
MultiValueBigNumberFilter,
MultiValueCharFilter,
MultiValueContentTypeFilter,
MultiValueMACAddressFilter,
@@ -2175,7 +2176,7 @@ class InterfaceFilterSet(
distinct=False,
label=_('LAG interface (ID)'),
)
speed = MultiValueNumberFilter()
speed = MultiValueBigNumberFilter(min_value=0)
duplex = django_filters.MultipleChoiceFilter(
choices=InterfaceDuplexChoices,
distinct=False,

View File

@@ -20,7 +20,13 @@ from netbox.forms.mixins import ChangelogMessageMixin, OwnerMixin
from tenancy.models import Tenant
from users.models import User
from utilities.forms import BulkEditForm, add_blank_choice, form_from_model
from utilities.forms.fields import ColorField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField
from utilities.forms.fields import (
ColorField,
DynamicModelChoiceField,
DynamicModelMultipleChoiceField,
JSONField,
PositiveBigIntegerField,
)
from utilities.forms.rendering import FieldSet, InlineFields, TabbedGroups
from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions
from virtualization.models import Cluster
@@ -1420,7 +1426,7 @@ class InterfaceBulkEditForm(
'device_id': '$device',
}
)
speed = forms.IntegerField(
speed = PositiveBigIntegerField(
label=_('Speed'),
required=False,
widget=NumberWithOptions(

View File

@@ -19,7 +19,7 @@ from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
from tenancy.models import Tenant
from users.models import User
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, TagFilterField
from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, PositiveBigIntegerField, TagFilterField
from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import NumberWithOptions
from virtualization.models import Cluster, ClusterGroup, VirtualMachine
@@ -1603,7 +1603,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
choices=InterfaceTypeChoices,
required=False
)
speed = forms.IntegerField(
speed = PositiveBigIntegerField(
label=_('Speed'),
required=False,
widget=NumberWithOptions(

View File

@@ -47,7 +47,13 @@ if TYPE_CHECKING:
VRFFilter,
)
from netbox.graphql.enums import ColorEnum
from netbox.graphql.filter_lookups import FloatLookup, IntegerArrayLookup, IntegerLookup, TreeNodeFilter
from netbox.graphql.filter_lookups import (
BigIntegerLookup,
FloatLookup,
IntegerArrayLookup,
IntegerLookup,
TreeNodeFilter,
)
from users.graphql.filters import UserFilter
from virtualization.graphql.filters import ClusterFilter
from vpn.graphql.filters import L2VPNFilter, TunnelTerminationFilter
@@ -519,7 +525,7 @@ class InterfaceFilter(
strawberry_django.filter_field()
)
mgmt_only: FilterLookup[bool] | None = strawberry_django.filter_field()
speed: Annotated['IntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
speed: Annotated['BigIntegerLookup', strawberry.lazy('netbox.graphql.filter_lookups')] | None = (
strawberry_django.filter_field()
)
duplex: BaseFilterLookup[Annotated['InterfaceDuplexEnum', strawberry.lazy('dcim.graphql.enums')]] | None = (

View File

@@ -433,6 +433,7 @@ class MACAddressType(PrimaryObjectType):
)
class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin):
_name: str
speed: BigInt | None
wwn: str | None
parent: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None
bridge: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None

View File

@@ -0,0 +1,15 @@
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0226_modulebay_rebuild_tree'),
]
operations = [
migrations.AlterField(
model_name='interface',
name='speed',
field=models.PositiveBigIntegerField(blank=True, null=True),
),
]

View File

@@ -806,7 +806,7 @@ class Interface(
verbose_name=_('management only'),
help_text=_('This interface is used only for out-of-band management')
)
speed = models.PositiveIntegerField(
speed = models.PositiveBigIntegerField(
blank=True,
null=True,
verbose_name=_('speed (Kbps)')

View File

@@ -1932,7 +1932,7 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
'name': 'Interface 4',
'type': '1000base-t',
'mode': InterfaceModeChoices.MODE_TAGGED,
'speed': 1000000,
'speed': 16000000000,
'duplex': 'full',
'vrf': vrfs[0].pk,
'poe_mode': InterfacePoEModeChoices.MODE_PD,

View File

@@ -7,9 +7,12 @@ from django_filters.constants import EMPTY_VALUES
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from .forms.fields import BigIntegerField
__all__ = (
'ContentTypeFilter',
'MultiValueArrayFilter',
'MultiValueBigNumberFilter',
'MultiValueCharFilter',
'MultiValueContentTypeFilter',
'MultiValueDateFilter',
@@ -77,6 +80,11 @@ class MultiValueNumberFilter(django_filters.MultipleChoiceFilter):
field_class = multivalue_field_factory(forms.IntegerField)
@extend_schema_field(OpenApiTypes.INT64)
class MultiValueBigNumberFilter(MultiValueNumberFilter):
field_class = multivalue_field_factory(BigIntegerField)
@extend_schema_field(OpenApiTypes.DECIMAL)
class MultiValueDecimalFilter(django_filters.MultipleChoiceFilter):
field_class = multivalue_field_factory(forms.DecimalField)

View File

@@ -2,6 +2,7 @@ import json
from django import forms
from django.conf import settings
from django.db.models import BigIntegerField as BigIntegerModelField
from django.db.models import Count
from django.forms.fields import InvalidJSONInput
from django.forms.fields import JSONField as _JSONField
@@ -13,17 +14,39 @@ from utilities.forms import widgets
from utilities.validators import EnhancedURLValidator
__all__ = (
'BigIntegerField',
'ColorField',
'CommentField',
'JSONField',
'LaxURLField',
'MACAddressField',
'PositiveBigIntegerField',
'QueryField',
'SlugField',
'TagFilterField',
)
class BigIntegerField(forms.IntegerField):
"""
An IntegerField constrained to the range of a signed 64-bit integer.
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault('min_value', -BigIntegerModelField.MAX_BIGINT - 1)
kwargs.setdefault('max_value', BigIntegerModelField.MAX_BIGINT)
super().__init__(*args, **kwargs)
class PositiveBigIntegerField(BigIntegerField):
"""
An IntegerField constrained to the range supported by Django's
PositiveBigIntegerField model field.
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault('min_value', 0)
super().__init__(*args, **kwargs)
class QueryField(forms.CharField):
"""
A CharField subclass used for global search/query fields in filter forms.