mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-08 08:38:16 -06:00
Fix logic for upper range boundaries
This commit is contained in:
parent
f6c2396a30
commit
c1a0eb8b37
@ -10,7 +10,9 @@ def move_min_max(apps, schema_editor):
|
||||
VLANGroup = apps.get_model('ipam', 'VLANGroup')
|
||||
for group in VLANGroup.objects.all():
|
||||
if group.min_vid or group.max_vid:
|
||||
group.vlan_id_ranges = [NumericRange(group.min_vid, group.max_vid)]
|
||||
group.vlan_id_ranges = [
|
||||
NumericRange(group.min_vid, group.max_vid, bounds='[]')
|
||||
]
|
||||
|
||||
group._total_vlan_ids = 0
|
||||
for vlan_range in group.vlan_id_ranges:
|
||||
@ -31,7 +33,7 @@ class Migration(migrations.Migration):
|
||||
name='vlan_id_ranges',
|
||||
field=django.contrib.postgres.fields.ArrayField(
|
||||
base_field=django.contrib.postgres.fields.ranges.IntegerRangeField(),
|
||||
default=ipam.models.vlans.default_vland_id_ranges,
|
||||
default=ipam.models.vlans.default_vlan_id_ranges,
|
||||
size=None
|
||||
),
|
||||
),
|
||||
|
@ -21,7 +21,7 @@ __all__ = (
|
||||
)
|
||||
|
||||
|
||||
def default_vland_id_ranges():
|
||||
def default_vlan_id_ranges():
|
||||
return [
|
||||
NumericRange(VLAN_VID_MIN, VLAN_VID_MAX, bounds='[]')
|
||||
]
|
||||
@ -57,7 +57,7 @@ class VLANGroup(OrganizationalModel):
|
||||
vlan_id_ranges = ArrayField(
|
||||
IntegerRangeField(),
|
||||
verbose_name=_('VLAN ID ranges'),
|
||||
default=default_vland_id_ranges
|
||||
default=default_vlan_id_ranges
|
||||
)
|
||||
_total_vlan_ids = models.PositiveBigIntegerField(
|
||||
default=VLAN_VID_MAX - VLAN_VID_MIN + 1
|
||||
@ -120,7 +120,7 @@ class VLANGroup(OrganizationalModel):
|
||||
"""
|
||||
available_vlans = {}
|
||||
for vlan_range in self.vlan_id_ranges:
|
||||
available_vlans = {vid for vid in range(vlan_range.lower, vlan_range.upper + 1)}
|
||||
available_vlans = {vid for vid in range(vlan_range.lower, vlan_range.upper)}
|
||||
available_vlans -= set(VLAN.objects.filter(group=self).values_list('vid', flat=True))
|
||||
|
||||
return sorted(available_vlans)
|
||||
|
@ -9,6 +9,7 @@ from utilities.querysets import RestrictedQuerySet
|
||||
__all__ = (
|
||||
'ASNRangeQuerySet',
|
||||
'PrefixQuerySet',
|
||||
'VLANGroupQuerySet',
|
||||
'VLANQuerySet',
|
||||
)
|
||||
|
||||
|
@ -168,7 +168,7 @@ class IntegerRangeSerializer(serializers.Serializer):
|
||||
if type(data[0]) is not int or type(data[1]) is not int:
|
||||
raise ValidationError(_("Range boundaries must be defined as integers."))
|
||||
|
||||
return NumericRange(data[0], data[1])
|
||||
return NumericRange(data[0], data[1], bounds='[]')
|
||||
|
||||
def to_representation(self, instance):
|
||||
return instance.lower, instance.upper
|
||||
return instance.lower, instance.upper - 1
|
||||
|
@ -138,27 +138,25 @@ def ranges_to_string(ranges):
|
||||
"""
|
||||
Generate a human-friendly string from a set of ranges. Intended for use with ArrayField.
|
||||
For example:
|
||||
[Range(1, 100), Range(200, 300)] => "1-100, 200-300"
|
||||
[[1, 100)], [200, 300)] => "1-99,200-299"
|
||||
"""
|
||||
if not ranges:
|
||||
return ''
|
||||
return ', '.join([f"{r.lower}-{r.upper}" for r in ranges])
|
||||
return ','.join([f"{r.lower}-{r.upper - 1}" for r in ranges])
|
||||
|
||||
|
||||
def string_to_range_array(value):
|
||||
"""
|
||||
Given a string in the format "1-100, 200-300" create an array of ranges. Intended for use with ArrayField.
|
||||
For example:
|
||||
"1-100, 200-300" => [1-100, 200-300]
|
||||
"1-99,200-299" => [NumericRange(1, 100), NumericRange(200, 300)]
|
||||
"""
|
||||
if not value:
|
||||
return None
|
||||
ranges = value.split(",")
|
||||
values = []
|
||||
for dash_range in value.split(','):
|
||||
if '-' not in dash_range:
|
||||
return None
|
||||
|
||||
lower, upper = dash_range.split('-')
|
||||
values.append(NumericRange(int(lower), int(upper)))
|
||||
values.append(NumericRange(int(lower), int(upper), bounds='[]'))
|
||||
return values
|
||||
|
@ -2,7 +2,7 @@ import json
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.contrib.postgres.fields import ArrayField, RangeField
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
from django.db.models import ManyToManyField, ManyToManyRel, JSONField
|
||||
from django.forms.models import model_to_dict
|
||||
@ -12,6 +12,7 @@ from taggit.managers import TaggableManager
|
||||
|
||||
from core.models import ObjectType
|
||||
from users.models import ObjectPermission
|
||||
from utilities.data import ranges_to_string
|
||||
from utilities.object_types import object_type_identifier
|
||||
from utilities.permissions import resolve_permission_type
|
||||
from .utils import DUMMY_CF_DATA, extract_form_failures
|
||||
@ -139,6 +140,9 @@ class ModelTestCase(TestCase):
|
||||
if type(field.base_field) is ArrayField:
|
||||
# Handle nested arrays (e.g. choice sets)
|
||||
model_dict[key] = '\n'.join([f'{k},{v}' for k, v in value])
|
||||
elif issubclass(type(field.base_field), RangeField):
|
||||
# Handle arrays of numeric ranges (e.g. VLANGroup VLAN ID ranges)
|
||||
model_dict[key] = ranges_to_string(value)
|
||||
else:
|
||||
model_dict[key] = ','.join([str(v) for v in value])
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user