mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-27 02:48:38 -06:00
Support VLAN in Import Prefixes, Add VLAN column to Prefixes page
catch MultipleObjectsReturned Error & Cleanup Fix VLAN Filter on Prefixes page
This commit is contained in:
parent
5e9090a03a
commit
4ea70763e1
@ -192,13 +192,15 @@ class PrefixFromCSVForm(forms.ModelForm):
|
|||||||
error_messages={'invalid_choice': 'VRF not found.'})
|
error_messages={'invalid_choice': 'VRF not found.'})
|
||||||
site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False, to_field_name='name',
|
site = forms.ModelChoiceField(queryset=Site.objects.all(), required=False, to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Site not found.'})
|
error_messages={'invalid_choice': 'Site not found.'})
|
||||||
|
vlan = forms.ModelChoiceField(queryset=VLAN.objects.all(), required=False, to_field_name='name',
|
||||||
|
error_messages={'invalid_choice': 'VLAN not found.'})
|
||||||
status_name = forms.ChoiceField(choices=[(s[1], s[0]) for s in PREFIX_STATUS_CHOICES])
|
status_name = forms.ChoiceField(choices=[(s[1], s[0]) for s in PREFIX_STATUS_CHOICES])
|
||||||
role = forms.ModelChoiceField(queryset=Role.objects.all(), required=False, to_field_name='name',
|
role = forms.ModelChoiceField(queryset=Role.objects.all(), required=False, to_field_name='name',
|
||||||
error_messages={'invalid_choice': 'Invalid role.'})
|
error_messages={'invalid_choice': 'Invalid role.'})
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Prefix
|
model = Prefix
|
||||||
fields = ['prefix', 'vrf', 'site', 'status_name', 'role', 'description']
|
fields = ['prefix', 'vrf', 'site', 'vlan', 'status_name', 'role', 'description']
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
m = super(PrefixFromCSVForm, self).save(commit=False)
|
m = super(PrefixFromCSVForm, self).save(commit=False)
|
||||||
@ -238,6 +240,9 @@ def prefix_site_choices():
|
|||||||
site_choices = Site.objects.annotate(prefix_count=Count('prefixes'))
|
site_choices = Site.objects.annotate(prefix_count=Count('prefixes'))
|
||||||
return [(s.slug, '{} ({})'.format(s.name, s.prefix_count)) for s in site_choices]
|
return [(s.slug, '{} ({})'.format(s.name, s.prefix_count)) for s in site_choices]
|
||||||
|
|
||||||
|
def prefix_vlan_choices():
|
||||||
|
vlan_choices = VLAN.objects.annotate(prefix_count=Count('prefixes'))
|
||||||
|
return [(v.id, '{} ({})'.format(v.display_name, v.prefix_count)) for v in vlan_choices]
|
||||||
|
|
||||||
def prefix_status_choices():
|
def prefix_status_choices():
|
||||||
status_counts = {}
|
status_counts = {}
|
||||||
@ -256,9 +261,11 @@ class PrefixFilterForm(forms.Form, BootstrapMixin):
|
|||||||
vrf = forms.ChoiceField(required=False, choices=prefix_vrf_choices, label='VRF')
|
vrf = forms.ChoiceField(required=False, choices=prefix_vrf_choices, label='VRF')
|
||||||
status = forms.MultipleChoiceField(required=False, choices=prefix_status_choices)
|
status = forms.MultipleChoiceField(required=False, choices=prefix_status_choices)
|
||||||
site = forms.MultipleChoiceField(required=False, choices=prefix_site_choices,
|
site = forms.MultipleChoiceField(required=False, choices=prefix_site_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 6}))
|
||||||
|
vlan_id = forms.MultipleChoiceField(required=False, choices=prefix_vlan_choices, label='VLAN',
|
||||||
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
role = forms.MultipleChoiceField(required=False, choices=prefix_role_choices,
|
role = forms.MultipleChoiceField(required=False, choices=prefix_role_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 6}))
|
||||||
expand = forms.BooleanField(required=False, label='Expand prefix hierarchy')
|
expand = forms.BooleanField(required=False, label='Expand prefix hierarchy')
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,12 +127,13 @@ class PrefixTable(BaseTable):
|
|||||||
prefix = tables.TemplateColumn(PREFIX_LINK, verbose_name='Prefix')
|
prefix = tables.TemplateColumn(PREFIX_LINK, verbose_name='Prefix')
|
||||||
vrf = tables.Column(orderable=False, default='Global', verbose_name='VRF')
|
vrf = tables.Column(orderable=False, default='Global', verbose_name='VRF')
|
||||||
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
|
site = tables.LinkColumn('dcim:site', args=[Accessor('site.slug')], verbose_name='Site')
|
||||||
|
vlan = tables.Column(accessor='vlan.display_name', verbose_name='VLAN')
|
||||||
role = tables.Column(verbose_name='Role')
|
role = tables.Column(verbose_name='Role')
|
||||||
description = tables.Column(orderable=False, verbose_name='Description')
|
description = tables.Column(orderable=False, verbose_name='Description')
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
model = Prefix
|
model = Prefix
|
||||||
fields = ('pk', 'prefix', 'status', 'vrf', 'site', 'role', 'description')
|
fields = ('pk', 'prefix', 'status', 'vrf', 'site', 'vlan', 'role', 'description')
|
||||||
|
|
||||||
|
|
||||||
class PrefixBriefTable(BaseTable):
|
class PrefixBriefTable(BaseTable):
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<td><a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a></td>
|
<td><a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a></td>
|
||||||
<td>{{ prefix.vrf|default:"Global" }}</td>
|
<td>{{ prefix.vrf|default:"Global" }}</td>
|
||||||
<td>{{ prefix.site }}</td>
|
<td>{{ prefix.site }}</td>
|
||||||
|
<td>{{ prefix.vlan }}</td>
|
||||||
<td>{{ prefix.status }}</td>
|
<td>{{ prefix.status }}</td>
|
||||||
<td>{{ prefix.role }}</td>
|
<td>{{ prefix.role }}</td>
|
||||||
<td>{{ prefix.description }}</td>
|
<td>{{ prefix.description }}</td>
|
||||||
|
@ -43,6 +43,11 @@
|
|||||||
<td>Name of assigned site (optional)</td>
|
<td>Name of assigned site (optional)</td>
|
||||||
<td>HQ</td>
|
<td>HQ</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>VLAN</td>
|
||||||
|
<td>VLAN Name (optional)</td>
|
||||||
|
<td>Security</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Status</td>
|
<td>Status</td>
|
||||||
<td>Current status</td>
|
<td>Current status</td>
|
||||||
@ -61,7 +66,7 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<h4>Example</h4>
|
<h4>Example</h4>
|
||||||
<pre>192.168.42.0/24,65000:123,HQ,Active,Customer,7th floor WiFi</pre>
|
<pre>192.168.42.0/24,65000:123,HQ,Security,Active,Customer,7th floor WiFi</pre>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -5,7 +5,7 @@ from django.core.urlresolvers import reverse_lazy
|
|||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils.html import format_html
|
from django.utils.html import format_html
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
|
|
||||||
EXPANSION_PATTERN = '\[(\d+-\d+)\]'
|
EXPANSION_PATTERN = '\[(\d+-\d+)\]'
|
||||||
|
|
||||||
@ -244,18 +244,20 @@ class BulkImportForm(forms.Form):
|
|||||||
return
|
return
|
||||||
|
|
||||||
obj_list = []
|
obj_list = []
|
||||||
|
|
||||||
for i, record in enumerate(records, start=1):
|
for i, record in enumerate(records, start=1):
|
||||||
obj_form = self.fields['csv'].csv_form(data=record)
|
obj_form = self.fields['csv'].csv_form(data=record)
|
||||||
if obj_form.is_valid():
|
try:
|
||||||
obj = obj_form.save(commit=False)
|
if obj_form.is_valid():
|
||||||
obj_list.append(obj)
|
obj = obj_form.save(commit=False)
|
||||||
else:
|
obj_list.append(obj)
|
||||||
for field, errors in obj_form.errors.items():
|
else:
|
||||||
for e in errors:
|
for field, errors in obj_form.errors.items():
|
||||||
if field == '__all__':
|
for e in errors:
|
||||||
self.add_error('csv', "Record {}: {}".format(i, e))
|
if field == '__all__':
|
||||||
else:
|
self.add_error('csv', "Record {}: {}".format(i, e))
|
||||||
self.add_error('csv', "Record {} ({}): {}".format(i, field, e))
|
else:
|
||||||
|
self.add_error('csv', "Record {} ({}): {}".format(i, field, e))
|
||||||
|
except MultipleObjectsReturned as e:
|
||||||
|
self.add_error('csv', '%s' % (e.message))
|
||||||
|
|
||||||
self.cleaned_data['csv'] = obj_list
|
self.cleaned_data['csv'] = obj_list
|
||||||
|
Loading…
Reference in New Issue
Block a user