mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Model import/export route targets on VRFs
This commit is contained in:
@ -26,14 +26,16 @@ from .nested_serializers import *
|
||||
class VRFSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='ipam-api:vrf-detail')
|
||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||
import_targets = NestedRouteTargetSerializer(required=False, allow_null=True, many=True)
|
||||
export_targets = NestedRouteTargetSerializer(required=False, allow_null=True, many=True)
|
||||
ipaddress_count = serializers.IntegerField(read_only=True)
|
||||
prefix_count = serializers.IntegerField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = VRF
|
||||
fields = [
|
||||
'id', 'url', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'tags', 'display_name',
|
||||
'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'prefix_count',
|
||||
'id', 'url', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets',
|
||||
'tags', 'display_name', 'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'prefix_count',
|
||||
]
|
||||
|
||||
|
||||
|
@ -30,7 +30,9 @@ class IPAMRootView(APIRootView):
|
||||
#
|
||||
|
||||
class VRFViewSet(CustomFieldModelViewSet):
|
||||
queryset = VRF.objects.prefetch_related('tenant').prefetch_related('tags').annotate(
|
||||
queryset = VRF.objects.prefetch_related('tenant').prefetch_related(
|
||||
'import_targets', 'export_targets', 'tags'
|
||||
).annotate(
|
||||
ipaddress_count=get_subquery(IPAddress, 'vrf'),
|
||||
prefix_count=get_subquery(Prefix, 'vrf')
|
||||
).order_by(*VRF._meta.ordering)
|
||||
|
@ -35,6 +35,28 @@ class VRFFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet, Create
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
import_target_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='import_targets',
|
||||
queryset=RouteTarget.objects.all(),
|
||||
label='Import target',
|
||||
)
|
||||
import_target = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='import_targets__name',
|
||||
queryset=RouteTarget.objects.all(),
|
||||
to_field_name='name',
|
||||
label='Import target (name)',
|
||||
)
|
||||
export_target_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='export_targets',
|
||||
queryset=RouteTarget.objects.all(),
|
||||
label='Export target',
|
||||
)
|
||||
export_target = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='export_targets__name',
|
||||
queryset=RouteTarget.objects.all(),
|
||||
to_field_name='name',
|
||||
label='Export target (name)',
|
||||
)
|
||||
tag = TagFilter()
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
@ -56,6 +78,28 @@ class RouteTargetFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldFilterSet
|
||||
method='search',
|
||||
label='Search',
|
||||
)
|
||||
importing_vrf_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='importing_vrfs',
|
||||
queryset=VRF.objects.all(),
|
||||
label='Importing VRF',
|
||||
)
|
||||
importing_vrf = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='importing_vrfs__rd',
|
||||
queryset=VRF.objects.all(),
|
||||
to_field_name='rd',
|
||||
label='Import VRF (RD)',
|
||||
)
|
||||
exporting_vrf_id = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='exporting_vrfs',
|
||||
queryset=VRF.objects.all(),
|
||||
label='Exporting VRF',
|
||||
)
|
||||
exporting_vrf = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='exporting_vrfs__rd',
|
||||
queryset=VRF.objects.all(),
|
||||
to_field_name='rd',
|
||||
label='Export VRF (RD)',
|
||||
)
|
||||
tag = TagFilter()
|
||||
|
||||
def search(self, queryset, name, value):
|
||||
|
@ -31,6 +31,14 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([
|
||||
#
|
||||
|
||||
class VRFForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
import_targets = DynamicModelMultipleChoiceField(
|
||||
queryset=RouteTarget.objects.all(),
|
||||
required=False
|
||||
)
|
||||
export_targets = DynamicModelMultipleChoiceField(
|
||||
queryset=RouteTarget.objects.all(),
|
||||
required=False
|
||||
)
|
||||
tags = DynamicModelMultipleChoiceField(
|
||||
queryset=Tag.objects.all(),
|
||||
required=False
|
||||
@ -39,7 +47,8 @@ class VRFForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
|
||||
class Meta:
|
||||
model = VRF
|
||||
fields = [
|
||||
'name', 'rd', 'enforce_unique', 'description', 'tenant_group', 'tenant', 'tags',
|
||||
'name', 'rd', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tenant_group', 'tenant',
|
||||
'tags',
|
||||
]
|
||||
labels = {
|
||||
'rd': "RD",
|
||||
@ -89,11 +98,21 @@ class VRFBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm
|
||||
|
||||
class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
model = VRF
|
||||
field_order = ['q', 'tenant_group', 'tenant']
|
||||
field_order = ['q', 'import_target', 'export_target', 'tenant_group', 'tenant']
|
||||
q = forms.CharField(
|
||||
required=False,
|
||||
label='Search'
|
||||
)
|
||||
import_target = DynamicModelMultipleChoiceField(
|
||||
queryset=RouteTarget.objects.all(),
|
||||
to_field_name='name',
|
||||
required=False
|
||||
)
|
||||
export_target = DynamicModelMultipleChoiceField(
|
||||
queryset=RouteTarget.objects.all(),
|
||||
to_field_name='name',
|
||||
required=False
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
@ -149,11 +168,21 @@ class RouteTargetBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulk
|
||||
|
||||
class RouteTargetFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
model = RouteTarget
|
||||
field_order = ['q', 'name', 'tenant_group', 'tenant']
|
||||
field_order = ['q', 'name', 'tenant_group', 'tenant', 'importing_vrfs', 'exporting_vrfs']
|
||||
q = forms.CharField(
|
||||
required=False,
|
||||
label='Search'
|
||||
)
|
||||
importing_vrf_id = DynamicModelMultipleChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label='Imported by VRF'
|
||||
)
|
||||
exporting_vrf_id = DynamicModelMultipleChoiceField(
|
||||
queryset=VRF.objects.all(),
|
||||
required=False,
|
||||
label='Exported by VRF'
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
|
||||
|
||||
|
@ -31,4 +31,14 @@ class Migration(migrations.Migration):
|
||||
'ordering': ['name'],
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vrf',
|
||||
name='export_targets',
|
||||
field=models.ManyToManyField(blank=True, related_name='exporting_vrfs', to='ipam.RouteTarget'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='vrf',
|
||||
name='import_targets',
|
||||
field=models.ManyToManyField(blank=True, related_name='importing_vrfs', to='ipam.RouteTarget'),
|
||||
),
|
||||
]
|
||||
|
@ -71,6 +71,16 @@ class VRF(ChangeLoggedModel, CustomFieldModel):
|
||||
max_length=200,
|
||||
blank=True
|
||||
)
|
||||
import_targets = models.ManyToManyField(
|
||||
to='ipam.RouteTarget',
|
||||
related_name='importing_vrfs',
|
||||
blank=True
|
||||
)
|
||||
export_targets = models.ManyToManyField(
|
||||
to='ipam.RouteTarget',
|
||||
related_name='exporting_vrfs',
|
||||
blank=True
|
||||
)
|
||||
tags = TaggableManager(through=TaggedItem)
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
|
@ -39,9 +39,20 @@ class VRFView(ObjectView):
|
||||
vrf = get_object_or_404(self.queryset, pk=pk)
|
||||
prefix_count = Prefix.objects.restrict(request.user, 'view').filter(vrf=vrf).count()
|
||||
|
||||
import_targets_table = tables.RouteTargetTable(
|
||||
vrf.import_targets.prefetch_related('tenant'),
|
||||
orderable=False
|
||||
)
|
||||
export_targets_table = tables.RouteTargetTable(
|
||||
vrf.export_targets.prefetch_related('tenant'),
|
||||
orderable=False
|
||||
)
|
||||
|
||||
return render(request, 'ipam/vrf.html', {
|
||||
'vrf': vrf,
|
||||
'prefix_count': prefix_count,
|
||||
'import_targets_table': import_targets_table,
|
||||
'export_targets_table': export_targets_table,
|
||||
})
|
||||
|
||||
|
||||
@ -91,8 +102,19 @@ class RouteTargetView(ObjectView):
|
||||
def get(self, request, pk):
|
||||
routetarget = get_object_or_404(self.queryset, pk=pk)
|
||||
|
||||
importing_vrfs_table = tables.VRFTable(
|
||||
routetarget.importing_vrfs.prefetch_related('tenant'),
|
||||
orderable=False
|
||||
)
|
||||
exporting_vrfs_table = tables.VRFTable(
|
||||
routetarget.exporting_vrfs.prefetch_related('tenant'),
|
||||
orderable=False
|
||||
)
|
||||
|
||||
return render(request, 'ipam/routetarget.html', {
|
||||
'routetarget': routetarget,
|
||||
'importing_vrfs_table': importing_vrfs_table,
|
||||
'exporting_vrfs_table': exporting_vrfs_table,
|
||||
})
|
||||
|
||||
|
||||
|
@ -83,10 +83,12 @@
|
||||
</table>
|
||||
</div>
|
||||
{% include 'extras/inc/tags_panel.html' with tags=routetarget.tags.all url='ipam:routetarget_list' %}
|
||||
{% include 'inc/custom_fields_panel.html' with obj=routetarget %}
|
||||
{% plugin_left_page routetarget %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% include 'inc/custom_fields_panel.html' with obj=routetarget %}
|
||||
{% include 'panel_table.html' with table=importing_vrfs_table heading="Importing VRFs" %}
|
||||
{% include 'panel_table.html' with table=exporting_vrfs_table heading="Exporting VRFs" %}
|
||||
{% plugin_right_page routetarget %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -99,10 +99,12 @@
|
||||
</table>
|
||||
</div>
|
||||
{% include 'extras/inc/tags_panel.html' with tags=vrf.tags.all url='ipam:vrf_list' %}
|
||||
{% include 'inc/custom_fields_panel.html' with obj=vrf %}
|
||||
{% plugin_left_page vrf %}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{% include 'inc/custom_fields_panel.html' with obj=vrf %}
|
||||
{% include 'panel_table.html' with table=import_targets_table heading="Import Route Targets" %}
|
||||
{% include 'panel_table.html' with table=export_targets_table heading="Export Route Targets" %}
|
||||
{% plugin_right_page vrf %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,6 +11,13 @@
|
||||
{% render_field form.description %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Route Targets</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.import_targets %}
|
||||
{% render_field form.export_targets %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tenancy</strong></div>
|
||||
<div class="panel-body">
|
||||
|
Reference in New Issue
Block a user