9627 change to NumericArrayField

This commit is contained in:
Arthur Hanson 2024-06-24 11:40:10 -07:00
parent 3c89651076
commit 72ed36fd5b
8 changed files with 34 additions and 67 deletions

View File

@ -12,7 +12,6 @@ from tenancy.models import Tenant
from utilities.forms import add_blank_choice
from utilities.forms.fields import (
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
NumericRangeArrayField,
)
from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import BulkEditNullBooleanSelect
@ -472,13 +471,16 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
'group_id': '$clustergroup',
}
)
vlan_id_ranges = NumericRangeArrayField(
allowed_vids = NumericArrayField(
required=False,
label=_('min/max VLAN IDs'),
base_field=forms.IntegerField(),
help_text=_('Comma-separated list of numeric VLAN IDs. A range may be specified using a hyphen.'),
)
model = VLANGroup
fieldsets = (
FieldSet('site', 'vlan_id_ranges', 'description'),
FieldSet('site', 'allowed_vids', 'description'),
FieldSet(
'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster', name=_('Scope')
),

View File

@ -10,7 +10,7 @@ from netbox.forms import NetBoxModelImportForm
from tenancy.models import Tenant
from utilities.forms.fields import (
CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelMultipleChoiceField, SlugField,
NumericRangeArrayField,
NumericArrayField,
)
from virtualization.models import VirtualMachine, VMInterface
@ -412,13 +412,16 @@ class VLANGroupImportForm(NetBoxModelImportForm):
required=False,
label=_('Scope type (app & model)')
)
vlan_id_ranges = NumericRangeArrayField(
allowed_vids = NumericArrayField(
required=False,
label=_('min/max VLAN IDs'),
base_field=forms.IntegerField(),
help_text=_('Comma-separated list of numeric VLAN IDs. A range may be specified using a hyphen.'),
)
class Meta:
model = VLANGroup
fields = ('name', 'slug', 'scope_type', 'scope_id', 'vlan_id_ranges', 'description', 'tags')
fields = ('name', 'slug', 'scope_type', 'scope_id', 'allowed_vids', 'description', 'tags')
labels = {
'scope_id': 'Scope ID',
}

View File

@ -15,7 +15,7 @@ from utilities.exceptions import PermissionsViolation
from utilities.forms import add_blank_choice
from utilities.forms.fields import (
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
SlugField, NumericRangeArrayField
SlugField
)
from utilities.forms.rendering import FieldSet, InlineFields, ObjectAttribute, TabbedGroups
from utilities.forms.widgets import DatePicker
@ -633,13 +633,16 @@ class VLANGroupForm(NetBoxModelForm):
}
)
slug = SlugField()
vlan_id_ranges = NumericRangeArrayField(
required=False
allowed_vids = NumericArrayField(
required=False,
label=_('min/max VLAN IDs'),
base_field=forms.IntegerField(),
help_text=_('Comma-separated list of numeric VLAN IDs. A range may be specified using a hyphen.'),
)
fieldsets = (
FieldSet('name', 'slug', 'description', 'tags', name=_('VLAN Group')),
FieldSet('vlan_id_ranges', name=_('Child VLANs')),
FieldSet('allowed_vids', name=_('Child VLANs')),
FieldSet(
'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster',
name=_('Scope')
@ -650,7 +653,7 @@ class VLANGroupForm(NetBoxModelForm):
model = VLANGroup
fields = [
'name', 'slug', 'description', 'scope_type', 'region', 'sitegroup', 'site', 'location', 'rack',
'clustergroup', 'cluster', 'vlan_id_ranges', 'tags',
'clustergroup', 'cluster', 'allowed_vids', 'tags',
]
def __init__(self, *args, **kwargs):

View File

@ -251,7 +251,7 @@ class VLANType(NetBoxObjectType):
class VLANGroupType(OrganizationalObjectType):
vlans: List[VLANType]
vlan_id_ranges: List[str]
allowed_vids: str
@strawberry_django.field
def scope(self) -> Annotated[Union[

View File

@ -30,18 +30,13 @@ class Migration(migrations.Migration):
operations = [
migrations.AddField(
model_name='vlangroup',
name='vlan_id_ranges',
name='allowed_vids',
field=django.contrib.postgres.fields.ArrayField(
base_field=django.contrib.postgres.fields.ranges.BigIntegerRangeField(),
blank=True, null=True, size=None,
default=ipam.models.vlans.get_default_vlan_ids,
base_field=models.PositiveSmallIntegerField(),
default=ipam.models.vlans.get_default_allowed_vids,
size=None,
),
),
migrations.AddField(
model_name='vlangroup',
name='_total_vlan_ids',
field=models.PositiveBigIntegerField(default=4094),
),
migrations.RunPython(
code=move_min_max,
reverse_code=migrations.RunPython.noop

View File

@ -1,9 +1,8 @@
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.postgres.fields import ArrayField, BigIntegerRangeField
from django.contrib.postgres.fields import ArrayField
from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.backends.postgresql.psycopg_any import NumericRange
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
@ -21,8 +20,8 @@ __all__ = (
)
def get_default_vlan_ids():
return [NumericRange(VLAN_VID_MIN, VLAN_VID_MAX)]
def get_default_allowed_vids():
return list(range(VLAN_VID_MIN, VLAN_VID_MAX + 1))
class VLANGroup(OrganizationalModel):
@ -52,16 +51,11 @@ class VLANGroup(OrganizationalModel):
ct_field='scope_type',
fk_field='scope_id'
)
vlan_id_ranges = ArrayField(
BigIntegerRangeField(),
allowed_vids = ArrayField(
verbose_name=_('min/max VLAN IDs'),
default=get_default_vlan_ids,
help_text=_('Ranges of Minimum, maximum VLAN IDs'),
blank=True,
null=True
)
_total_vlan_ids = models.PositiveBigIntegerField(
default=VLAN_VID_MAX - VLAN_VID_MIN + 1
base_field=models.PositiveSmallIntegerField(),
default=get_default_allowed_vids,
help_text=_('Ranges of Minimum-maximum child VLAN VID'),
)
objects = VLANGroupQuerySet.as_manager()

View File

@ -1,5 +1,5 @@
from django.contrib.contenttypes.models import ContentType
from django.db.models import Count, F, OuterRef, Q, Subquery, Value
from django.db.models import Count, F, Func, OuterRef, Q, Subquery, Value
from django.db.models.expressions import RawSQL
from django.db.models.functions import Round
@ -63,7 +63,8 @@ class VLANGroupQuerySet(RestrictedQuerySet):
return self.annotate(
vlan_count=count_related(VLAN, 'group'),
utilization=Round(F('vlan_count') * 100 / F('_total_vlan_ids'), 2)
total_allowed_vids=Func(F('allowed_vids'), function='CARDINALITY'),
utilization=Round(F('vlan_count') * 100 / F('total_allowed_vids'), 2)
)

View File

@ -7,7 +7,6 @@ from ..utils import parse_numeric_range
__all__ = (
'NumericArrayField',
'NumericRangeArrayField',
)
@ -26,33 +25,3 @@ class NumericArrayField(SimpleArrayField):
if isinstance(value, str):
value = ','.join([str(n) for n in parse_numeric_range(value)])
return super().to_python(value)
class NumericRangeArrayField(forms.CharField):
"""
A field which allows for array of numeric ranges:
Example: 1-5,7-20,30-50
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.help_text:
self.help_text = _(
"Specify one or more numeric ranges separated by commas "
"Example: <code>1-5,20-30</code>"
)
def clean(self, value):
if value and not self.to_python(value):
raise forms.ValidationError(
_("Invalid ranges ({value}). Must be range of number '100-200' and ranges must be in ascending order.").format(value=value)
)
return super().clean(value)
def prepare_value(self, value):
if isinstance(value, str):
return value
return ranges_to_string(value)
def to_python(self, value):
return string_to_range_array(value)