Add relationship from ASN to ASNRange

This commit is contained in:
jeremystretch 2023-02-25 15:14:31 -05:00
parent 7e7c9e981d
commit 6ce40b58cb
10 changed files with 57 additions and 10 deletions

View File

@ -38,6 +38,7 @@ 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)
@ -45,7 +46,7 @@ class ASNSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = ASN model = ASN
fields = [ fields = [
'id', 'url', 'display', 'asn', 'rir', 'tenant', 'description', 'comments', 'tags', 'custom_fields', 'id', 'url', 'display', 'asn', 'rir', 'range', 'tenant', 'description', 'comments', 'tags', 'custom_fields',
'created', 'last_updated', 'site_count', 'provider_count', 'created', 'last_updated', 'site_count', 'provider_count',
] ]

View File

@ -192,6 +192,16 @@ 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(),

View File

@ -125,6 +125,10 @@ 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
@ -140,9 +144,9 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm):
model = ASN model = ASN
fieldsets = ( fieldsets = (
(None, ('sites', 'rir', 'tenant', 'description')), (None, ('sites', 'rir', 'range', 'tenant', 'description')),
) )
nullable_fields = ('date_added', 'description', 'comments') nullable_fields = ('range', 'description', 'comments')
class AggregateBulkEditForm(NetBoxModelBulkEditForm): class AggregateBulkEditForm(NetBoxModelBulkEditForm):

View File

@ -107,6 +107,11 @@ 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(),
to_field_name='name',
help_text=_('ASN range')
)
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
@ -116,7 +121,7 @@ class ASNImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ASN model = ASN
fields = ('asn', 'rir', 'tenant', 'description', 'comments', 'tags') fields = ('asn', 'rir', 'range', 'tenant', 'description', 'comments', 'tags')
class RoleImportForm(NetBoxModelImportForm): class RoleImportForm(NetBoxModelImportForm):

View File

@ -135,7 +135,7 @@ class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
model = ASN model = ASN
fieldsets = ( fieldsets = (
(None, ('q', 'filter_id', 'tag')), (None, ('q', 'filter_id', 'tag')),
('Assignment', ('rir_id', 'site_id')), ('Assignment', ('rir_id', 'range_id', 'site_id')),
('Tenant', ('tenant_group_id', 'tenant_id')), ('Tenant', ('tenant_group_id', 'tenant_id')),
) )
rir_id = DynamicModelMultipleChoiceField( rir_id = DynamicModelMultipleChoiceField(
@ -143,6 +143,11 @@ 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,

View File

@ -106,7 +106,7 @@ class ASNRange(OrganizationalModel):
verbose_name_plural = 'ASN ranges' verbose_name_plural = 'ASN ranges'
def __str__(self): def __str__(self):
return f'ASNs {self.range_as_string()}' return f'{self.name} ({self.range_as_string()})'
def get_absolute_url(self): def get_absolute_url(self):
return reverse('ipam:asnrange', args=[self.pk]) return reverse('ipam:asnrange', args=[self.pk])

View File

@ -37,6 +37,12 @@ class ASNTable(TenancyColumnsMixin, NetBoxTable):
asn = tables.Column( asn = tables.Column(
linkify=True linkify=True
) )
rir = tables.Column(
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,
@ -63,7 +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', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description', 'pk', 'asn', 'asn_asdot', 'rir', 'range', 'site_count', 'provider_count', 'tenant', 'tenant_group',
'comments', 'sites', 'tags', 'created', 'last_updated', 'actions', 'description', 'comments', 'sites', 'tags', 'created', 'last_updated', 'actions',
)
default_columns = (
'pk', 'asn', 'rir', 'range', 'site_count', 'provider_count', 'sites', 'description', 'tenant',
) )
default_columns = ('pk', 'asn', 'rir', 'site_count', 'provider_count', 'sites', 'description', 'tenant')

View File

@ -213,7 +213,7 @@ class ASNRangeView(generic.ObjectView):
def get_extra_context(self, request, instance): def get_extra_context(self, request, instance):
related_models = ( related_models = (
(ASN.objects.restrict(request.user, 'view').filter(range=instance), 'asn_id'), (ASN.objects.restrict(request.user, 'view').filter(range=instance), 'range_id'),
) )
return { return {

View File

@ -7,6 +7,9 @@
{% block breadcrumbs %} {% block breadcrumbs %}
{{ block.super }} {{ block.super }}
<li class="breadcrumb-item"><a href="{% url 'ipam:asn_list' %}?rir_id={{ object.rir.pk }}">{{ object.rir }}</a></li> <li class="breadcrumb-item"><a href="{% url 'ipam:asn_list' %}?rir_id={{ object.rir.pk }}">{{ object.rir }}</a></li>
{% if object.range %}
<li class="breadcrumb-item"><a href="{% url 'ipam:asn_list' %}?range_id={{ object.range.pk }}">{{ object.range }}</a></li>
{% endif %}
{% endblock breadcrumbs %} {% endblock breadcrumbs %}
{% block content %} {% block content %}
@ -26,6 +29,10 @@
<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>

View File

@ -46,6 +46,13 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col col-md-12"> <div class="col col-md-12">
<div class="card">
<h5 class="card-header">ASNs</h5>
<div class="card-body htmx-container table-responsive"
hx-get="{% url 'ipam:asn_list' %}?range_id={{ object.pk }}"
hx-trigger="load"
></div>
</div>
{% plugin_full_width_page object %} {% plugin_full_width_page object %}
</div> </div>
</div> </div>