Expose API_SELECT widget to custom scripts. #3068

Closed
opened 2025-12-29 18:25:18 +01:00 by adam · 7 comments
Owner

Originally created by @pszulczewski on GitHub (Dec 14, 2019).

Originally assigned to: @DanSheps on GitHub.

Environment

  • Python version: 3.6.8
  • NetBox version: 2.6.6

Proposed Functionality

Add more advanced ObjectVar filtering mechanism in Custom Scripts.
Custom script to use widgets like API_SELECT to relate second ObjectVar on already selected first ObjectVar.

Use Case

Use Case 1
Two ObjectVars
1st Device
2nd Interfaces
Second ObjectVar is limited to interfaces only for selected device in first ObjectVar

Use Case 2
Two ObjectVars
1st Site
2nd Device
Second ObjectVar is limited to Devices only for selected site in first ObjectVar

Database Changes

None

External Dependencies

None

Originally created by @pszulczewski on GitHub (Dec 14, 2019). Originally assigned to: @DanSheps on GitHub. ### Environment * Python version: 3.6.8 * NetBox version: 2.6.6 ### Proposed Functionality Add more advanced ObjectVar filtering mechanism in Custom Scripts. Custom script to use widgets like API_SELECT to relate second ObjectVar on already selected first ObjectVar. ### Use Case Use Case 1 Two ObjectVars 1st Device 2nd Interfaces Second ObjectVar is limited to interfaces only for selected device in first ObjectVar Use Case 2 Two ObjectVars 1st Site 2nd Device Second ObjectVar is limited to Devices only for selected site in first ObjectVar ### Database Changes None ### External Dependencies None
adam added the status: acceptedtype: feature labels 2025-12-29 18:25:18 +01:00
adam closed this issue 2025-12-29 18:25:19 +01:00
Author
Owner

@stale[bot] commented on GitHub (Dec 28, 2019):

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. Please see our contributing guide.

@stale[bot] commented on GitHub (Dec 28, 2019): This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. NetBox is governed by a small group of core maintainers which means not all opened issues may receive direct feedback. Please see our [contributing guide](https://github.com/netbox-community/netbox/blob/develop/CONTRIBUTING.md).
Author
Owner

@lampwins commented on GitHub (Dec 30, 2019):

We need to do this but I am not sure our current widget API will work very well. We likely need to investigate modifying it or creating a new one for use with custom scripts.

@lampwins commented on GitHub (Dec 30, 2019): We need to do this but I am not sure our current widget API will work very well. We likely need to investigate modifying it or creating a new one for use with custom scripts.
Author
Owner

@DanSheps commented on GitHub (Jan 2, 2020):

I have managed to expose the widget API for my own custom scripts, I will have to see what changes I made. I believe I simply had it inherit something additional.

@DanSheps commented on GitHub (Jan 2, 2020): I have managed to expose the widget API for my own custom scripts, I will have to see what changes I made. I believe I simply had it inherit something additional.
Author
Owner

@DanSheps commented on GitHub (Jan 2, 2020):

Yeah, it looks like I just created separate classes within the individual scripts:


class WidgetIntegerVar(IntegerVar):
    def __init__(self, widget, required=False, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.field_attrs['widget'] = widget
        self.field_attrs['required'] = required

    def as_field(self):
        """
        Render the variable as a Django form field.
        """
        form_field = self.form_field(**self.field_attrs)
        form_field.widget.attrs['class'] += ' form-control'

        return form_field


class WidgetObjectVar(ObjectVar):
    def __init__(self, queryset, widget, *args, **kwargs):
        super().__init__(queryset, *args, **kwargs)
        self.field_attrs['widget'] = widget

    def as_field(self):
        """
        Render the variable as a Django form field.
        """
        form_field = self.form_field(**self.field_attrs)
        form_field.widget.attrs['class'] += ' form-control'

        return form_field

I think this would be cleaner if it were incorporated into the main classes, as overriding certain things would not be required.

@DanSheps commented on GitHub (Jan 2, 2020): Yeah, it looks like I just created separate classes within the individual scripts: ``` class WidgetIntegerVar(IntegerVar): def __init__(self, widget, required=False, *args, **kwargs): super().__init__(*args, **kwargs) self.field_attrs['widget'] = widget self.field_attrs['required'] = required def as_field(self): """ Render the variable as a Django form field. """ form_field = self.form_field(**self.field_attrs) form_field.widget.attrs['class'] += ' form-control' return form_field class WidgetObjectVar(ObjectVar): def __init__(self, queryset, widget, *args, **kwargs): super().__init__(queryset, *args, **kwargs) self.field_attrs['widget'] = widget def as_field(self): """ Render the variable as a Django form field. """ form_field = self.form_field(**self.field_attrs) form_field.widget.attrs['class'] += ' form-control' return form_field ``` I think this would be cleaner if it were incorporated into the main classes, as overriding certain things would not be required.
Author
Owner

@pszulczewski commented on GitHub (Jan 3, 2020):

Hi Daniel,

Thanks for sharing the code.
I added the second class to the custom script and APISelect works fine.

    upstream_node = ObjectVar(
        description="Upstream Node",
        queryset=Device.objects.filter(
            status=1
        )
    )
    upstream_port = WidgetObjectVar(
        queryset=Interface.objects.all(),
        widget=APISelect(
            api_url="/api/dcim/interfaces/",
            disabled_indicator='cable',
            additional_query_params={
                'kind': 'physical',
                'device_id': '75',
            }
        )
    )

But the problem is that device_id above is static and I would like to dynamically pass device id depending on previously selected device in another ObjectVar.
All ObjectVars seems to be added to data upon running the script, but I don't see any method accessing them before the script is run to pass device_id to the widget.

@pszulczewski commented on GitHub (Jan 3, 2020): Hi Daniel, Thanks for sharing the code. I added the second class to the custom script and APISelect works fine. ``` upstream_node = ObjectVar( description="Upstream Node", queryset=Device.objects.filter( status=1 ) ) upstream_port = WidgetObjectVar( queryset=Interface.objects.all(), widget=APISelect( api_url="/api/dcim/interfaces/", disabled_indicator='cable', additional_query_params={ 'kind': 'physical', 'device_id': '75', } ) ) ``` But the problem is that **device_id** above is static and I would like to dynamically pass device id depending on previously selected device in another ObjectVar. All ObjectVars seems to be added to **data** upon running the script, but I don't see any method accessing them before the script is run to pass device_id to the widget.
Author
Owner

@DanSheps commented on GitHub (Jan 3, 2020):

@pszulczewski Please take any help requests to the discussion group.

@DanSheps commented on GitHub (Jan 3, 2020): @pszulczewski Please take any help requests to the discussion group.
Author
Owner

@DanSheps commented on GitHub (Feb 11, 2020):

I am going to take this on (unless someone else wants to give it a shot).

@DanSheps commented on GitHub (Feb 11, 2020): I am going to take this on (unless someone else wants to give it a shot).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#3068