netbox-community/netbox#6905: Add prefix-vlan assignment view

This commit is contained in:
Rhys Barrie 2021-11-18 14:50:31 -05:00
parent e8d6281007
commit 8b510b3b5e
7 changed files with 158 additions and 0 deletions

View File

@ -20,6 +20,7 @@ __all__ = (
'IPAddressForm', 'IPAddressForm',
'IPRangeForm', 'IPRangeForm',
'PrefixForm', 'PrefixForm',
'PrefixAssignForm',
'RIRForm', 'RIRForm',
'RoleForm', 'RoleForm',
'RouteTargetForm', 'RouteTargetForm',
@ -203,6 +204,23 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
} }
class PrefixAssignForm(BootstrapMixin, forms.Form):
site_id = DynamicModelChoiceField(
queryset=Site.objects.all(),
required=False,
label='Site'
)
vrf_id = DynamicModelChoiceField(
queryset=VRF.objects.all(),
required=False,
label='VRF'
)
q = forms.CharField(
required=False,
label='Search',
)
class IPRangeForm(BootstrapMixin, TenancyForm, CustomFieldModelForm): class IPRangeForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),

View File

@ -16,6 +16,7 @@ __all__ = (
'IPAddressTable', 'IPAddressTable',
'IPRangeTable', 'IPRangeTable',
'PrefixTable', 'PrefixTable',
'PrefixAssignTable',
'RIRTable', 'RIRTable',
'RoleTable', 'RoleTable',
) )
@ -43,6 +44,10 @@ PREFIXFLAT_LINK = """
{% endif %} {% endif %}
""" """
PREFIX_ASSIGN_LINK = """
<a href="{% url 'ipam:prefix_edit' pk=record.pk %}?{% if request.GET.vlan %}vlan={{ request.GET.vlan }}{% endif %}&return_url={{ request.GET.return_url }}">{{ record }}</a>
"""
IPADDRESS_LINK = """ IPADDRESS_LINK = """
{% if record.pk %} {% if record.pk %}
<a href="{{ record.get_absolute_url }}">{{ record.address }}</a> <a href="{{ record.get_absolute_url }}">{{ record.address }}</a>
@ -246,6 +251,23 @@ class PrefixTable(BaseTable):
} }
class PrefixAssignTable(BaseTable):
prefix = tables.TemplateColumn(
template_code=PREFIX_ASSIGN_LINK,
verbose_name='Prefix'
)
status = ChoiceFieldColumn()
is_pool = BooleanColumn(
verbose_name='Pool'
)
class Meta(BaseTable.Meta):
model = Prefix
fields = ('prefix', 'site', 'vrf', 'tenant', 'status', 'role', 'vlan', 'is_pool', 'description')
exclude = ('id', )
orderable = False
# #
# IP ranges # IP ranges
# #

View File

@ -71,6 +71,7 @@ urlpatterns = [
path('prefixes/import/', views.PrefixBulkImportView.as_view(), name='prefix_import'), path('prefixes/import/', views.PrefixBulkImportView.as_view(), name='prefix_import'),
path('prefixes/edit/', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'), path('prefixes/edit/', views.PrefixBulkEditView.as_view(), name='prefix_bulk_edit'),
path('prefixes/delete/', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'), path('prefixes/delete/', views.PrefixBulkDeleteView.as_view(), name='prefix_bulk_delete'),
path('prefixes/assign/', views.PrefixAssignView.as_view(), name='prefix_assign'),
path('prefixes/<int:pk>/', views.PrefixView.as_view(), name='prefix'), path('prefixes/<int:pk>/', views.PrefixView.as_view(), name='prefix'),
path('prefixes/<int:pk>/edit/', views.PrefixEditView.as_view(), name='prefix_edit'), path('prefixes/<int:pk>/edit/', views.PrefixEditView.as_view(), name='prefix_edit'),
path('prefixes/<int:pk>/delete/', views.PrefixDeleteView.as_view(), name='prefix_delete'), path('prefixes/<int:pk>/delete/', views.PrefixDeleteView.as_view(), name='prefix_delete'),

View File

@ -494,6 +494,47 @@ class PrefixIPAddressesView(generic.ObjectView):
class PrefixEditView(generic.ObjectEditView): class PrefixEditView(generic.ObjectEditView):
queryset = Prefix.objects.all() queryset = Prefix.objects.all()
model_form = forms.PrefixForm model_form = forms.PrefixForm
template_name = 'ipam/prefix_edit.html'
# TODO: Standardize or remove this view
class PrefixAssignView(generic.ObjectView):
"""
Search for Prefixes to assign to a VLAN
"""
queryset = Prefix.objects.all()
def dispatch(self, request, *args, **kwargs):
# Redirect the user if a VLAN has not been provided
if 'vlan' not in request.GET:
return redirect('ipam:prefix_add')
return super().dispatch(request, *args, **kwargs)
def get(self, request):
form = forms.PrefixAssignForm()
return render(request, 'ipam/prefix_assign.html', {
'form': form,
'return_url': request.GET.get('return_url', ''),
})
def post(self, request):
form = forms.PrefixAssignForm(request.POST)
table = None
if form.is_valid():
prefixes = self.queryset.prefetch_related('site', 'vrf', 'tenant')
# Limit to 100 results
prefixes = filtersets.PrefixFilterSet(request.POST, prefixes).qs[:100]
table = tables.PrefixAssignTable(prefixes)
return render(request, 'ipam/prefix_assign.html', {
'form': form,
'table': table,
'return_url': request.GET.get('return_url'),
})
class PrefixDeleteView(generic.ObjectDeleteView): class PrefixDeleteView(generic.ObjectDeleteView):

View File

@ -0,0 +1,22 @@
{% load helpers %}
<ul class="nav nav-tabs px-3">
<li class="nav-item">
<a
class="nav-link {% if active_tab == 'add' %}active{% endif %}"
href="{% url 'ipam:prefix_add' %}{% querystring request %}"
>
{% if obj.pk %}Edit{% else %}Create{% endif %}
</a>
</li>
{% if 'vlan' in request.GET %}
<li class="nav-item">
<a
class="nav-link {% if active_tab == 'assign' %}active{% endif %}"
href="{% url 'ipam:prefix_assign' %}{% querystring request %}"
>
Assign Prefix
</a>
</li>
{% endif %}
</ul>

View File

@ -0,0 +1,46 @@
{% extends 'generic/object_edit.html' %}
{% load static %}
{% load form_helpers %}
{% load helpers %}
{% block title %}Assign a Prefix{% endblock title %}
{% block tabs %}
{% include 'ipam/inc/prefix_edit_header.html' with active_tab='assign' %}
{% endblock %}
{% block form %}
<form action="{% querystring request %}" method="post" class="form form-horizontal">
{% csrf_token %}
{% for field in form.hidden_fields %}
{{ field }}
{% endfor %}
<div class="row mb-3">
<div class="col col-md-8 offset-md-2">
<div class="field-group">
<h6>Select Prefix</h6>
{% render_field form.site_id %}
{% render_field form.vrf_id %}
{% render_field form.q %}
</div>
</div>
</div>
<div class="row mb-3">
<div class="col col-md-8 offset-md-2 text-end">
<a href="{{ return_url }}" class="btn btn-outline-danger">Cancel</a>
<button type="submit" class="btn btn-primary">Search</button>
</div>
</div>
</form>
{% if table %}
<div class="row mb-3">
<div class="col col-md-12">
<h3>Search Results</h3>
{% include 'utilities/obj_table.html' %}
</div>
</div>
{% endif %}
{% endblock form %}
{% block buttons %}
{% endblock buttons%}

View File

@ -0,0 +1,8 @@
{% extends 'generic/object_edit.html' %}
{% load static %}
{% load form_helpers %}
{% load helpers %}
{% block tabs %}
{% include 'ipam/inc/prefix_edit_header.html' with active_tab='add' %}
{% endblock tabs %}