mirror of
https://github.com/netbox-community/netbox.git
synced 2026-04-27 11:17:27 +02:00
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:
@@ -26,6 +26,7 @@ from tenancy.models import *
|
|||||||
from users.filterset_mixins import OwnerFilterMixin
|
from users.filterset_mixins import OwnerFilterMixin
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from utilities.filters import (
|
from utilities.filters import (
|
||||||
|
MultiValueBigNumberFilter,
|
||||||
MultiValueCharFilter,
|
MultiValueCharFilter,
|
||||||
MultiValueContentTypeFilter,
|
MultiValueContentTypeFilter,
|
||||||
MultiValueMACAddressFilter,
|
MultiValueMACAddressFilter,
|
||||||
@@ -2175,7 +2176,7 @@ class InterfaceFilterSet(
|
|||||||
distinct=False,
|
distinct=False,
|
||||||
label=_('LAG interface (ID)'),
|
label=_('LAG interface (ID)'),
|
||||||
)
|
)
|
||||||
speed = MultiValueNumberFilter()
|
speed = MultiValueBigNumberFilter(min_value=0)
|
||||||
duplex = django_filters.MultipleChoiceFilter(
|
duplex = django_filters.MultipleChoiceFilter(
|
||||||
choices=InterfaceDuplexChoices,
|
choices=InterfaceDuplexChoices,
|
||||||
distinct=False,
|
distinct=False,
|
||||||
|
|||||||
@@ -20,7 +20,13 @@ from netbox.forms.mixins import ChangelogMessageMixin, OwnerMixin
|
|||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from utilities.forms import BulkEditForm, add_blank_choice, form_from_model
|
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.rendering import FieldSet, InlineFields, TabbedGroups
|
||||||
from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions
|
from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions
|
||||||
from virtualization.models import Cluster
|
from virtualization.models import Cluster
|
||||||
@@ -1420,7 +1426,7 @@ class InterfaceBulkEditForm(
|
|||||||
'device_id': '$device',
|
'device_id': '$device',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
speed = forms.IntegerField(
|
speed = PositiveBigIntegerField(
|
||||||
label=_('Speed'),
|
label=_('Speed'),
|
||||||
required=False,
|
required=False,
|
||||||
widget=NumberWithOptions(
|
widget=NumberWithOptions(
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
|
|||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from users.models import 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, DynamicModelMultipleChoiceField, TagFilterField
|
from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, PositiveBigIntegerField, 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
|
||||||
@@ -1603,7 +1603,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
|||||||
choices=InterfaceTypeChoices,
|
choices=InterfaceTypeChoices,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
speed = forms.IntegerField(
|
speed = PositiveBigIntegerField(
|
||||||
label=_('Speed'),
|
label=_('Speed'),
|
||||||
required=False,
|
required=False,
|
||||||
widget=NumberWithOptions(
|
widget=NumberWithOptions(
|
||||||
|
|||||||
@@ -47,7 +47,13 @@ if TYPE_CHECKING:
|
|||||||
VRFFilter,
|
VRFFilter,
|
||||||
)
|
)
|
||||||
from netbox.graphql.enums import ColorEnum
|
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 users.graphql.filters import UserFilter
|
||||||
from virtualization.graphql.filters import ClusterFilter
|
from virtualization.graphql.filters import ClusterFilter
|
||||||
from vpn.graphql.filters import L2VPNFilter, TunnelTerminationFilter
|
from vpn.graphql.filters import L2VPNFilter, TunnelTerminationFilter
|
||||||
@@ -519,7 +525,7 @@ class InterfaceFilter(
|
|||||||
strawberry_django.filter_field()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
mgmt_only: FilterLookup[bool] | None = 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()
|
strawberry_django.filter_field()
|
||||||
)
|
)
|
||||||
duplex: BaseFilterLookup[Annotated['InterfaceDuplexEnum', strawberry.lazy('dcim.graphql.enums')]] | None = (
|
duplex: BaseFilterLookup[Annotated['InterfaceDuplexEnum', strawberry.lazy('dcim.graphql.enums')]] | None = (
|
||||||
|
|||||||
@@ -433,6 +433,7 @@ class MACAddressType(PrimaryObjectType):
|
|||||||
)
|
)
|
||||||
class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin):
|
class InterfaceType(IPAddressesMixin, ModularComponentType, CabledObjectMixin, PathEndpointMixin):
|
||||||
_name: str
|
_name: str
|
||||||
|
speed: BigInt | None
|
||||||
wwn: str | None
|
wwn: str | None
|
||||||
parent: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None
|
parent: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None
|
||||||
bridge: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None
|
bridge: Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')] | None
|
||||||
|
|||||||
15
netbox/dcim/migrations/0227_alter_interface_speed_bigint.py
Normal file
15
netbox/dcim/migrations/0227_alter_interface_speed_bigint.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -806,7 +806,7 @@ class Interface(
|
|||||||
verbose_name=_('management only'),
|
verbose_name=_('management only'),
|
||||||
help_text=_('This interface is used only for out-of-band management')
|
help_text=_('This interface is used only for out-of-band management')
|
||||||
)
|
)
|
||||||
speed = models.PositiveIntegerField(
|
speed = models.PositiveBigIntegerField(
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name=_('speed (Kbps)')
|
verbose_name=_('speed (Kbps)')
|
||||||
|
|||||||
@@ -1932,7 +1932,7 @@ class InterfaceTest(Mixins.ComponentTraceMixin, APIViewTestCases.APIViewTestCase
|
|||||||
'name': 'Interface 4',
|
'name': 'Interface 4',
|
||||||
'type': '1000base-t',
|
'type': '1000base-t',
|
||||||
'mode': InterfaceModeChoices.MODE_TAGGED,
|
'mode': InterfaceModeChoices.MODE_TAGGED,
|
||||||
'speed': 1000000,
|
'speed': 16000000000,
|
||||||
'duplex': 'full',
|
'duplex': 'full',
|
||||||
'vrf': vrfs[0].pk,
|
'vrf': vrfs[0].pk,
|
||||||
'poe_mode': InterfacePoEModeChoices.MODE_PD,
|
'poe_mode': InterfacePoEModeChoices.MODE_PD,
|
||||||
|
|||||||
@@ -7,9 +7,12 @@ from django_filters.constants import EMPTY_VALUES
|
|||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_spectacular.utils import extend_schema_field
|
from drf_spectacular.utils import extend_schema_field
|
||||||
|
|
||||||
|
from .forms.fields import BigIntegerField
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ContentTypeFilter',
|
'ContentTypeFilter',
|
||||||
'MultiValueArrayFilter',
|
'MultiValueArrayFilter',
|
||||||
|
'MultiValueBigNumberFilter',
|
||||||
'MultiValueCharFilter',
|
'MultiValueCharFilter',
|
||||||
'MultiValueContentTypeFilter',
|
'MultiValueContentTypeFilter',
|
||||||
'MultiValueDateFilter',
|
'MultiValueDateFilter',
|
||||||
@@ -77,6 +80,11 @@ class MultiValueNumberFilter(django_filters.MultipleChoiceFilter):
|
|||||||
field_class = multivalue_field_factory(forms.IntegerField)
|
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)
|
@extend_schema_field(OpenApiTypes.DECIMAL)
|
||||||
class MultiValueDecimalFilter(django_filters.MultipleChoiceFilter):
|
class MultiValueDecimalFilter(django_filters.MultipleChoiceFilter):
|
||||||
field_class = multivalue_field_factory(forms.DecimalField)
|
field_class = multivalue_field_factory(forms.DecimalField)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import json
|
|||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.db.models import BigIntegerField as BigIntegerModelField
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
from django.forms.fields import InvalidJSONInput
|
from django.forms.fields import InvalidJSONInput
|
||||||
from django.forms.fields import JSONField as _JSONField
|
from django.forms.fields import JSONField as _JSONField
|
||||||
@@ -13,17 +14,39 @@ from utilities.forms import widgets
|
|||||||
from utilities.validators import EnhancedURLValidator
|
from utilities.validators import EnhancedURLValidator
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
'BigIntegerField',
|
||||||
'ColorField',
|
'ColorField',
|
||||||
'CommentField',
|
'CommentField',
|
||||||
'JSONField',
|
'JSONField',
|
||||||
'LaxURLField',
|
'LaxURLField',
|
||||||
'MACAddressField',
|
'MACAddressField',
|
||||||
|
'PositiveBigIntegerField',
|
||||||
'QueryField',
|
'QueryField',
|
||||||
'SlugField',
|
'SlugField',
|
||||||
'TagFilterField',
|
'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):
|
class QueryField(forms.CharField):
|
||||||
"""
|
"""
|
||||||
A CharField subclass used for global search/query fields in filter forms.
|
A CharField subclass used for global search/query fields in filter forms.
|
||||||
|
|||||||
Reference in New Issue
Block a user