mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-14 01:41:22 -06:00
#8054: Support configurable status choices
This commit is contained in:
parent
28f577738a
commit
419f86a4a5
@ -140,6 +140,41 @@ EXEMPT_VIEW_PERMISSIONS = ['*']
|
||||
|
||||
---
|
||||
|
||||
## FIELD_CHOICES
|
||||
|
||||
Default: Empty dictionary
|
||||
|
||||
Some static choice fields on models can be configured with custom values. This is done by defining `FIELD_CHOICES` as a dictionary mapping model fields to their choices list. Each choice in the list must have a database value and a human-friendly label, and may optionally specify a color.
|
||||
|
||||
For example, to specify a custom set of choices for the site status field:
|
||||
|
||||
```python
|
||||
FIELD_CHOICES = {
|
||||
'dcim.Site.status': (
|
||||
('foo', 'Foo'),
|
||||
('bar', 'Bar'),
|
||||
('baz', 'Baz'),
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
These will be appended to the stock choices for the field.
|
||||
|
||||
The following model field support configurable choices:
|
||||
|
||||
* `circuits.Circuit.status`
|
||||
* `dcim.Device.status`
|
||||
* `dcim.PowerFeed.status`
|
||||
* `dcim.Rack.status`
|
||||
* `dcim.Site.status`
|
||||
* `ipam.IPAddress.status`
|
||||
* `ipam.IPRange.status`
|
||||
* `ipam.Prefix.status`
|
||||
* `ipam.VLAN.status`
|
||||
* `virtualization.VirtualMachine.status`
|
||||
|
||||
---
|
||||
|
||||
## HTTP_PROXIES
|
||||
|
||||
Default: None
|
||||
|
@ -6,6 +6,7 @@ from utilities.choices import ChoiceSet
|
||||
#
|
||||
|
||||
class CircuitStatusChoices(ChoiceSet):
|
||||
key = 'circuits.Circuit.status'
|
||||
|
||||
STATUS_DEPROVISIONING = 'deprovisioning'
|
||||
STATUS_ACTIVE = 'active'
|
||||
@ -14,14 +15,14 @@ class CircuitStatusChoices(ChoiceSet):
|
||||
STATUS_OFFLINE = 'offline'
|
||||
STATUS_DECOMMISSIONED = 'decommissioned'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_PLANNED, 'Planned'),
|
||||
(STATUS_PROVISIONING, 'Provisioning'),
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_OFFLINE, 'Offline'),
|
||||
(STATUS_DEPROVISIONING, 'Deprovisioning'),
|
||||
(STATUS_DECOMMISSIONED, 'Decommissioned'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_DEPROVISIONING: 'warning',
|
||||
|
@ -6,6 +6,7 @@ from utilities.choices import ChoiceSet
|
||||
#
|
||||
|
||||
class SiteStatusChoices(ChoiceSet):
|
||||
key = 'dcim.Site.status'
|
||||
|
||||
STATUS_PLANNED = 'planned'
|
||||
STATUS_STAGING = 'staging'
|
||||
@ -13,13 +14,13 @@ class SiteStatusChoices(ChoiceSet):
|
||||
STATUS_DECOMMISSIONING = 'decommissioning'
|
||||
STATUS_RETIRED = 'retired'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_PLANNED, 'Planned'),
|
||||
(STATUS_STAGING, 'Staging'),
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_DECOMMISSIONING, 'Decommissioning'),
|
||||
(STATUS_RETIRED, 'Retired'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_PLANNED: 'info',
|
||||
@ -67,6 +68,7 @@ class RackWidthChoices(ChoiceSet):
|
||||
|
||||
|
||||
class RackStatusChoices(ChoiceSet):
|
||||
key = 'dcim.Rack.status'
|
||||
|
||||
STATUS_RESERVED = 'reserved'
|
||||
STATUS_AVAILABLE = 'available'
|
||||
@ -74,13 +76,13 @@ class RackStatusChoices(ChoiceSet):
|
||||
STATUS_ACTIVE = 'active'
|
||||
STATUS_DEPRECATED = 'deprecated'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_RESERVED, 'Reserved'),
|
||||
(STATUS_AVAILABLE, 'Available'),
|
||||
(STATUS_PLANNED, 'Planned'),
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_DEPRECATED, 'Deprecated'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_RESERVED: 'warning',
|
||||
@ -144,6 +146,7 @@ class DeviceFaceChoices(ChoiceSet):
|
||||
|
||||
|
||||
class DeviceStatusChoices(ChoiceSet):
|
||||
key = 'dcim.Device.status'
|
||||
|
||||
STATUS_OFFLINE = 'offline'
|
||||
STATUS_ACTIVE = 'active'
|
||||
@ -153,7 +156,7 @@ class DeviceStatusChoices(ChoiceSet):
|
||||
STATUS_INVENTORY = 'inventory'
|
||||
STATUS_DECOMMISSIONING = 'decommissioning'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_OFFLINE, 'Offline'),
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_PLANNED, 'Planned'),
|
||||
@ -161,7 +164,7 @@ class DeviceStatusChoices(ChoiceSet):
|
||||
(STATUS_FAILED, 'Failed'),
|
||||
(STATUS_INVENTORY, 'Inventory'),
|
||||
(STATUS_DECOMMISSIONING, 'Decommissioning'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_OFFLINE: 'warning',
|
||||
@ -1183,18 +1186,19 @@ class CableLengthUnitChoices(ChoiceSet):
|
||||
#
|
||||
|
||||
class PowerFeedStatusChoices(ChoiceSet):
|
||||
key = 'dcim.PowerFeed.status'
|
||||
|
||||
STATUS_OFFLINE = 'offline'
|
||||
STATUS_ACTIVE = 'active'
|
||||
STATUS_PLANNED = 'planned'
|
||||
STATUS_FAILED = 'failed'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_OFFLINE, 'Offline'),
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_PLANNED, 'Planned'),
|
||||
(STATUS_FAILED, 'Failed'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_OFFLINE: 'warning',
|
||||
|
@ -17,18 +17,19 @@ class IPAddressFamilyChoices(ChoiceSet):
|
||||
#
|
||||
|
||||
class PrefixStatusChoices(ChoiceSet):
|
||||
key = 'ipam.Prefix.status'
|
||||
|
||||
STATUS_CONTAINER = 'container'
|
||||
STATUS_ACTIVE = 'active'
|
||||
STATUS_RESERVED = 'reserved'
|
||||
STATUS_DEPRECATED = 'deprecated'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_CONTAINER, 'Container'),
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_RESERVED, 'Reserved'),
|
||||
(STATUS_DEPRECATED, 'Deprecated'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_CONTAINER: 'secondary',
|
||||
@ -43,16 +44,17 @@ class PrefixStatusChoices(ChoiceSet):
|
||||
#
|
||||
|
||||
class IPRangeStatusChoices(ChoiceSet):
|
||||
key = 'ipam.IPRange.status'
|
||||
|
||||
STATUS_ACTIVE = 'active'
|
||||
STATUS_RESERVED = 'reserved'
|
||||
STATUS_DEPRECATED = 'deprecated'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_RESERVED, 'Reserved'),
|
||||
(STATUS_DEPRECATED, 'Deprecated'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_ACTIVE: 'primary',
|
||||
@ -66,6 +68,7 @@ class IPRangeStatusChoices(ChoiceSet):
|
||||
#
|
||||
|
||||
class IPAddressStatusChoices(ChoiceSet):
|
||||
key = 'ipam.IPAddress.status'
|
||||
|
||||
STATUS_ACTIVE = 'active'
|
||||
STATUS_RESERVED = 'reserved'
|
||||
@ -73,13 +76,13 @@ class IPAddressStatusChoices(ChoiceSet):
|
||||
STATUS_DHCP = 'dhcp'
|
||||
STATUS_SLAAC = 'slaac'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_RESERVED, 'Reserved'),
|
||||
(STATUS_DEPRECATED, 'Deprecated'),
|
||||
(STATUS_DHCP, 'DHCP'),
|
||||
(STATUS_SLAAC, 'SLAAC'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_ACTIVE: 'primary',
|
||||
@ -161,16 +164,17 @@ class FHRPGroupAuthTypeChoices(ChoiceSet):
|
||||
#
|
||||
|
||||
class VLANStatusChoices(ChoiceSet):
|
||||
key = 'ipam.VLAN.status'
|
||||
|
||||
STATUS_ACTIVE = 'active'
|
||||
STATUS_RESERVED = 'reserved'
|
||||
STATUS_DEPRECATED = 'deprecated'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_RESERVED, 'Reserved'),
|
||||
(STATUS_DEPRECATED, 'Deprecated'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_ACTIVE: 'primary',
|
||||
|
@ -86,6 +86,7 @@ DEVELOPER = getattr(configuration, 'DEVELOPER', False)
|
||||
DOCS_ROOT = getattr(configuration, 'DOCS_ROOT', os.path.join(os.path.dirname(BASE_DIR), 'docs'))
|
||||
EMAIL = getattr(configuration, 'EMAIL', {})
|
||||
EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', [])
|
||||
FIELD_CHOICES = getattr(configuration, 'FIELD_CHOICES', {})
|
||||
HTTP_PROXIES = getattr(configuration, 'HTTP_PROXIES', None)
|
||||
INTERNAL_IPS = getattr(configuration, 'INTERNAL_IPS', ('127.0.0.1', '::1'))
|
||||
LOGGING = getattr(configuration, 'LOGGING', {})
|
||||
|
@ -1,7 +1,21 @@
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class ChoiceSetMeta(type):
|
||||
"""
|
||||
Metaclass for ChoiceSet
|
||||
"""
|
||||
def __new__(mcs, name, bases, attrs):
|
||||
|
||||
# Extend static choices with any configured choices
|
||||
if 'key' in attrs:
|
||||
try:
|
||||
attrs['CHOICES'].extend(settings.FIELD_CHOICES[attrs['key']])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return super().__new__(mcs, name, bases, attrs)
|
||||
|
||||
def __call__(cls, *args, **kwargs):
|
||||
# Django will check if a 'choices' value is callable, and if so assume that it returns an iterable
|
||||
return getattr(cls, 'CHOICES', ())
|
||||
|
@ -6,6 +6,7 @@ from utilities.choices import ChoiceSet
|
||||
#
|
||||
|
||||
class VirtualMachineStatusChoices(ChoiceSet):
|
||||
key = 'virtualization.VirtualMachine.status'
|
||||
|
||||
STATUS_OFFLINE = 'offline'
|
||||
STATUS_ACTIVE = 'active'
|
||||
@ -14,14 +15,14 @@ class VirtualMachineStatusChoices(ChoiceSet):
|
||||
STATUS_FAILED = 'failed'
|
||||
STATUS_DECOMMISSIONING = 'decommissioning'
|
||||
|
||||
CHOICES = (
|
||||
CHOICES = [
|
||||
(STATUS_OFFLINE, 'Offline'),
|
||||
(STATUS_ACTIVE, 'Active'),
|
||||
(STATUS_PLANNED, 'Planned'),
|
||||
(STATUS_STAGED, 'Staged'),
|
||||
(STATUS_FAILED, 'Failed'),
|
||||
(STATUS_DECOMMISSIONING, 'Decommissioning'),
|
||||
)
|
||||
]
|
||||
|
||||
CSS_CLASSES = {
|
||||
STATUS_OFFLINE: 'warning',
|
||||
|
Loading…
Reference in New Issue
Block a user