Create DecimalVar class for custom script input #11411

Closed
opened 2025-12-29 21:44:54 +01:00 by adam · 7 comments
Owner

Originally created by @kyerlasswell on GitHub (Jul 24, 2025).

Originally assigned to: @kyerlasswell on GitHub.

NetBox version

v4.2.9

Feature type

Data model extension

Proposed functionality

Create a new class in netbox/extras/scripts.py called DecimalVar that enables custom scripts to take in decimal numbers as user input. This would be functionally identical to IntegerVar except it would allow decimal numbers.

class DecimalVar(ScriptVariable):
    """
    Decimal representation. Can enforce minimum/maximum values.
    """

    form_field = forms.DecimalField

    def __init__(self, min_value=None, max_value=None, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Optional minimum/maximum values
        if min_value:
            self.field_attrs["min_value"] = min_value
        if max_value:
            self.field_attrs["max_value"] = max_value

Use case

There is currently no built-in way to get decimal input from a user in a custom script (unless I'm just overlooking something obvious). IntegerVar exists for whole number input, but it cannot be used to get, for example, GPS coordinates from a user trying to create a site from a custom script.

Adding DecimalVar would enable the following:

# get data from user:

site_lat = DecimalVar(
    label="Latitude",
)

site_long = DecimalVar(
    label="Longitude",
)

# run:
site = Site(
    name="name",
    slug="slug",
    region="region",
    latitude=data["site_lat"],
    longitude=data["site_long"],
)

Database changes

None

External dependencies

None

Originally created by @kyerlasswell on GitHub (Jul 24, 2025). Originally assigned to: @kyerlasswell on GitHub. ### NetBox version v4.2.9 ### Feature type Data model extension ### Proposed functionality Create a new class in `netbox/extras/scripts.py` called `DecimalVar` that enables custom scripts to take in decimal numbers as user input. This would be functionally identical to IntegerVar except it would allow decimal numbers. ```python class DecimalVar(ScriptVariable): """ Decimal representation. Can enforce minimum/maximum values. """ form_field = forms.DecimalField def __init__(self, min_value=None, max_value=None, *args, **kwargs): super().__init__(*args, **kwargs) # Optional minimum/maximum values if min_value: self.field_attrs["min_value"] = min_value if max_value: self.field_attrs["max_value"] = max_value ``` ### Use case There is currently no built-in way to get decimal input from a user in a custom script (unless I'm just overlooking something obvious). IntegerVar exists for whole number input, but it cannot be used to get, for example, GPS coordinates from a user trying to create a site from a custom script. Adding DecimalVar would enable the following: ```python # get data from user: site_lat = DecimalVar( label="Latitude", ) site_long = DecimalVar( label="Longitude", ) # run: site = Site( name="name", slug="slug", region="region", latitude=data["site_lat"], longitude=data["site_long"], ) ``` ### Database changes None ### External dependencies None
adam added the status: acceptedtype: featurecomplexity: low labels 2025-12-29 21:44:54 +01:00
adam closed this issue 2025-12-29 21:44:54 +01:00
Author
Owner

@sleepinggenius2 commented on GitHub (Jul 24, 2025):

As a workaround, we are currently doing this:

    latitude = StringVar(
        label="Latitude",
        regex=r"^-?(90|([1-8]?\d))(\.\d{1,6})?$",
    )

    longitude = StringVar(
        label="Longitude",
        regex=r"^-?(180|(1[0-7]|[1-9])?\d)(\.\d{1,6})?$",
    )

    def run(self, data, commit):
        site = Site(
            ...
            latitude=Decimal(data['latitude']),
            longitude=Decimal(data['longitude']),
        )
@sleepinggenius2 commented on GitHub (Jul 24, 2025): As a workaround, we are currently doing this: ```python latitude = StringVar( label="Latitude", regex=r"^-?(90|([1-8]?\d))(\.\d{1,6})?$", ) longitude = StringVar( label="Longitude", regex=r"^-?(180|(1[0-7]|[1-9])?\d)(\.\d{1,6})?$", ) def run(self, data, commit): site = Site( ... latitude=Decimal(data['latitude']), longitude=Decimal(data['longitude']), ) ```
Author
Owner

@kyerlasswell commented on GitHub (Jul 24, 2025):

@sleepinggenius2 I started with something like that, but I ended up putting that DecimalVar class (that I just copied and modified from IntegerVar) directly into my custom script. This way, it can be used just like any other available variable class, you just have to import these:

  • from django import forms
  • from extras.scripts import ScriptVariable

So the whole script would look like:

from django import forms
from extras.scripts import ScriptVariable
from dcim.models import Site

class DecimalVar(ScriptVariable):
    """
    Decimal representation. Can enforce minimum/maximum values.
    """

    form_field = forms.DecimalField

    def __init__(self, min_value=None, max_value=None, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Optional minimum/maximum values
        if min_value:
            self.field_attrs["min_value"] = min_value
        if max_value:
            self.field_attrs["max_value"] = max_value

class ProvisionSite(Script):
    class Meta:
        name = "Provision site"

    site_lat = DecimalVar(
        label="Latitude",
    )

    site_long = DecimalVar(
        label="Longitude",
    )

    def run(self, data, commit):
        site = Site(
            ...
            latitude=data["site_lat"],
            longitude=data["site_long"],
        )

@kyerlasswell commented on GitHub (Jul 24, 2025): @sleepinggenius2 I started with something like that, but I ended up putting that DecimalVar class (that I just copied and modified from IntegerVar) directly into my custom script. This way, it can be used just like any other available variable class, you just have to import these: - from django import forms - from extras.scripts import ScriptVariable So the whole script would look like: ```python from django import forms from extras.scripts import ScriptVariable from dcim.models import Site class DecimalVar(ScriptVariable): """ Decimal representation. Can enforce minimum/maximum values. """ form_field = forms.DecimalField def __init__(self, min_value=None, max_value=None, *args, **kwargs): super().__init__(*args, **kwargs) # Optional minimum/maximum values if min_value: self.field_attrs["min_value"] = min_value if max_value: self.field_attrs["max_value"] = max_value class ProvisionSite(Script): class Meta: name = "Provision site" site_lat = DecimalVar( label="Latitude", ) site_long = DecimalVar( label="Longitude", ) def run(self, data, commit): site = Site( ... latitude=data["site_lat"], longitude=data["site_long"], ) ```
Author
Owner

@sleepinggenius2 commented on GitHub (Jul 24, 2025):

If you're going to go that route, I would suggest adding options for max_digits and decimal_places to your constructor, as your current solution does not account for the max_digits=8, decimal_places=6 on the Site.latitude field and the max_digits=9, decimal_places=6 on the Site.longitude field.

@sleepinggenius2 commented on GitHub (Jul 24, 2025): If you're going to go that route, I would suggest adding options for `max_digits` and `decimal_places` to your constructor, as your current solution does not account for the `max_digits=8, decimal_places=6` on the `Site.latitude` field and the `max_digits=9, decimal_places=6` on the `Site.longitude` field.
Author
Owner

@jnovinger commented on GitHub (Jul 24, 2025):

Is this something you'd like to work on @kyerlasswell , given your start above?

@jnovinger commented on GitHub (Jul 24, 2025): Is this something you'd like to work on @kyerlasswell , given your start above?
Author
Owner

@kyerlasswell commented on GitHub (Jul 24, 2025):

Yeah I'd be happy to.

@kyerlasswell commented on GitHub (Jul 24, 2025): Yeah I'd be happy to.
Author
Owner

@jnovinger commented on GitHub (Jul 24, 2025):

Thank @kyerlasswell ! It's all yours.

@jnovinger commented on GitHub (Jul 24, 2025): Thank @kyerlasswell ! It's all yours.
Author
Owner

@jeremystretch commented on GitHub (Jul 24, 2025):

@kyerlasswell please be sure to base your PR off the feature branch, as this will need to ship in NetBox v4.4.

@jeremystretch commented on GitHub (Jul 24, 2025): @kyerlasswell please be sure to base your PR off the `feature` branch, as this will need to ship in NetBox v4.4.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11411