mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-17 04:58:16 -06:00
Closes #8437
This commit is contained in:
parent
8cd24b1a67
commit
9937efc4ee
@ -17,6 +17,7 @@ from django.urls import reverse
|
|||||||
from utilities.choices import unpack_grouped_choices
|
from utilities.choices import unpack_grouped_choices
|
||||||
from utilities.utils import content_type_identifier, content_type_name
|
from utilities.utils import content_type_identifier, content_type_name
|
||||||
from utilities.validators import EnhancedURLValidator
|
from utilities.validators import EnhancedURLValidator
|
||||||
|
from virtualization.choices import MemoryUnitChoices
|
||||||
from . import widgets
|
from . import widgets
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .utils import expand_alphanumeric_pattern, expand_ipaddress_pattern, parse_csv, validate_csv
|
from .utils import expand_alphanumeric_pattern, expand_ipaddress_pattern, parse_csv, validate_csv
|
||||||
@ -41,6 +42,7 @@ __all__ = (
|
|||||||
'JSONField',
|
'JSONField',
|
||||||
'LaxURLField',
|
'LaxURLField',
|
||||||
'MACAddressField',
|
'MACAddressField',
|
||||||
|
'MemoryField',
|
||||||
'SlugField',
|
'SlugField',
|
||||||
'TagFilterField',
|
'TagFilterField',
|
||||||
)
|
)
|
||||||
@ -150,6 +152,40 @@ class MACAddressField(forms.Field):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryField(forms.MultiValueField):
|
||||||
|
widget = widgets.MemoryWidget
|
||||||
|
empty_values = ['', 'gb', 'mb', 'tb']
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
fields = (
|
||||||
|
forms.IntegerField(required=False),
|
||||||
|
forms.CharField(required=False),
|
||||||
|
)
|
||||||
|
super(MemoryField, self).__init__(
|
||||||
|
fields=fields, required=False,
|
||||||
|
require_all_fields=False, **kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def compress(self, data):
|
||||||
|
if data:
|
||||||
|
value = data[0]
|
||||||
|
unit = data[1]
|
||||||
|
|
||||||
|
defs = {
|
||||||
|
'gb': 1024**1,
|
||||||
|
'tb': 1024**2,
|
||||||
|
}
|
||||||
|
if value:
|
||||||
|
if unit != MemoryUnitChoices.UNIT_MB:
|
||||||
|
return value * defs[unit]
|
||||||
|
else:
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Content type fields
|
# Content type fields
|
||||||
#
|
#
|
||||||
|
@ -6,6 +6,7 @@ from django.conf import settings
|
|||||||
from django.contrib.postgres.forms import SimpleArrayField
|
from django.contrib.postgres.forms import SimpleArrayField
|
||||||
|
|
||||||
from utilities.choices import ColorChoices
|
from utilities.choices import ColorChoices
|
||||||
|
from virtualization.choices import MemoryUnitChoices
|
||||||
from .utils import add_blank_choice, parse_numeric_range
|
from .utils import add_blank_choice, parse_numeric_range
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -16,6 +17,7 @@ __all__ = (
|
|||||||
'ColorSelect',
|
'ColorSelect',
|
||||||
'DatePicker',
|
'DatePicker',
|
||||||
'DateTimePicker',
|
'DateTimePicker',
|
||||||
|
'MemoryWidget',
|
||||||
'NumericArrayField',
|
'NumericArrayField',
|
||||||
'SelectSpeedWidget',
|
'SelectSpeedWidget',
|
||||||
'SelectWithDisabled',
|
'SelectWithDisabled',
|
||||||
@ -310,3 +312,21 @@ class TimePicker(forms.TextInput):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.attrs['class'] = 'time-picker'
|
self.attrs['class'] = 'time-picker'
|
||||||
self.attrs['placeholder'] = 'hh:mm:ss'
|
self.attrs['placeholder'] = 'hh:mm:ss'
|
||||||
|
|
||||||
|
|
||||||
|
class MemoryWidget(forms.MultiWidget):
|
||||||
|
"""
|
||||||
|
Memory Widget.
|
||||||
|
"""
|
||||||
|
def __init__(self, attrs=None):
|
||||||
|
widget = (
|
||||||
|
forms.NumberInput(),
|
||||||
|
StaticSelect(choices=MemoryUnitChoices.choices)
|
||||||
|
)
|
||||||
|
super(MemoryWidget, self).__init__(widget, attrs)
|
||||||
|
|
||||||
|
def decompress(self, value):
|
||||||
|
if value:
|
||||||
|
return [value, '']
|
||||||
|
else:
|
||||||
|
return ['', '']
|
||||||
|
@ -84,6 +84,25 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% elif field|widget_type == 'memorywidget'%}
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label class="col-sm-3 col-form-label text-lg-end{% if field.field.required %} required{% endif %}" for="{{ field.id_for_label }}">
|
||||||
|
{{ field.label }}
|
||||||
|
</label>
|
||||||
|
<div class="col">
|
||||||
|
<div class="input-group">
|
||||||
|
{{ field }}
|
||||||
|
</div>
|
||||||
|
{% if bulk_nullable %}
|
||||||
|
<div class="form-check my-1">
|
||||||
|
<input type="checkbox" class="form-check-input" name="_nullify" value="{{ field.name }}" />
|
||||||
|
<label class="form-check-label">Set Null</label>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
{% elif field|widget_type == 'selectmultiple' %}
|
{% elif field|widget_type == 'selectmultiple' %}
|
||||||
<div class="row mb-3">
|
<div class="row mb-3">
|
||||||
<label for="{{ field.id_for_label }}" class="form-label col col-md-3 text-lg-end{% if field.field.required %} required{% endif %}">
|
<label for="{{ field.id_for_label }}" class="form-label col col-md-3 text-lg-end{% if field.field.required %} required{% endif %}">
|
||||||
@ -93,7 +112,7 @@
|
|||||||
{{ field }}
|
{{ field }}
|
||||||
{% if bulk_nullable %}
|
{% if bulk_nullable %}
|
||||||
<div class="form-check my-1">
|
<div class="form-check my-1">
|
||||||
<input type="checkbox" class="form-check-input" name="_nullify" value="{{ field.name }}" />
|
<input type="checkbox" class="form-check-input" name="_nullify" value="{{ field.name }}_0" />
|
||||||
<label class="form-check-label">Set Null</label>
|
<label class="form-check-label">Set Null</label>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -5,6 +5,17 @@ from utilities.choices import ChoiceSet
|
|||||||
# VirtualMachines
|
# VirtualMachines
|
||||||
#
|
#
|
||||||
|
|
||||||
|
class MemoryUnitChoices(ChoiceSet):
|
||||||
|
UNIT_MB = 'mb'
|
||||||
|
UNIT_GB = 'gb'
|
||||||
|
UNIT_TB = 'tb'
|
||||||
|
|
||||||
|
choices = (
|
||||||
|
(UNIT_MB, 'MB'),
|
||||||
|
(UNIT_GB, 'GB'),
|
||||||
|
(UNIT_TB, 'TB'),
|
||||||
|
)
|
||||||
|
|
||||||
class VirtualMachineStatusChoices(ChoiceSet):
|
class VirtualMachineStatusChoices(ChoiceSet):
|
||||||
|
|
||||||
STATUS_OFFLINE = 'offline'
|
STATUS_OFFLINE = 'offline'
|
||||||
|
@ -8,7 +8,7 @@ from ipam.models import VLAN
|
|||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
add_blank_choice, BulkEditNullBooleanSelect, BulkRenameForm, CommentField, DynamicModelChoiceField,
|
add_blank_choice, BulkEditNullBooleanSelect, BulkRenameForm, CommentField, DynamicModelChoiceField,
|
||||||
DynamicModelMultipleChoiceField, SmallTextarea, StaticSelect
|
DynamicModelMultipleChoiceField, SmallTextarea, StaticSelect, MemoryField
|
||||||
)
|
)
|
||||||
from virtualization.choices import *
|
from virtualization.choices import *
|
||||||
from virtualization.models import *
|
from virtualization.models import *
|
||||||
@ -131,10 +131,10 @@ class VirtualMachineBulkEditForm(AddRemoveTagsForm, CustomFieldModelBulkEditForm
|
|||||||
required=False,
|
required=False,
|
||||||
label='vCPUs'
|
label='vCPUs'
|
||||||
)
|
)
|
||||||
memory = forms.IntegerField(
|
memory = MemoryField()
|
||||||
required=False,
|
# memory = forms.IntegerField(
|
||||||
label='Memory (MB)'
|
# required=False
|
||||||
)
|
# )
|
||||||
disk = forms.IntegerField(
|
disk = forms.IntegerField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Disk (GB)'
|
label='Disk (GB)'
|
||||||
|
@ -11,7 +11,7 @@ from ipam.models import IPAddress, VLAN, VLANGroup
|
|||||||
from tenancy.forms import TenancyForm
|
from tenancy.forms import TenancyForm
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
BootstrapMixin, CommentField, ConfirmationForm, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
|
BootstrapMixin, CommentField, ConfirmationForm, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
|
||||||
JSONField, SlugField, StaticSelect,
|
JSONField, SlugField, StaticSelect, MemoryField
|
||||||
)
|
)
|
||||||
from virtualization.models import *
|
from virtualization.models import *
|
||||||
|
|
||||||
@ -205,6 +205,7 @@ class VirtualMachineForm(TenancyForm, CustomFieldModelForm):
|
|||||||
queryset=Tag.objects.all(),
|
queryset=Tag.objects.all(),
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
memory = MemoryField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
|
@ -192,7 +192,8 @@ class VirtualMachineTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
'primary_ip4': None,
|
'primary_ip4': None,
|
||||||
'primary_ip6': None,
|
'primary_ip6': None,
|
||||||
'vcpus': 4,
|
'vcpus': 4,
|
||||||
'memory': 32768,
|
'memory_0': 32768,
|
||||||
|
'memory_1': MemoryUnitChoices.UNIT_MB,
|
||||||
'disk': 4000,
|
'disk': 4000,
|
||||||
'comments': 'Some comments',
|
'comments': 'Some comments',
|
||||||
'tags': [t.pk for t in tags],
|
'tags': [t.pk for t in tags],
|
||||||
|
Loading…
Reference in New Issue
Block a user