mirror of
https://github.com/netbox-community/netbox.git
synced 2026-01-21 11:08:44 -06:00
Compare commits
7 Commits
v4.4.7
...
4230aba8de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4230aba8de | ||
|
|
ebf8f7fa1b | ||
|
|
922b08c0ff | ||
|
|
84864fa5e1 | ||
|
|
767dfccd8f | ||
|
|
dc4bab7477 | ||
|
|
60aa952eb1 |
@@ -12,7 +12,7 @@ Depending on its classification, each NetBox model may support various features
|
|||||||
|
|
||||||
| Feature | Feature Mixin | Registry Key | Description |
|
| Feature | Feature Mixin | Registry Key | Description |
|
||||||
|------------------------------------------------------------|-------------------------|---------------------|-----------------------------------------------------------------------------------------|
|
|------------------------------------------------------------|-------------------------|---------------------|-----------------------------------------------------------------------------------------|
|
||||||
| [Bookmarks](../features/customization.md#bookmarks) | `BookmarksMixin` | `bookmarks` | These models can be bookmarked natively in the user interface |
|
| [Bookmarks](../features/user-preferences.md#bookmarks) | `BookmarksMixin` | `bookmarks` | These models can be bookmarked natively in the user interface |
|
||||||
| [Change logging](../features/change-logging.md) | `ChangeLoggingMixin` | `change_logging` | Changes to these objects are automatically recorded in the change log |
|
| [Change logging](../features/change-logging.md) | `ChangeLoggingMixin` | `change_logging` | Changes to these objects are automatically recorded in the change log |
|
||||||
| Cloning | `CloningMixin` | `cloning` | Provides the `clone()` method to prepare a copy |
|
| Cloning | `CloningMixin` | `cloning` | Provides the `clone()` method to prepare a copy |
|
||||||
| [Contacts](../features/contacts.md) | `ContactsMixin` | `contacts` | Contacts can be associated with these models |
|
| [Contacts](../features/contacts.md) | `ContactsMixin` | `contacts` | Contacts can be associated with these models |
|
||||||
|
|||||||
@@ -472,14 +472,30 @@ class ModuleTypeImportForm(NetBoxModelImportForm):
|
|||||||
required=False,
|
required=False,
|
||||||
help_text=_('Unit for module weight')
|
help_text=_('Unit for module weight')
|
||||||
)
|
)
|
||||||
|
attribute_data = forms.JSONField(
|
||||||
|
label=_('Attributes'),
|
||||||
|
required=False,
|
||||||
|
help_text=_('Attribute values for the assigned profile, passed as a dictionary')
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fields = [
|
fields = [
|
||||||
'manufacturer', 'model', 'part_number', 'description', 'airflow', 'weight', 'weight_unit', 'profile',
|
'manufacturer', 'model', 'part_number', 'description', 'airflow', 'weight', 'weight_unit', 'profile',
|
||||||
'comments', 'tags'
|
'attribute_data', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
|
||||||
|
# Attribute data may be included only if a profile is specified
|
||||||
|
if self.cleaned_data.get('attribute_data') and not self.cleaned_data.get('profile'):
|
||||||
|
raise forms.ValidationError(_("Profile must be specified if attribute data is provided."))
|
||||||
|
|
||||||
|
# Default attribute_data to an empty dictionary if a profile is specified (to enforce schema validation)
|
||||||
|
if self.cleaned_data.get('profile') and not self.cleaned_data.get('attribute_data'):
|
||||||
|
self.cleaned_data['attribute_data'] = {}
|
||||||
|
|
||||||
|
|
||||||
class DeviceRoleImportForm(NetBoxModelImportForm):
|
class DeviceRoleImportForm(NetBoxModelImportForm):
|
||||||
parent = CSVModelChoiceField(
|
parent = CSVModelChoiceField(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import decimal
|
||||||
|
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
@@ -17,8 +19,8 @@ class Migration(migrations.Migration):
|
|||||||
max_digits=8,
|
max_digits=8,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[
|
validators=[
|
||||||
django.core.validators.MinValueValidator(-90.0),
|
django.core.validators.MinValueValidator(decimal.Decimal('-90.0')),
|
||||||
django.core.validators.MaxValueValidator(90.0),
|
django.core.validators.MaxValueValidator(decimal.Decimal('90.0'))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -31,8 +33,8 @@ class Migration(migrations.Migration):
|
|||||||
max_digits=9,
|
max_digits=9,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[
|
validators=[
|
||||||
django.core.validators.MinValueValidator(-180.0),
|
django.core.validators.MinValueValidator(decimal.Decimal('-180.0')),
|
||||||
django.core.validators.MaxValueValidator(180.0),
|
django.core.validators.MaxValueValidator(decimal.Decimal('180.0'))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -45,8 +47,8 @@ class Migration(migrations.Migration):
|
|||||||
max_digits=8,
|
max_digits=8,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[
|
validators=[
|
||||||
django.core.validators.MinValueValidator(-90.0),
|
django.core.validators.MinValueValidator(decimal.Decimal('-90.0')),
|
||||||
django.core.validators.MaxValueValidator(90.0),
|
django.core.validators.MaxValueValidator(decimal.Decimal('90.0'))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -59,8 +61,8 @@ class Migration(migrations.Migration):
|
|||||||
max_digits=9,
|
max_digits=9,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[
|
validators=[
|
||||||
django.core.validators.MinValueValidator(-180.0),
|
django.core.validators.MinValueValidator(decimal.Decimal('-180.0')),
|
||||||
django.core.validators.MaxValueValidator(180.0),
|
django.core.validators.MaxValueValidator(decimal.Decimal('180.0'))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -646,7 +646,10 @@ class Device(
|
|||||||
decimal_places=6,
|
decimal_places=6,
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[MinValueValidator(-90.0), MaxValueValidator(90.0)],
|
validators=[
|
||||||
|
MinValueValidator(decimal.Decimal('-90.0')),
|
||||||
|
MaxValueValidator(decimal.Decimal('90.0'))
|
||||||
|
],
|
||||||
help_text=_("GPS coordinate in decimal format (xx.yyyyyy)")
|
help_text=_("GPS coordinate in decimal format (xx.yyyyyy)")
|
||||||
)
|
)
|
||||||
longitude = models.DecimalField(
|
longitude = models.DecimalField(
|
||||||
@@ -655,7 +658,10 @@ class Device(
|
|||||||
decimal_places=6,
|
decimal_places=6,
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[MinValueValidator(-180.0), MaxValueValidator(180.0)],
|
validators=[
|
||||||
|
MinValueValidator(decimal.Decimal('-180.0')),
|
||||||
|
MaxValueValidator(decimal.Decimal('180.0'))
|
||||||
|
],
|
||||||
help_text=_("GPS coordinate in decimal format (xx.yyyyyy)")
|
help_text=_("GPS coordinate in decimal format (xx.yyyyyy)")
|
||||||
)
|
)
|
||||||
services = GenericRelation(
|
services = GenericRelation(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import decimal
|
||||||
|
|
||||||
from django.contrib.contenttypes.fields import GenericRelation
|
from django.contrib.contenttypes.fields import GenericRelation
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
@@ -211,7 +213,10 @@ class Site(ContactsMixin, ImageAttachmentsMixin, PrimaryModel):
|
|||||||
decimal_places=6,
|
decimal_places=6,
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[MinValueValidator(-90.0), MaxValueValidator(90.0)],
|
validators=[
|
||||||
|
MinValueValidator(decimal.Decimal('-90.0')),
|
||||||
|
MaxValueValidator(decimal.Decimal('90.0'))
|
||||||
|
],
|
||||||
help_text=_('GPS coordinate in decimal format (xx.yyyyyy)')
|
help_text=_('GPS coordinate in decimal format (xx.yyyyyy)')
|
||||||
)
|
)
|
||||||
longitude = models.DecimalField(
|
longitude = models.DecimalField(
|
||||||
@@ -220,7 +225,10 @@ class Site(ContactsMixin, ImageAttachmentsMixin, PrimaryModel):
|
|||||||
decimal_places=6,
|
decimal_places=6,
|
||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
validators=[MinValueValidator(-180.0), MaxValueValidator(180.0)],
|
validators=[
|
||||||
|
MinValueValidator(decimal.Decimal('-180.0')),
|
||||||
|
MaxValueValidator(decimal.Decimal('180.0'))
|
||||||
|
],
|
||||||
help_text=_('GPS coordinate in decimal format (xx.yyyyyy)')
|
help_text=_('GPS coordinate in decimal format (xx.yyyyyy)')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -559,6 +559,7 @@ class ComponentCreateView(GetReturnURLMixin, BaseObjectView):
|
|||||||
form.instance._replicated_base = hasattr(self.form, "replication_fields")
|
form.instance._replicated_base = hasattr(self.form, "replication_fields")
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
changelog_message = form.cleaned_data.pop('changelog_message', '')
|
||||||
new_components = []
|
new_components = []
|
||||||
data = deepcopy(request.POST)
|
data = deepcopy(request.POST)
|
||||||
pattern_count = len(form.cleaned_data[self.form.replication_fields[0]])
|
pattern_count = len(form.cleaned_data[self.form.replication_fields[0]])
|
||||||
@@ -585,6 +586,9 @@ class ComponentCreateView(GetReturnURLMixin, BaseObjectView):
|
|||||||
# Create the new components
|
# Create the new components
|
||||||
new_objs = []
|
new_objs = []
|
||||||
for component_form in new_components:
|
for component_form in new_components:
|
||||||
|
# Record changelog message (if any)
|
||||||
|
if changelog_message:
|
||||||
|
component_form.instance._changelog_message = changelog_message
|
||||||
obj = component_form.save()
|
obj = component_form.save()
|
||||||
new_objs.append(obj)
|
new_objs.append(obj)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user