Repository: netbox-community/netbox

Issue:
Allow filtering by Parent device in Interfaces view
### Environment
* Python version:  3.6.9
* NetBox version:  2.7.4

### Proposed Functionality
Allow interfaces to be filtered also by Parent device. Field should allow to select multiple devices.

### Use Case
We're using tags to mark free/reserved/special interfaces to be able later select them and count/review. Now Netbox displaying all interfaces from all devices that matching criteria such as Name/Region/Site/Tags. Ability to filter by Parent device will help alot to find interfaces with selected tags on one/multiple devices.


Discussion:
Fairly simple. This is somewhat similar to #3122. If there are no objections, I'd like to work on this (I've missed adding `filter_for` on the `site` field for `device_id`, so I'd improve that in the process).

Edit: or just `git apply` this:
```diff
diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py
index 34f18f6d..e9169523 100644
--- a/netbox/dcim/forms.py
+++ b/netbox/dcim/forms.py
@@ -84,7 +84,18 @@ class DeviceComponentFilterForm(BootstrapMixin, forms.Form):
         to_field_name='slug',
         widget=APISelectMultiple(
             api_url="/api/dcim/sites/",
-            value_field="slug"
+            value_field="slug",
+            filter_for={
+                'device_id': 'site',
+            }
+        )
+    )
+    device_id = FilterChoiceField(
+        queryset=Device.objects.all(),
+        required=False,
+        label='Device',
+        widget=APISelectMultiple(
+            api_url='/api/dcim/devices/',
         )
     )
 
@@ -3642,6 +3653,7 @@ class CableFilterForm(BootstrapMixin, forms.Form):
             value_field="slug",
             filter_for={
                 'rack_id': 'site',
+                'device_id': 'site',
             }
         )
     )
@@ -3663,6 +3675,9 @@ class CableFilterForm(BootstrapMixin, forms.Form):
         widget=APISelectMultiple(
             api_url="/api/dcim/racks/",
             null_option=True,
+            filter_for={
+                'device_id': 'rack_id',
+            }
         )
     )
     type = forms.MultipleChoiceField(
@@ -3816,6 +3831,9 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
         widget=APISelectMultiple(
             api_url="/api/dcim/sites/",
             value_field="slug",
+            filter_for={
+                'device_id': 'site',
+            }
         )
     )
     device_id = FilterChoiceField(
@@ -3835,6 +3853,9 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
         widget=APISelectMultiple(
             api_url="/api/dcim/sites/",
             value_field="slug",
+            filter_for={
+                'device_id': 'site',
+            }
         )
     )
     device_id = FilterChoiceField(
@@ -3854,6 +3875,9 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
         widget=APISelectMultiple(
             api_url="/api/dcim/sites/",
             value_field="slug",
+            filter_for={
+                'device_id': 'site',
+            }
         )
     )
     device_id = FilterChoiceField(
```

In addition, it might be worth creating `ConnectionFilterForm` from which `CableFilterForm` and `*ConnectionFilterForm` inherit for the sake of consistency (similar thing would need to be done in the filterset), but this may be out of scope of this issue.
> Fairly simple. This is somewhat similar to #3122. If there are no objections, I'd like to work on this

Done

> I've missed adding `filter_for` on the `site` field for `device_id`, so I'd improve that in the process

Not sure @jeremystretch view on this, but I would probably want this as a separate Issue/PR

Resolving patch:
diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py
--- a/netbox/dcim/forms.py
+++ b/netbox/dcim/forms.py
@@ -84,7 +84,18 @@ class DeviceComponentFilterForm(BootstrapMixin, forms.Form):
         to_field_name='slug',
         widget=APISelectMultiple(
             api_url="/api/dcim/sites/",
-            value_field="slug"
+            value_field="slug",
+            filter_for={
+                'device_id': 'site',
+            }
+        )
+    )
+    device_id = FilterChoiceField(
+        queryset=Device.objects.all(),
+        required=False,
+        label='Device',
+        widget=APISelectMultiple(
+            api_url='/api/dcim/devices/',
         )
     )
 
@@ -3642,6 +3653,7 @@ class CableFilterForm(BootstrapMixin, forms.Form):
             value_field="slug",
             filter_for={
                 'rack_id': 'site',
+                'device_id': 'site',
             }
         )
     )
@@ -3663,6 +3675,9 @@ class CableFilterForm(BootstrapMixin, forms.Form):
         widget=APISelectMultiple(
             api_url="/api/dcim/racks/",
             null_option=True,
+            filter_for={
+                'device_id': 'rack_id',
+            }
         )
     )
     type = forms.MultipleChoiceField(
@@ -3816,6 +3831,9 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
         widget=APISelectMultiple(
             api_url="/api/dcim/sites/",
             value_field="slug",
+            filter_for={
+                'device_id': 'site',
+            }
         )
     )
     device_id = FilterChoiceField(
@@ -3835,6 +3853,9 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
         widget=APISelectMultiple(
             api_url="/api/dcim/sites/",
             value_field="slug",
+            filter_for={
+                'device_id': 'site',
+            }
         )
     )
     device_id = FilterChoiceField(
@@ -3854,6 +3875,9 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
         widget=APISelectMultiple(
             api_url="/api/dcim/sites/",
             value_field="slug",
+            filter_for={
+                'device_id': 'site',
+            }
         )
     )
     device_id = FilterChoiceField(


Test patch: