From 9ca11c9ed4476fe7afd00169533b1cc4ad0c6d16 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 27 Feb 2018 14:59:45 -0500 Subject: [PATCH 1/7] Fixes #1915: Redirect to device view after deleting a component --- netbox/templates/dcim/inc/consoleport.html | 2 +- netbox/templates/dcim/inc/consoleserverport.html | 2 +- netbox/templates/dcim/inc/devicebay.html | 2 +- netbox/templates/dcim/inc/interface.html | 2 +- netbox/templates/dcim/inc/inventoryitem.html | 2 +- netbox/templates/dcim/inc/poweroutlet.html | 2 +- netbox/templates/dcim/inc/powerport.html | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/netbox/templates/dcim/inc/consoleport.html b/netbox/templates/dcim/inc/consoleport.html index 62375c7f2..4d75cc65b 100644 --- a/netbox/templates/dcim/inc/consoleport.html +++ b/netbox/templates/dcim/inc/consoleport.html @@ -44,7 +44,7 @@ {% else %} - + {% endif %} diff --git a/netbox/templates/dcim/inc/consoleserverport.html b/netbox/templates/dcim/inc/consoleserverport.html index aed27d62a..673f51388 100644 --- a/netbox/templates/dcim/inc/consoleserverport.html +++ b/netbox/templates/dcim/inc/consoleserverport.html @@ -49,7 +49,7 @@ {% else %} - + {% endif %} diff --git a/netbox/templates/dcim/inc/devicebay.html b/netbox/templates/dcim/inc/devicebay.html index e6e4d3e47..4e17e3d36 100644 --- a/netbox/templates/dcim/inc/devicebay.html +++ b/netbox/templates/dcim/inc/devicebay.html @@ -40,7 +40,7 @@ {% else %} - + {% endif %} diff --git a/netbox/templates/dcim/inc/interface.html b/netbox/templates/dcim/inc/interface.html index 783a56460..aa0a9cbd5 100644 --- a/netbox/templates/dcim/inc/interface.html +++ b/netbox/templates/dcim/inc/interface.html @@ -124,7 +124,7 @@ {% else %} - + {% endif %} diff --git a/netbox/templates/dcim/inc/inventoryitem.html b/netbox/templates/dcim/inc/inventoryitem.html index b50765271..21de1014e 100644 --- a/netbox/templates/dcim/inc/inventoryitem.html +++ b/netbox/templates/dcim/inc/inventoryitem.html @@ -11,7 +11,7 @@ {% endif %} {% if perms.dcim.delete_inventoryitem %} - + {% endif %} diff --git a/netbox/templates/dcim/inc/poweroutlet.html b/netbox/templates/dcim/inc/poweroutlet.html index 306977207..f3c855ea7 100644 --- a/netbox/templates/dcim/inc/poweroutlet.html +++ b/netbox/templates/dcim/inc/poweroutlet.html @@ -49,7 +49,7 @@ {% else %} - + {% endif %} diff --git a/netbox/templates/dcim/inc/powerport.html b/netbox/templates/dcim/inc/powerport.html index 555d6d3ee..32e7f20fd 100644 --- a/netbox/templates/dcim/inc/powerport.html +++ b/netbox/templates/dcim/inc/powerport.html @@ -44,7 +44,7 @@ {% else %} - + {% endif %} From 9130202a421237df3303c175b752596774b9e31f Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 27 Feb 2018 15:40:24 -0500 Subject: [PATCH 2/7] Fixes #1919: Prevent exception when attempting to create a virtual machine without selecting devices --- netbox/dcim/views.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 02c87c122..8a8fb8d4c 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -7,7 +7,7 @@ from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.paginator import EmptyPage, PageNotAnInteger from django.db import transaction from django.db.models import Count, Q -from django.forms import ModelChoiceField, ModelForm, modelformset_factory +from django.forms import modelformset_factory from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse @@ -2082,14 +2082,13 @@ class VirtualChassisCreateView(PermissionRequiredMixin, View): # Get the list of devices being added to a VirtualChassis pk_form = forms.DeviceSelectionForm(request.POST) pk_form.full_clean() + if not pk_form.cleaned_data.get('pk'): + messages.warning(request, "No devices were selected.") + return redirect('dcim:device_list') device_queryset = Device.objects.filter( pk__in=pk_form.cleaned_data.get('pk') ).select_related('rack').order_by('vc_position') - if not device_queryset: - messages.warning(request, "No devices were selected.") - return redirect('dcim:device_list') - VCMemberFormSet = modelformset_factory( model=Device, formset=forms.BaseVCMemberFormSet, From 54a2b3bc136c007119ecea1ccd415918fac62b46 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 27 Feb 2018 15:54:25 -0500 Subject: [PATCH 3/7] Closes #1918: Add note about copying media directory to upgrade doc --- docs/installation/upgrading.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/installation/upgrading.md b/docs/installation/upgrading.md index 02dbb878f..02a08716b 100644 --- a/docs/installation/upgrading.md +++ b/docs/installation/upgrading.md @@ -21,6 +21,12 @@ Copy the 'configuration.py' you created when first installing to the new version # cp /opt/netbox-X.Y.Z/netbox/netbox/configuration.py /opt/netbox/netbox/netbox/configuration.py ``` +Be sure to replicate your uploaded media as well. (The exact action necessary will depend on where you choose to store your media, but in general moving or copying the media directory will suffice.) + +```no-highlight +# cp -pr /opt/netbox-X.Y.Z/netbox/media/ /opt/netbox/netbox/ +``` + If you followed the original installation guide to set up gunicorn, be sure to copy its configuration as well: ```no-highlight From aa17be3c2d13853a8b080f6069ed704cdf2f1708 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 27 Feb 2018 16:10:02 -0500 Subject: [PATCH 4/7] Fixes #1924: Include VID in VLAN lists when editing an interface --- netbox/dcim/forms.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index 6d0892f67..d74d6fcd9 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -1679,6 +1679,7 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm, ChainedFieldsMixin): label='Untagged VLAN', widget=APISelect( api_url='/api/ipam/vlans/?site_id={{site}}&group_id={{vlan_group}}', + display_field='display_name' ) ) tagged_vlans = ChainedModelMultipleChoiceField( @@ -1691,6 +1692,7 @@ class InterfaceForm(BootstrapMixin, forms.ModelForm, ChainedFieldsMixin): label='Tagged VLANs', widget=APISelectMultiple( api_url='/api/ipam/vlans/?site_id={{site}}&group_id={{vlan_group}}', + display_field='display_name' ) ) From 7d2aa5ab7bfc3a42153455249fa1e7dff78be1fb Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 27 Feb 2018 17:56:18 -0500 Subject: [PATCH 5/7] Post-release version bump (a bit late) --- netbox/netbox/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 37a3585ec..63f3a492d 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -22,7 +22,7 @@ if sys.version_info[0] < 3: DeprecationWarning ) -VERSION = '2.3.0' +VERSION = '2.3.1-dev' BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) From fa86bf3893d6ca51a46c749d2c794120fbd9c8ef Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 1 Mar 2018 09:49:17 -0500 Subject: [PATCH 6/7] Fixes #1927: Include all VC member interaces on A side when creating a new interface connection --- netbox/dcim/forms.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index d74d6fcd9..0c8ea3716 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -2069,7 +2069,7 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor super(InterfaceConnectionForm, self).__init__(*args, **kwargs) # Initialize interface A choices - device_a_interfaces = Interface.objects.connectable().order_naturally().filter(device=device_a).select_related( + device_a_interfaces = device_a.vc_interfaces.connectable().order_naturally().select_related( 'circuit_termination', 'connected_as_a', 'connected_as_b' ) self.fields['interface_a'].choices = [ @@ -2078,9 +2078,11 @@ class InterfaceConnectionForm(BootstrapMixin, ChainedFieldsMixin, forms.ModelFor # Mark connected interfaces as disabled if self.data.get('device_b'): - self.fields['interface_b'].choices = [ - (iface.id, {'label': iface.name, 'disabled': iface.is_connected}) for iface in self.fields['interface_b'].queryset - ] + self.fields['interface_b'].choices = [] + for iface in self.fields['interface_b'].queryset: + self.fields['interface_b'].choices.append( + (iface.id, {'label': iface.name, 'disabled': iface.is_connected}) + ) class InterfaceConnectionCSVForm(forms.ModelForm): From ca9479b76d998c7903841213b8b37e43b32059da Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 1 Mar 2018 11:16:28 -0500 Subject: [PATCH 7/7] Fixes #1921: Ignore ManyToManyFields when validating a new object created via the API --- netbox/utilities/api.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/netbox/utilities/api.py b/netbox/utilities/api.py index 9dccdcc9d..8471d0e00 100644 --- a/netbox/utilities/api.py +++ b/netbox/utilities/api.py @@ -5,6 +5,7 @@ import pytz from django.conf import settings from django.contrib.contenttypes.models import ContentType +from django.db.models import ManyToManyField from django.http import Http404 from rest_framework import mixins from rest_framework.exceptions import APIException @@ -51,6 +52,11 @@ class ValidatedModelSerializer(ModelSerializer): # Run clean() on an instance of the model if self.instance is None: + model = self.Meta.model + # Ignore ManyToManyFields for new instances (a PK is needed for validation) + for field in model._meta.get_fields(): + if isinstance(field, ManyToManyField): + attrs.pop(field.name) instance = self.Meta.model(**attrs) else: instance = self.instance