mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-26 17:26:10 -06:00
Remove FK on ASN to ASNRange
This commit is contained in:
parent
67569fe264
commit
92dd015cab
@ -39,7 +39,6 @@ class ASNRangeSerializer(NetBoxModelSerializer):
|
|||||||
|
|
||||||
class ASNSerializer(NetBoxModelSerializer):
|
class ASNSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:asn-detail')
|
||||||
range = NestedASNRangeSerializer(required=False, allow_null=True)
|
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||||
site_count = serializers.IntegerField(read_only=True)
|
site_count = serializers.IntegerField(read_only=True)
|
||||||
provider_count = serializers.IntegerField(read_only=True)
|
provider_count = serializers.IntegerField(read_only=True)
|
||||||
@ -47,7 +46,7 @@ class ASNSerializer(NetBoxModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = ASN
|
model = ASN
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'asn', 'rir', 'range', 'tenant', 'description', 'comments', 'tags', 'custom_fields',
|
'id', 'url', 'display', 'asn', 'rir', 'tenant', 'description', 'comments', 'tags', 'custom_fields',
|
||||||
'created', 'last_updated', 'site_count', 'provider_count',
|
'created', 'last_updated', 'site_count', 'provider_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -34,9 +34,7 @@ class IPAMRootView(APIRootView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ASNRangeViewSet(NetBoxModelViewSet):
|
class ASNRangeViewSet(NetBoxModelViewSet):
|
||||||
queryset = ASNRange.objects.prefetch_related('tenant', 'rir').annotate(
|
queryset = ASNRange.objects.prefetch_related('tenant', 'rir').all()
|
||||||
asn_count=count_related(ASN, 'range')
|
|
||||||
)
|
|
||||||
serializer_class = serializers.ASNRangeSerializer
|
serializer_class = serializers.ASNRangeSerializer
|
||||||
filterset_class = filtersets.ASNRangeFilterSet
|
filterset_class = filtersets.ASNRangeFilterSet
|
||||||
|
|
||||||
|
@ -202,16 +202,6 @@ class ASNFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label=_('RIR (slug)'),
|
label=_('RIR (slug)'),
|
||||||
)
|
)
|
||||||
range_id = django_filters.ModelMultipleChoiceFilter(
|
|
||||||
queryset=ASNRange.objects.all(),
|
|
||||||
label=_('Range (ID)'),
|
|
||||||
)
|
|
||||||
range = django_filters.ModelMultipleChoiceFilter(
|
|
||||||
field_name='range__slug',
|
|
||||||
queryset=ASNRange.objects.all(),
|
|
||||||
to_field_name='slug',
|
|
||||||
label=_('Range (slug)'),
|
|
||||||
)
|
|
||||||
site_id = django_filters.ModelMultipleChoiceFilter(
|
site_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='sites',
|
field_name='sites',
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
|
@ -130,10 +130,6 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label=_('RIR')
|
label=_('RIR')
|
||||||
)
|
)
|
||||||
range = DynamicModelChoiceField(
|
|
||||||
queryset=ASNRange.objects.all(),
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
tenant = DynamicModelChoiceField(
|
tenant = DynamicModelChoiceField(
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
@ -149,9 +145,9 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
|
|
||||||
model = ASN
|
model = ASN
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('sites', 'rir', 'range', 'tenant', 'description')),
|
(None, ('sites', 'rir', 'tenant', 'description')),
|
||||||
)
|
)
|
||||||
nullable_fields = ('range', 'description', 'comments')
|
nullable_fields = ('tenant', 'description', 'comments')
|
||||||
|
|
||||||
|
|
||||||
class AggregateBulkEditForm(NetBoxModelBulkEditForm):
|
class AggregateBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
|
@ -112,12 +112,6 @@ class ASNImportForm(NetBoxModelImportForm):
|
|||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
help_text=_('Assigned RIR')
|
help_text=_('Assigned RIR')
|
||||||
)
|
)
|
||||||
range = CSVModelChoiceField(
|
|
||||||
queryset=ASNRange.objects.all(),
|
|
||||||
required=False,
|
|
||||||
to_field_name='name',
|
|
||||||
help_text=_('ASN range')
|
|
||||||
)
|
|
||||||
tenant = CSVModelChoiceField(
|
tenant = CSVModelChoiceField(
|
||||||
queryset=Tenant.objects.all(),
|
queryset=Tenant.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
@ -127,7 +121,7 @@ class ASNImportForm(NetBoxModelImportForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ASN
|
model = ASN
|
||||||
fields = ('asn', 'rir', 'range', 'tenant', 'description', 'comments', 'tags')
|
fields = ('asn', 'rir', 'tenant', 'description', 'comments', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class RoleImportForm(NetBoxModelImportForm):
|
class RoleImportForm(NetBoxModelImportForm):
|
||||||
|
@ -140,7 +140,7 @@ class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
model = ASN
|
model = ASN
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'filter_id', 'tag')),
|
(None, ('q', 'filter_id', 'tag')),
|
||||||
('Assignment', ('rir_id', 'range_id', 'site_id')),
|
('Assignment', ('rir_id', 'site_id')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
)
|
)
|
||||||
rir_id = DynamicModelMultipleChoiceField(
|
rir_id = DynamicModelMultipleChoiceField(
|
||||||
@ -148,11 +148,6 @@ class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label=_('RIR')
|
label=_('RIR')
|
||||||
)
|
)
|
||||||
range_id = DynamicModelMultipleChoiceField(
|
|
||||||
queryset=ASNRange.objects.all(),
|
|
||||||
required=False,
|
|
||||||
label=_('Range')
|
|
||||||
)
|
|
||||||
site_id = DynamicModelMultipleChoiceField(
|
site_id = DynamicModelMultipleChoiceField(
|
||||||
queryset=Site.objects.all(),
|
queryset=Site.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 4.1.7 on 2023-02-25 21:18
|
# Generated by Django 4.1.7 on 2023-02-26 19:33
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
@ -38,9 +38,4 @@ class Migration(migrations.Migration):
|
|||||||
'ordering': ('name',),
|
'ordering': ('name',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
|
||||||
model_name='asn',
|
|
||||||
name='range',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ipam.asnrange'),
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
@ -72,7 +72,7 @@ class ASNRange(OrganizationalModel):
|
|||||||
Return all available ASNs within this range.
|
Return all available ASNs within this range.
|
||||||
"""
|
"""
|
||||||
range = set(self.range)
|
range = set(self.range)
|
||||||
existing_asns = set(ASN.objects.filter(range=self).values_list('asn', flat=True))
|
existing_asns = set(self.get_child_asns().values_list('asn', flat=True))
|
||||||
available_asns = sorted(range - existing_asns)
|
available_asns = sorted(range - existing_asns)
|
||||||
|
|
||||||
return available_asns
|
return available_asns
|
||||||
@ -89,12 +89,6 @@ class ASN(PrimaryModel):
|
|||||||
related_name='asns',
|
related_name='asns',
|
||||||
verbose_name='RIR'
|
verbose_name='RIR'
|
||||||
)
|
)
|
||||||
range = models.ForeignKey(
|
|
||||||
to='ipam.ASNRange',
|
|
||||||
on_delete=models.PROTECT,
|
|
||||||
blank=True,
|
|
||||||
null=True
|
|
||||||
)
|
|
||||||
asn = ASNField(
|
asn = ASNField(
|
||||||
unique=True,
|
unique=True,
|
||||||
verbose_name='ASN',
|
verbose_name='ASN',
|
||||||
@ -141,9 +135,3 @@ class ASN(PrimaryModel):
|
|||||||
return f'{self.asn} ({self.asn // 65536}.{self.asn % 65536})'
|
return f'{self.asn} ({self.asn // 65536}.{self.asn % 65536})'
|
||||||
else:
|
else:
|
||||||
return self.asn
|
return self.asn
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
super().clean()
|
|
||||||
|
|
||||||
if self.range and self.asn not in self.range.range:
|
|
||||||
raise ValidationError(f"ASN {self.asn} is outside of assigned range ({self.range})")
|
|
||||||
|
@ -43,9 +43,6 @@ class ASNTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
rir = tables.Column(
|
rir = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
range = tables.Column(
|
|
||||||
linkify=True
|
|
||||||
)
|
|
||||||
asn_asdot = tables.Column(
|
asn_asdot = tables.Column(
|
||||||
accessor=tables.A('asn_asdot'),
|
accessor=tables.A('asn_asdot'),
|
||||||
linkify=True,
|
linkify=True,
|
||||||
@ -72,9 +69,9 @@ class ASNTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = ASN
|
model = ASN
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'asn', 'asn_asdot', 'rir', 'range', 'site_count', 'provider_count', 'tenant', 'tenant_group',
|
'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description',
|
||||||
'description', 'comments', 'sites', 'tags', 'created', 'last_updated', 'actions',
|
'comments', 'sites', 'tags', 'created', 'last_updated', 'actions',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'asn', 'rir', 'range', 'site_count', 'provider_count', 'sites', 'description', 'tenant',
|
'pk', 'asn', 'rir', 'site_count', 'provider_count', 'sites', 'description', 'tenant',
|
||||||
)
|
)
|
||||||
|
@ -92,12 +92,6 @@ class ASNTest(APIViewTestCases.APIViewTestCase):
|
|||||||
)
|
)
|
||||||
RIR.objects.bulk_create(rirs)
|
RIR.objects.bulk_create(rirs)
|
||||||
|
|
||||||
ranges = (
|
|
||||||
ASNRange(name='ASN Range 1', slug='asn-range-1', rir=rirs[0], start=65001, end=65100),
|
|
||||||
ASNRange(name='ASN Range 2', slug='asn-range-2', rir=rirs[1], start=4200000001, end=4200000100),
|
|
||||||
)
|
|
||||||
ASNRange.objects.bulk_create(ranges)
|
|
||||||
|
|
||||||
sites = (
|
sites = (
|
||||||
Site(name='Site 1', slug='site-1'),
|
Site(name='Site 1', slug='site-1'),
|
||||||
Site(name='Site 2', slug='site-2')
|
Site(name='Site 2', slug='site-2')
|
||||||
@ -112,9 +106,9 @@ class ASNTest(APIViewTestCases.APIViewTestCase):
|
|||||||
|
|
||||||
asns = (
|
asns = (
|
||||||
ASN(asn=65000, rir=rirs[0], tenant=tenants[0]),
|
ASN(asn=65000, rir=rirs[0], tenant=tenants[0]),
|
||||||
ASN(asn=65001, rir=rirs[0], tenant=tenants[1], range=ranges[0]),
|
ASN(asn=65001, rir=rirs[0], tenant=tenants[1]),
|
||||||
ASN(asn=4200000000, rir=rirs[1], tenant=tenants[0]),
|
ASN(asn=4200000000, rir=rirs[1], tenant=tenants[0]),
|
||||||
ASN(asn=4200000001, rir=rirs[1], tenant=tenants[1], range=ranges[1]),
|
ASN(asn=4200000001, rir=rirs[1], tenant=tenants[1]),
|
||||||
)
|
)
|
||||||
ASN.objects.bulk_create(asns)
|
ASN.objects.bulk_create(asns)
|
||||||
|
|
||||||
@ -131,12 +125,10 @@ class ASNTest(APIViewTestCases.APIViewTestCase):
|
|||||||
{
|
{
|
||||||
'asn': 65002,
|
'asn': 65002,
|
||||||
'rir': rirs[0].pk,
|
'rir': rirs[0].pk,
|
||||||
'range': ranges[0].pk,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'asn': 4200000002,
|
'asn': 4200000002,
|
||||||
'rir': rirs[1].pk,
|
'rir': rirs[1].pk,
|
||||||
'range': ranges[1].pk,
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -78,14 +78,18 @@ class ASNTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
RIR(name='RIR 2', slug='rir-2', is_private=True),
|
RIR(name='RIR 2', slug='rir-2', is_private=True),
|
||||||
]
|
]
|
||||||
RIR.objects.bulk_create(rirs)
|
RIR.objects.bulk_create(rirs)
|
||||||
sites = [
|
|
||||||
Site.objects.create(name='Site 1', slug='site-1'),
|
sites = (
|
||||||
Site.objects.create(name='Site 2', slug='site-2')
|
Site(name='Site 1', slug='site-1'),
|
||||||
]
|
Site(name='Site 2', slug='site-2')
|
||||||
tenants = [
|
)
|
||||||
Tenant.objects.create(name='Tenant 1', slug='tenant-1'),
|
Site.objects.bulk_create(sites)
|
||||||
Tenant.objects.create(name='Tenant 2', slug='tenant-2'),
|
|
||||||
]
|
tenants = (
|
||||||
|
Tenant(name='Tenant 1', slug='tenant-1'),
|
||||||
|
Tenant(name='Tenant 2', slug='tenant-2'),
|
||||||
|
)
|
||||||
|
Tenant.objects.bulk_create(tenants)
|
||||||
|
|
||||||
asns = (
|
asns = (
|
||||||
ASN(asn=65001, rir=rirs[0], tenant=tenants[0]),
|
ASN(asn=65001, rir=rirs[0], tenant=tenants[0]),
|
||||||
|
@ -199,9 +199,7 @@ class RIRBulkDeleteView(generic.BulkDeleteView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ASNRangeListView(generic.ObjectListView):
|
class ASNRangeListView(generic.ObjectListView):
|
||||||
queryset = ASNRange.objects.annotate(
|
queryset = ASNRange.objects.all()
|
||||||
asn_count=count_related(ASN, 'range'),
|
|
||||||
)
|
|
||||||
filterset = filtersets.ASNRangeFilterSet
|
filterset = filtersets.ASNRangeFilterSet
|
||||||
filterset_form = forms.ASNRangeFilterForm
|
filterset_form = forms.ASNRangeFilterForm
|
||||||
table = tables.ASNRangeTable
|
table = tables.ASNRangeTable
|
||||||
|
@ -29,10 +29,6 @@
|
|||||||
<a href="{% url 'ipam:asn_list' %}?rir={{ object.rir.slug }}">{{ object.rir }}</a>
|
<a href="{% url 'ipam:asn_list' %}?rir={{ object.rir.slug }}">{{ object.rir }}</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td>Range</td>
|
|
||||||
<td>{{ object.range|linkify|placeholder }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td>Tenant</td>
|
<td>Tenant</td>
|
||||||
<td>
|
<td>
|
||||||
|
Loading…
Reference in New Issue
Block a user