From ba85101d30cde82a5e108f3c47ff2b7a28913694 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Mon, 27 Dec 2021 21:25:47 -0500 Subject: [PATCH] Update component model forms to use DynamicModelChoiceField query_params for related objects --- netbox/dcim/forms/models.py | 112 ++++++++++++-------------- netbox/dcim/views.py | 53 ++++++------ netbox/virtualization/forms/models.py | 24 +++--- 3 files changed, 87 insertions(+), 102 deletions(-) diff --git a/netbox/dcim/forms/models.py b/netbox/dcim/forms/models.py index b193f76d5..f5988030c 100644 --- a/netbox/dcim/forms/models.py +++ b/netbox/dcim/forms/models.py @@ -957,6 +957,7 @@ class ConsolePortTemplateForm(BootstrapMixin, forms.ModelForm): widgets = { 'device_type': forms.HiddenInput(), 'module_type': forms.HiddenInput(), + 'type': StaticSelect, } @@ -969,6 +970,7 @@ class ConsoleServerPortTemplateForm(BootstrapMixin, forms.ModelForm): widgets = { 'device_type': forms.HiddenInput(), 'module_type': forms.HiddenInput(), + 'type': StaticSelect, } @@ -981,10 +983,19 @@ class PowerPortTemplateForm(BootstrapMixin, forms.ModelForm): widgets = { 'device_type': forms.HiddenInput(), 'module_type': forms.HiddenInput(), + 'type': StaticSelect(), } class PowerOutletTemplateForm(BootstrapMixin, forms.ModelForm): + power_port = DynamicModelChoiceField( + queryset=PowerPortTemplate.objects.all(), + required=False, + query_params={ + 'devicetype_id': '$device_type', + } + ) + class Meta: model = PowerOutletTemplate fields = [ @@ -993,18 +1004,10 @@ class PowerOutletTemplateForm(BootstrapMixin, forms.ModelForm): widgets = { 'device_type': forms.HiddenInput(), 'module_type': forms.HiddenInput(), + 'type': StaticSelect(), + 'feed_leg': StaticSelect(), } - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Limit power_port choices to current DeviceType/ModuleType - if self.instance.pk: - self.fields['power_port'].queryset = PowerPortTemplate.objects.filter( - device_type=self.instance.device_type, - module_type=self.instance.module_type - ) - class InterfaceTemplateForm(BootstrapMixin, forms.ModelForm): class Meta: @@ -1020,6 +1023,14 @@ class InterfaceTemplateForm(BootstrapMixin, forms.ModelForm): class FrontPortTemplateForm(BootstrapMixin, forms.ModelForm): + rear_port = DynamicModelChoiceField( + queryset=RearPortTemplate.objects.all(), + required=False, + query_params={ + 'devicetype_id': '$device_type', + } + ) + class Meta: model = FrontPortTemplate fields = [ @@ -1029,19 +1040,9 @@ class FrontPortTemplateForm(BootstrapMixin, forms.ModelForm): widgets = { 'device_type': forms.HiddenInput(), 'module_type': forms.HiddenInput(), - 'rear_port': StaticSelect(), + 'type': StaticSelect(), } - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Limit rear_port choices to current DeviceType/ModuleType - if self.instance.pk: - self.fields['rear_port'].queryset = RearPortTemplate.objects.filter( - device_type=self.instance.device_type, - module_type=self.instance.module_type - ) - class RearPortTemplateForm(BootstrapMixin, forms.ModelForm): class Meta: @@ -1095,6 +1096,7 @@ class ConsolePortForm(CustomFieldModelForm): ] widgets = { 'device': forms.HiddenInput(), + 'type': StaticSelect(), } @@ -1111,6 +1113,7 @@ class ConsoleServerPortForm(CustomFieldModelForm): ] widgets = { 'device': forms.HiddenInput(), + 'type': StaticSelect(), } @@ -1128,13 +1131,17 @@ class PowerPortForm(CustomFieldModelForm): ] widgets = { 'device': forms.HiddenInput(), + 'type': StaticSelect(), } class PowerOutletForm(CustomFieldModelForm): - power_port = forms.ModelChoiceField( + power_port = DynamicModelChoiceField( queryset=PowerPort.objects.all(), - required=False + required=False, + query_params={ + 'device_id': '$device', + } ) tags = DynamicModelMultipleChoiceField( queryset=Tag.objects.all(), @@ -1148,34 +1155,34 @@ class PowerOutletForm(CustomFieldModelForm): ] widgets = { 'device': forms.HiddenInput(), + 'type': StaticSelect(), + 'feed_leg': StaticSelect(), } - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Limit power_port choices to the local device - if hasattr(self.instance, 'device'): - self.fields['power_port'].queryset = PowerPort.objects.filter( - device=self.instance.device - ) - class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm): parent = DynamicModelChoiceField( queryset=Interface.objects.all(), required=False, - label='Parent interface' + label='Parent interface', + query_params={ + 'device_id': '$device', + } ) bridge = DynamicModelChoiceField( queryset=Interface.objects.all(), required=False, - label='Bridged interface' + label='Bridged interface', + query_params={ + 'device_id': '$device', + } ) lag = DynamicModelChoiceField( queryset=Interface.objects.all(), required=False, label='LAG interface', query_params={ + 'device_id': '$device', 'type': 'lag', } ) @@ -1203,6 +1210,7 @@ class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm): label='Untagged VLAN', query_params={ 'group_id': '$vlan_group', + 'available_on_device': '$device', } ) tagged_vlans = DynamicModelMultipleChoiceField( @@ -1211,6 +1219,7 @@ class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm): label='Tagged VLANs', query_params={ 'group_id': '$vlan_group', + 'available_on_device': '$device', } ) tags = DynamicModelMultipleChoiceField( @@ -1241,26 +1250,15 @@ class InterfaceForm(InterfaceCommonForm, CustomFieldModelForm): 'rf_channel_width': "Populated by selected channel (if set)", } - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - device = Device.objects.get(pk=self.data['device']) if self.is_bound else self.instance.device - - # Restrict parent/bridge/LAG interface assignment by device/VC - self.fields['parent'].widget.add_query_param('device_id', device.pk) - self.fields['bridge'].widget.add_query_param('device_id', device.pk) - self.fields['lag'].widget.add_query_param('device_id', device.pk) - if device.virtual_chassis and device.virtual_chassis.master: - self.fields['parent'].widget.add_query_param('device_id', device.virtual_chassis.master.pk) - self.fields['bridge'].widget.add_query_param('device_id', device.virtual_chassis.master.pk) - self.fields['lag'].widget.add_query_param('device_id', device.virtual_chassis.master.pk) - - # Limit VLAN choices by device - self.fields['untagged_vlan'].widget.add_query_param('available_on_device', device.pk) - self.fields['tagged_vlans'].widget.add_query_param('available_on_device', device.pk) - class FrontPortForm(CustomFieldModelForm): + rear_port = DynamicModelChoiceField( + queryset=RearPort.objects.all(), + required=False, + query_params={ + 'device_id': '$device', + } + ) tags = DynamicModelMultipleChoiceField( queryset=Tag.objects.all(), required=False @@ -1275,18 +1273,8 @@ class FrontPortForm(CustomFieldModelForm): widgets = { 'device': forms.HiddenInput(), 'type': StaticSelect(), - 'rear_port': StaticSelect(), } - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - - # Limit RearPort choices to the local device - if hasattr(self.instance, 'device'): - self.fields['rear_port'].queryset = self.fields['rear_port'].queryset.filter( - device=self.instance.device - ) - class RearPortForm(CustomFieldModelForm): tags = DynamicModelMultipleChoiceField( diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 1616b95e9..05416b720 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -2000,33 +2000,34 @@ class InterfaceView(generic.ObjectView): class InterfaceCreateView(generic.ComponentCreateView): queryset = Interface.objects.all() model_form = forms.InterfaceForm - template_name = 'dcim/interface_create.html' + # template_name = 'dcim/interface_create.html' - def post(self, request): - """ - Override inherited post() method to handle request to assign newly created - interface objects (first object) to an IP Address object. - """ - form = self.form(request.POST, initial=request.GET) - new_objs = self.validate_form(request, form) - - if form.is_valid() and not form.errors: - if '_addanother' in request.POST: - return redirect(request.get_full_path()) - elif new_objs is not None and '_assignip' in request.POST and len(new_objs) >= 1 and \ - request.user.has_perm('ipam.add_ipaddress'): - first_obj = new_objs[0].pk - return redirect( - f'/ipam/ip-addresses/add/?interface={first_obj}&return_url={self.get_return_url(request)}' - ) - else: - return redirect(self.get_return_url(request)) - - return render(request, self.template_name, { - 'obj_type': self.queryset.model._meta.verbose_name, - 'form': form, - 'return_url': self.get_return_url(request), - }) + # TODO: Figure out what to do with this + # def post(self, request): + # """ + # Override inherited post() method to handle request to assign newly created + # interface objects (first object) to an IP Address object. + # """ + # form = self.form(request.POST, initial=request.GET) + # new_objs = self.validate_form(request, form) + # + # if form.is_valid() and not form.errors: + # if '_addanother' in request.POST: + # return redirect(request.get_full_path()) + # elif new_objs is not None and '_assignip' in request.POST and len(new_objs) >= 1 and \ + # request.user.has_perm('ipam.add_ipaddress'): + # first_obj = new_objs[0].pk + # return redirect( + # f'/ipam/ip-addresses/add/?interface={first_obj}&return_url={self.get_return_url(request)}' + # ) + # else: + # return redirect(self.get_return_url(request)) + # + # return render(request, self.template_name, { + # 'obj_type': self.queryset.model._meta.verbose_name, + # 'form': form, + # 'return_url': self.get_return_url(request), + # }) class InterfaceEditView(generic.ObjectEditView): diff --git a/netbox/virtualization/forms/models.py b/netbox/virtualization/forms/models.py index 6fa90ea65..624c9e87f 100644 --- a/netbox/virtualization/forms/models.py +++ b/netbox/virtualization/forms/models.py @@ -275,12 +275,18 @@ class VMInterfaceForm(InterfaceCommonForm, CustomFieldModelForm): parent = DynamicModelChoiceField( queryset=VMInterface.objects.all(), required=False, - label='Parent interface' + label='Parent interface', + query_params={ + 'virtual_machine_id': '$virtual_machine', + } ) bridge = DynamicModelChoiceField( queryset=VMInterface.objects.all(), required=False, - label='Bridged interface' + label='Bridged interface', + query_params={ + 'virtual_machine_id': '$virtual_machine', + } ) vlan_group = DynamicModelChoiceField( queryset=VLANGroup.objects.all(), @@ -293,6 +299,7 @@ class VMInterfaceForm(InterfaceCommonForm, CustomFieldModelForm): label='Untagged VLAN', query_params={ 'group_id': '$vlan_group', + 'available_on_virtualmachine': '$virtual_machine', } ) tagged_vlans = DynamicModelMultipleChoiceField( @@ -301,6 +308,7 @@ class VMInterfaceForm(InterfaceCommonForm, CustomFieldModelForm): label='Tagged VLANs', query_params={ 'group_id': '$vlan_group', + 'available_on_virtualmachine': '$virtual_machine', } ) tags = DynamicModelMultipleChoiceField( @@ -324,15 +332,3 @@ class VMInterfaceForm(InterfaceCommonForm, CustomFieldModelForm): help_texts = { 'mode': INTERFACE_MODE_HELP_TEXT, } - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - vm_id = self.initial.get('virtual_machine') or self.data.get('virtual_machine') - - # Restrict parent interface assignment by VM - self.fields['parent'].widget.add_query_param('virtual_machine_id', vm_id) - self.fields['bridge'].widget.add_query_param('virtual_machine_id', vm_id) - - # Limit VLAN choices by virtual machine - self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id) - self.fields['tagged_vlans'].widget.add_query_param('available_on_virtualmachine', vm_id)