mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-11 21:10:29 +01:00
Replace numeric constants with slug values #2926
Closed
opened 2025-12-29 18:23:36 +01:00 by adam
·
36 comments
No Branch/Tag Specified
main
update-changelog-comments-docs
feature-removal-issue-type
20911-dropdown
20239-plugin-menu-classes-mutable-state
21097-graphql-id-lookups
feature
fix_module_substitution
20923-dcim-templates
20044-elevation-stuck-lightmode
feature-ip-prefix-link
v4.5-beta1-release
20068-import-moduletype-attrs
20766-fix-german-translation-code-literals
20378-del-script
7604-filter-modifiers-v3
circuit-swap
12318-case-insensitive-uniqueness
20637-improve-device-q-filter
20660-script-load
19724-graphql
20614-update-ruff
14884-script
02496-max-page
19720-macaddress-interface-generic-relation
19408-circuit-terminations-export-templates
20203-openapi-check
fix-19669-api-image-download
7604-filter-modifiers
19275-fixes-interface-bulk-edit
fix-17794-get_field_value_return_list
11507-show-aggregate-and-rir-on-api
9583-add_column_specific_search_field_to_tables
v4.5.0
v4.4.10
v4.4.9
v4.5.0-beta1
v4.4.8
v4.4.7
v4.4.6
v4.4.5
v4.4.4
v4.4.3
v4.4.2
v4.4.1
v4.4.0
v4.3.7
v4.4.0-beta1
v4.3.6
v4.3.5
v4.3.4
v4.3.3
v4.3.2
v4.3.1
v4.3.0
v4.2.9
v4.3.0-beta2
v4.2.8
v4.3.0-beta1
v4.2.7
v4.2.6
v4.2.5
v4.2.4
v4.2.3
v4.2.2
v4.2.1
v4.2.0
v4.1.11
v4.1.10
v4.1.9
v4.1.8
v4.2-beta1
v4.1.7
v4.1.6
v4.1.5
v4.1.4
v4.1.3
v4.1.2
v4.1.1
v4.1.0
v4.0.11
v4.0.10
v4.0.9
v4.1-beta1
v4.0.8
v4.0.7
v4.0.6
v4.0.5
v4.0.3
v4.0.2
v4.0.1
v4.0.0
v3.7.8
v3.7.7
v4.0-beta2
v3.7.6
v3.7.5
v4.0-beta1
v3.7.4
v3.7.3
v3.7.2
v3.7.1
v3.7.0
v3.6.9
v3.6.8
v3.6.7
v3.7-beta1
v3.6.6
v3.6.5
v3.6.4
v3.6.3
v3.6.2
v3.6.1
v3.6.0
v3.5.9
v3.6-beta2
v3.5.8
v3.6-beta1
v3.5.7
v3.5.6
v3.5.5
v3.5.4
v3.5.3
v3.5.2
v3.5.1
v3.5.0
v3.4.10
v3.4.9
v3.5-beta2
v3.4.8
v3.5-beta1
v3.4.7
v3.4.6
v3.4.5
v3.4.4
v3.4.3
v3.4.2
v3.4.1
v3.4.0
v3.3.10
v3.3.9
v3.4-beta1
v3.3.8
v3.3.7
v3.3.6
v3.3.5
v3.3.4
v3.3.3
v3.3.2
v3.3.1
v3.3.0
v3.2.9
v3.2.8
v3.3-beta2
v3.2.7
v3.3-beta1
v3.2.6
v3.2.5
v3.2.4
v3.2.3
v3.2.2
v3.2.1
v3.2.0
v3.1.11
v3.1.10
v3.2-beta2
v3.1.9
v3.2-beta1
v3.1.8
v3.1.7
v3.1.6
v3.1.5
v3.1.4
v3.1.3
v3.1.2
v3.1.1
v3.1.0
v3.0.12
v3.0.11
v3.0.10
v3.1-beta1
v3.0.9
v3.0.8
v3.0.7
v3.0.6
v3.0.5
v3.0.4
v3.0.3
v3.0.2
v3.0.1
v3.0.0
v2.11.12
v3.0-beta2
v2.11.11
v2.11.10
v3.0-beta1
v2.11.9
v2.11.8
v2.11.7
v2.11.6
v2.11.5
v2.11.4
v2.11.3
v2.11.2
v2.11.1
v2.11.0
v2.10.10
v2.10.9
v2.11-beta1
v2.10.8
v2.10.7
v2.10.6
v2.10.5
v2.10.4
v2.10.3
v2.10.2
v2.10.1
v2.10.0
v2.9.11
v2.10-beta2
v2.9.10
v2.10-beta1
v2.9.9
v2.9.8
v2.9.7
v2.9.6
v2.9.5
v2.9.4
v2.9.3
v2.9.2
v2.9.1
v2.9.0
v2.9-beta2
v2.8.9
v2.9-beta1
v2.8.8
v2.8.7
v2.8.6
v2.8.5
v2.8.4
v2.8.3
v2.8.2
v2.8.1
v2.8.0
v2.7.12
v2.7.11
v2.7.10
v2.7.9
v2.7.8
v2.7.7
v2.7.6
v2.7.5
v2.7.4
v2.7.3
v2.7.2
v2.7.1
v2.7.0
v2.6.12
v2.6.11
v2.6.10
v2.6.9
v2.7-beta1
Solcon-2020-01-06
v2.6.8
v2.6.7
v2.6.6
v2.6.5
v2.6.4
v2.6.3
v2.6.2
v2.6.1
v2.6.0
v2.5.13
v2.5.12
v2.6-beta1
v2.5.11
v2.5.10
v2.5.9
v2.5.8
v2.5.7
v2.5.6
v2.5.5
v2.5.4
v2.5.3
v2.5.2
v2.5.1
v2.5.0
v2.4.9
v2.5-beta2
v2.4.8
v2.5-beta1
v2.4.7
v2.4.6
v2.4.5
v2.4.4
v2.4.3
v2.4.2
v2.4.1
v2.4.0
v2.3.7
v2.4-beta1
v2.3.6
v2.3.5
v2.3.4
v2.3.3
v2.3.2
v2.3.1
v2.3.0
v2.2.10
v2.3-beta2
v2.2.9
v2.3-beta1
v2.2.8
v2.2.7
v2.2.6
v2.2.5
v2.2.4
v2.2.3
v2.2.2
v2.2.1
v2.2.0
v2.1.6
v2.2-beta2
v2.1.5
v2.2-beta1
v2.1.4
v2.1.3
v2.1.2
v2.1.1
v2.1.0
v2.0.10
v2.1-beta1
v2.0.9
v2.0.8
v2.0.7
v2.0.6
v2.0.5
v2.0.4
v2.0.3
v2.0.2
v2.0.1
v2.0.0
v2.0-beta3
v1.9.6
v1.9.5
v2.0-beta2
v1.9.4-r1
v1.9.3
v2.0-beta1
v1.9.2
v1.9.1
v1.9.0-r1
v1.8.4
v1.8.3
v1.8.2
v1.8.1
v1.8.0
v1.7.3
v1.7.2-r1
v1.7.1
v1.7.0
v1.6.3
v1.6.2-r1
v1.6.1-r1
1.6.1
v1.6.0
v1.5.2
v1.5.1
v1.5.0
v1.4.2
v1.4.1
v1.4.0
v1.3.2
v1.3.1
v1.3.0
v1.2.2
v1.2.1
v1.2.0
v1.1.0
v1.0.7-r1
v1.0.7
v1.0.6
v1.0.5
v1.0.4
v1.0.3-r1
v1.0.3
1.0.0
Labels
Clear labels
beta
breaking change
complexity: high
complexity: low
complexity: medium
needs milestone
netbox
pending closure
plugin candidate
pull-request
severity: high
severity: low
severity: medium
status: accepted
status: backlog
status: blocked
status: duplicate
status: needs owner
status: needs triage
status: revisions needed
status: under review
topic: GraphQL
topic: Internationalization
topic: OpenAPI
topic: UI/UX
topic: cabling
topic: event rules
topic: htmx navigation
topic: industrialization
topic: migrations
topic: plugins
topic: scripts
topic: templating
topic: testing
type: bug
type: deprecation
type: documentation
type: feature
type: housekeeping
type: translation
Mirrored from GitHub Pull Request
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: starred/netbox#2926
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @jeremystretch on GitHub (Oct 4, 2019).
Originally assigned to: @jeremystretch on GitHub.
Proposed Changes
Replace the numeric values used for many fields with human-friendly slug values. For example:
would become
Justification
Employing human-friendly slug values make consuming the REST API more convenient. It also allows more human-friendly representations of the pertinent field values in other formats, such as YAML (see #451).
@candlerb commented on GitHub (Oct 4, 2019):
Would this also change the database column types to enum?
@jeremystretch commented on GitHub (Oct 7, 2019):
I don't think Django has built-in support for enumeration types, and adding it probably wouldn't get us much. It would also mean incurring a new migration each time a field had its set of valid choices modified.
@candlerb commented on GitHub (Oct 7, 2019):
In that case, surely the numeric values for RACK_STATUS_RESERVED, RACK_STATUS_AVAILABLE etc still need to be preserved in the Python code?
You could instead have RACK_STATUS_DISPLAY_CHOICES and RACK_STATUS_API_CHOICES ?
@jeremystretch commented on GitHub (Oct 7, 2019):
The point of the FR is to replace the numeric values with strings entirely. This will occur within a migration and be completely transparent to the user.
@candlerb commented on GitHub (Oct 7, 2019):
So the database field will be a varchar, not an enum? Got it.
@jeremystretch commented on GitHub (Oct 7, 2019):
Yep. I should point out that there will almost certainly be a transition period where the API will display and accept both the numeric and string values.
@jeremystretch commented on GitHub (Oct 7, 2019):
Something else occurs to me: By switching from integers to strings we'll lose the ability to order interfaces logically by type (ordering by type would be alphabetical using strings). I don't think this much of a concern but I wanted to put it out there.
@DanSheps commented on GitHub (Oct 7, 2019):
Could we define a sort order or a sort function for those perhaps?
I don't think the UI has any place to sort by them right now though, so I don't know if it is worth it until there is plans to actually have sorting for them.
@jeremystretch commented on GitHub (Oct 7, 2019):
AFAIK we've only ever sorted interfaces by name. The order in which the constants are currently defined is largely arbitrary anyway.
@candlerb commented on GitHub (Oct 7, 2019):
There is an explicit sequence in the list constants e.g.
RACK_STATUS_CHOICES, so it would be possible to map back to the index within this list, and sort on that if required.@jeremystretch commented on GitHub (Oct 17, 2019):
Currently, a choice field is represented like this in the API:
And after the change to slugs, it will look like this:
While it would be possible (although perhaps difficult) to accept either integer and slug (string) values on write requests to maintain backward compatibility, obviously we cannot convey both values in the same field simultaneously.
One thought I had was to introduce a temporary setting, allowing an admin to toggle between the old integer values and the new slug values. This would let the user to designate their own "flag day" for the API change irrespective of the NetBox release cycle. However, I'm not confident that the additional work needed to support this will ultimately be worthwhile, since users are in control of when they upgrade anyway.
@tyler-8 commented on GitHub (Oct 17, 2019):
Honestly I'm conflicted on this one. My main concern would be unintended side-effects in terms of database performance at scale. Seeing that this would be a fairly significant breaking change, if decided as the direction to go, perhaps add some sort of warnings or recurring deprecation message in multiple areas and table it for 2.8? Based on past 2.X releases that would give the community ~3-6 months to adjust their code and workflows after the official decision.
@candlerb commented on GitHub (Oct 18, 2019):
Database performance is not an issue. There is a massive python-based stack on top; the difference in time to read a string versus an int from the database will be immeasurable in comparison.
Breaking the API for reads bugs me. To avoid it, you'd have to have something like a query-string parameter which selects whether you want numeric or string values - it defaults to numeric initially, and later the default changes to string.
Is there really much value in this? An API is an API, hidden from humans. The "label" is what people see. Any sort of i18n implies that you must keep a mapping from human-readable labels to these codes.
@jeremystretch commented on GitHub (Oct 18, 2019):
Yes. People have expressed understandable frustration around having to maintain local integer-to-label mappings for API fields, but what prompted me to open this issue is the need for human-friendly names for interface and port types in support of a device type library (#451).
@tyler-8 commented on GitHub (Oct 18, 2019):
My concern lies more with indexing (and searching) at scale based on strings vs integers on the database side, rather than Python reading a string or integer. FWIW I think you're probably right though. The cardinality of constants is relatively low (at least for now...)
I'm leaning on the side of keeping existing behavior though. It's mostly a non-issue as is with the
choicesAPI endpoints. This seems like a big API change for what amounts to saving maybe one API call. IMO, the amount of work required to change existing integrations with Netbox's API is greater than the amount of work to call the choices API now.@cimnine commented on GitHub (Oct 18, 2019):
First, I'm really in favor of a change in this direction.
But I would like to raise my concern about the specific proposal of changing the
valuefrom being an id to a slug:As a user of API clients and former author of one, I would not be happy to see the type of the 'value' field change (from int to string). This might have unforeseen consequences on any statically typed API clients. They have to be re-written (that's the small part) and all the code, that goes with them, as well. Most of them would have to introduce special behavior to support Netbox versions prior and after this change.
Hence I suggest to introduce a 'slug' field instead (which might or might not get removed in the future):
This introduces the possibility for having at least a grace period, in which both - new and old - are available. Also, it does not change the type of a field to
stringthat was – until now and by definition – clearly anint.Further, it would open the possibility to just leave the
valueas it is for the foreseeable future, as it doesn't actually hurt to have both, does it?@candlerb commented on GitHub (Oct 18, 2019):
I would like to throw in one other option: keep the values in the database as integers, but make them foreign keys into a separate enumeration table for each status type. This means that:
I believe this won't have any measurable impact on performance. The FK relationship creates an index on the tiny enum/slug tables only; it doesn't affect the structure of the main tables which link to them. And the small number of enum/slug rows will be cached in RAM.
@jeremystretch commented on GitHub (Oct 18, 2019):
This would require NetBox to support both values in parallel. This is a nonstarter for me as that's simply not a reasonable burden to place on the maintainers: we have to pick one or the other.
I think this is a reasonable requirement. The most popular API client is pynetbox, and implementing this change should be pretty straightforward.
This is simply delaying a breaking change. Long-term we want to keep the
valuefield asslugis less intuitive. So, we either changevaluefrom an integer to a slug in one go, or we introduceslugfirst and then eventually rename it tovaluefor the same end result. It's much easier to manage one change than two.@jeremystretch commented on GitHub (Oct 18, 2019):
The plan is to introduce enumerated choices for all ChoiceFields once we move to Django 3.0.
Introducing ForeignKey relationships incurs additional JOINs. This was the primary reason for using static values originally.
I won't get into this as I've already provided my stance, but I will point out that we're talking about all choice fields, including those which have no reasonable use case for user-defined values, such as power phases or cable length unit.
@DanSheps commented on GitHub (Oct 18, 2019):
I definitely support this change, it would also allow us to take care of some "binary" fields (connected/planned).
@lampwins commented on GitHub (Oct 18, 2019):
For me, this is bringing up that we need to have a larger discussion around API versioning in general.
By definition this is a breaking change and absent either backward-compatible API versioning or a "grace period" in which the current integer values are supported, this puts certain classes of users in a tough spot. From the user's perspective, it is not as simple as saying "update your client."
That might be true if the only client in question is local ad-hoc scripts, but imagine cases where multiple other systems have been integrated with netbox. When the user wants to upgrade netbox, all of those clients have to be updated in sync, otherwise, things break with this kind of change. So if we don't allow a sort of grace period here, we force users into atomic upgrades across their automation infrastructures.
@jeremystretch commented on GitHub (Oct 18, 2019):
But no one is being forced to upgrade to v2.7 immediately. It's true that development stops on v2.6, but it should be reasonable to run a stable release of the v2.6 train for some time. It's a trade-off: make the necessary adaptations in order to get new features. While I believe every reasonable effort should be made to maintain backward compatibility for some period, everyone seems to have a different idea of what's reasonable.
Maybe instead of spending effort on ensuring some measure of backward compatibility between releases, we throw it out completely and instead begin supporting multiple trains. For example, keep releasing v2.6 versions with bug fixes only (no new features) in parallel with v2.7. When v2.8 comes out, kill v2.6 and change v2.7 to bug fixes only. IMO this is likely to be less of a burden for maintainers and more convenient for customers need more time to adapt.
@tyler-8 commented on GitHub (Oct 18, 2019):
The problem still lies in the transition of dependent-services. If the solution is to "wait until everything supports the new scheme" then that means the release of N-number of new versions external scripts/apps/services at the exact same time as the Netbox upgrade. That's untenable for most environments.
to @lampwins point, if there was some sort of API versioning in place, for example v2.7.0 provided these two endpoints:
That would allow each individual external app/service/script to migrate in its own time, on separate release windows from the Netbox upgrade. This is a far better experience all around and makes the upgrade process much easier to go through.
From a maintainer perspective, really it's just a separate API module at that point, the code for the two shall remain separate - and you only move new code to the
api_v2.pymodule when there's actually av2- keeping it clear where things are.@DanSheps commented on GitHub (Oct 18, 2019):
DRF does support API versioning: https://www.django-rest-framework.org/api-guide/versioning/
However, my problem with versioning is, at some point we have to stop maintaining the old version otherwise we are expending a large amount of resources maintaining something that we ultimately moved on from.
@tyler-8 commented on GitHub (Oct 18, 2019):
Absolutely - and you can even set those deadlines (for example, v1 removed by v2.8), add depreciation messages to releases notes and documentation. This is a common workflow and I think would be familiar to many Netbox users. Ansible, pip, and countless other apps & libraries follow this same pattern.
@jeremystretch commented on GitHub (Oct 18, 2019):
Why not simply extend these clients to support both versions simultaneously? That is what's being proposed for NetBox.
Ultimately this is a debate about how to distribute development burden, and I don't think it's fair to expect an all-volunteer team to commit to all the additional perpetual work required to maintain multiple API versions. We can barely keep up with the one as it is.
@cimnine commented on GitHub (Oct 19, 2019):
To me, introducing API versions because of this seems to be overkill. That's why my suggestion was to extend the API rather than introducing a radical change.
For what it's worth, I suggest rewriting those constants to actual Python
enums:So this
would become that
These enums can then be used like this:
If other functionality is required, it can be added relatively easily to the
ChoiceEnum. (E.g. if the slug can't always be inferred from the enum name like it's implemented above.)A solution like the proposed would make it trivial to maintain the
id, the correspondingslugand the actual name, for the foreseeable future:It would require a little more effort on the API side I believe. But I think it would boil down to a rather generic solution as well.
@jeremystretch commented on GitHub (Oct 25, 2019):
This won't address the root issue of accepting and conveying multiple values simultaneously in the REST API. (Additionally, Django 3.0 will introduce purpose-built enumerated choices.)
@jeremystretch commented on GitHub (Oct 29, 2019):
We need to decide what to do about this as it's currently blocking work needed for v2.7. We have a few options, which I'll list here.
Option 1: Change all integer choice values to slugs
Example:
This is the easiest option from a development standpoint, but of course it's also the most disruptive. Users would need to modify all affected API clients and upgrade NetBox to v2.7 at the same time.
Option 2: Introduce a new field to convey the slug value
Example:
This approach would be the least disruptive, however it would either lock us into using
slugas the value field instead ofvalue, or it would impose yet another migration at some future point whensluggets renamed tovalue.Option 3: Introduce a new field to convey the integer value
Example:
This is similar to option 2, but it ensures a smooth future deprecation of the
integerfield by front-loading the breaking change. Affected clients would need to be updated to reference the newintegerfield if they are not able to immediately adopt slugs.Option 4: Implement a configuration parameter to toggle between integer and slug values
This approach would introduce a mechanism by which a NetBox administrator can configure the API to use either integers or slugs in the
valuefield. It is essentially a stop-gap measure to allow users to upgrade to a v2.7 release without needing to immediately update API clients to use slugs. However, it would still eventually require a "flag day" to switch from integers to slugs.Option 5: Do nothing
We move forward with the v2.7 release without any changes to the existing integer values. This is acceptable, although it would be very nice to have made this switch prior to the implementation of #451, #792, and #1865.
@angely-dev commented on GitHub (Oct 29, 2019):
Just a user perspective here. We use the API intensively and we also support this change. We have what @lampwins called ad-hoc scripts (more a tiny framework though) so option 1 is not a problem. NetBox is a tool with a lot of activity so it seems to me users should be ready to make some changes from one version to another, especially if it is blocking some value-added features. Otherwise, they can stick to the current version until ready.
Also, why not extend this on user-defined roles? I mean, it is possible to filter prefixes using a role slug but the ID has to be used it to create a new one using the API. Just asking.
@sdktr commented on GitHub (Oct 30, 2019):
If option 1 is the intended outcome in the long run I'd prefer going that route in 2.7 directly. This is not very nice for users depending on external API client updates (and the synchronised 'big-bang-go-live') but imho the only feasible 'grey period' migration strategy boiles down to API versioning which @jeremystretch reasoned is unlikely to happen. We should act upon currently available realistic maintenance burden and I'd prefer not creating any future work in an already overbooked schema.
/offtopic API-versioning
Having a small (e.g. 1 minor version) overlap where people can utilize both the current and previous API might be less of an impact to the maintainers than keeping the complete current and previous minor releases up to date. But I'm in no position to make the correct judgement here so will stand corrected.
E.g.:
Netbox v2.7 supports both API schemas 2.6 and 2.7. If your client is 100% compatible with 2.7, it will continue to run in 2.8. If no breaking changes are in 2.9 it can still work, but the client still sends it 'known compatible schema'
X-Api-Version: 2.7and the server determines whether that endpoint version is still available.@jeremystretch commented on GitHub (Oct 30, 2019):
Out of scope for the current discussion. This has been discussed and laid to rest in other issues.
This is off the table as we simply don't have the development resources to support it at present.
@jeremystretch commented on GitHub (Nov 6, 2019):
After giving this some more thought, I'm going to proceed with option 3 as it seems like the best compromise between developer and user maintainability. The
valuefield will convey the new slug value, and we'll add anidfield to continue conveying the numeric value (to be deprecated for v2.8).Importantly, these fields will accept both the numeric and slug values on write for the entire v2.7 release, to maintain backward compatibility for the near future.
@lukasodhner commented on GitHub (Nov 17, 2019):
Will this change also apply to cable status? I believe this would relate to issue #3145
I know that cable status is currently boolean but if it was possible to add multiple statuses it would greatly improve our workflows. For example:
-Decomissioning (connected)
-Tested (disconnected)
-Failed (disconnected)
-Reterminate Side A(disconnected)
-Reterminate Side B (disconnected)
-Installation Error Side A (disconnected)
-Installation Error Side B (disconnected)
I understand this may be more complex then changing the other enum entries but I really hope it can be included in the transition to varchar
@jeremystretch commented on GitHub (Nov 18, 2019):
@lukasodhner Any changes to the available selections of any field are out of scope for this issue.
@lukasodhner commented on GitHub (Nov 19, 2019):
Understood. I have a slightly modified version of Netbox in a sandbox and I am just curious if you plan on changing the cable status into a slug as part of this issue