mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-25 08:46:10 -06:00
13132 add gettext_lazy to models
This commit is contained in:
parent
0c2e3ff898
commit
2eb2703219
@ -2,7 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from circuits.choices import *
|
||||
from dcim.models import CabledObjectModel
|
||||
@ -34,8 +34,8 @@ class Circuit(PrimaryModel):
|
||||
"""
|
||||
cid = models.CharField(
|
||||
max_length=100,
|
||||
verbose_name='Circuit ID',
|
||||
help_text=_("Unique circuit ID")
|
||||
verbose_name=_('Circuit ID'),
|
||||
help_text=_('Unique circuit ID')
|
||||
)
|
||||
provider = models.ForeignKey(
|
||||
to='circuits.Provider',
|
||||
@ -55,6 +55,7 @@ class Circuit(PrimaryModel):
|
||||
related_name='circuits'
|
||||
)
|
||||
status = models.CharField(
|
||||
verbose_name=_('status'),
|
||||
max_length=50,
|
||||
choices=CircuitStatusChoices,
|
||||
default=CircuitStatusChoices.STATUS_ACTIVE
|
||||
@ -69,17 +70,17 @@ class Circuit(PrimaryModel):
|
||||
install_date = models.DateField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Installed'
|
||||
verbose_name=_('Installed')
|
||||
)
|
||||
termination_date = models.DateField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Terminates'
|
||||
verbose_name=_('Terminates')
|
||||
)
|
||||
commit_rate = models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Commit rate (Kbps)',
|
||||
verbose_name=_('Commit rate (Kbps)'),
|
||||
help_text=_("Committed rate")
|
||||
)
|
||||
|
||||
@ -162,7 +163,7 @@ class CircuitTermination(
|
||||
term_side = models.CharField(
|
||||
max_length=1,
|
||||
choices=CircuitTerminationSideChoices,
|
||||
verbose_name='Termination'
|
||||
verbose_name=_('Termination')
|
||||
)
|
||||
site = models.ForeignKey(
|
||||
to='dcim.Site',
|
||||
@ -179,30 +180,31 @@ class CircuitTermination(
|
||||
null=True
|
||||
)
|
||||
port_speed = models.PositiveIntegerField(
|
||||
verbose_name='Port speed (Kbps)',
|
||||
verbose_name=_('Port speed (Kbps)'),
|
||||
blank=True,
|
||||
null=True,
|
||||
help_text=_("Physical circuit speed")
|
||||
help_text=_('Physical circuit speed')
|
||||
)
|
||||
upstream_speed = models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Upstream speed (Kbps)',
|
||||
verbose_name=_('Upstream speed (Kbps)'),
|
||||
help_text=_('Upstream speed, if different from port speed')
|
||||
)
|
||||
xconnect_id = models.CharField(
|
||||
max_length=50,
|
||||
blank=True,
|
||||
verbose_name='Cross-connect ID',
|
||||
help_text=_("ID of the local cross-connect")
|
||||
verbose_name=_('Cross-connect ID'),
|
||||
help_text=_('ID of the local cross-connect')
|
||||
)
|
||||
pp_info = models.CharField(
|
||||
max_length=100,
|
||||
blank=True,
|
||||
verbose_name='Patch panel/port(s)',
|
||||
help_text=_("Patch panel ID and port number(s)")
|
||||
verbose_name=_('Patch panel/port(s)'),
|
||||
help_text=_('Patch panel ID and port number(s)')
|
||||
)
|
||||
description = models.CharField(
|
||||
verbose_name=_('description'),
|
||||
max_length=200,
|
||||
blank=True
|
||||
)
|
||||
|
@ -2,7 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from netbox.models import PrimaryModel
|
||||
|
||||
@ -19,11 +19,13 @@ class Provider(PrimaryModel):
|
||||
stores information pertinent to the user's relationship with the Provider.
|
||||
"""
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=100,
|
||||
unique=True,
|
||||
help_text=_("Full name of the provider")
|
||||
help_text=_('Full name of the provider')
|
||||
)
|
||||
slug = models.SlugField(
|
||||
verbose_name=_('slug'),
|
||||
max_length=100,
|
||||
unique=True
|
||||
)
|
||||
@ -61,9 +63,10 @@ class ProviderAccount(PrimaryModel):
|
||||
)
|
||||
account = models.CharField(
|
||||
max_length=100,
|
||||
verbose_name='Account ID'
|
||||
verbose_name=_('Account ID')
|
||||
)
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=100,
|
||||
blank=True
|
||||
)
|
||||
@ -104,6 +107,7 @@ class ProviderNetwork(PrimaryModel):
|
||||
unimportant to the user.
|
||||
"""
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=100
|
||||
)
|
||||
provider = models.ForeignKey(
|
||||
@ -114,7 +118,7 @@ class ProviderNetwork(PrimaryModel):
|
||||
service_id = models.CharField(
|
||||
max_length=100,
|
||||
blank=True,
|
||||
verbose_name='Service ID'
|
||||
verbose_name=_('Service ID')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
|
@ -39,10 +39,12 @@ class DataSource(JobsMixin, PrimaryModel):
|
||||
A remote source, such as a git repository, from which DataFiles are synchronized.
|
||||
"""
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=100,
|
||||
unique=True
|
||||
)
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=DataSourceTypeChoices,
|
||||
default=DataSourceTypeChoices.LOCAL
|
||||
@ -52,23 +54,28 @@ class DataSource(JobsMixin, PrimaryModel):
|
||||
verbose_name=_('URL')
|
||||
)
|
||||
status = models.CharField(
|
||||
verbose_name=_('status'),
|
||||
max_length=50,
|
||||
choices=DataSourceStatusChoices,
|
||||
default=DataSourceStatusChoices.NEW,
|
||||
editable=False
|
||||
)
|
||||
enabled = models.BooleanField(
|
||||
verbose_name=_('enabled'),
|
||||
default=True
|
||||
)
|
||||
ignore_rules = models.TextField(
|
||||
verbose_name=_('ignore rules'),
|
||||
blank=True,
|
||||
help_text=_("Patterns (one per line) matching files to ignore when syncing")
|
||||
)
|
||||
parameters = models.JSONField(
|
||||
verbose_name=_('parameters'),
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
last_synced = models.DateTimeField(
|
||||
verbose_name=_('last synced'),
|
||||
blank=True,
|
||||
null=True,
|
||||
editable=False
|
||||
@ -239,9 +246,11 @@ class DataFile(models.Model):
|
||||
updated, or deleted only by calling DataSource.sync().
|
||||
"""
|
||||
created = models.DateTimeField(
|
||||
verbose_name=_('created'),
|
||||
auto_now_add=True
|
||||
)
|
||||
last_updated = models.DateTimeField(
|
||||
verbose_name=_('last updated'),
|
||||
editable=False
|
||||
)
|
||||
source = models.ForeignKey(
|
||||
@ -251,6 +260,7 @@ class DataFile(models.Model):
|
||||
editable=False
|
||||
)
|
||||
path = models.CharField(
|
||||
verbose_name=_('path'),
|
||||
max_length=1000,
|
||||
editable=False,
|
||||
help_text=_("File path relative to the data source's root")
|
||||
@ -259,12 +269,13 @@ class DataFile(models.Model):
|
||||
editable=False
|
||||
)
|
||||
hash = models.CharField(
|
||||
verbose_name=_('hash'),
|
||||
max_length=64,
|
||||
editable=False,
|
||||
validators=[
|
||||
RegexValidator(regex='^[0-9a-f]{64}$', message=_("Length must be 64 hexadecimal characters."))
|
||||
],
|
||||
help_text=_("SHA256 hash of the file data")
|
||||
help_text=_('SHA256 hash of the file data')
|
||||
)
|
||||
data = models.BinaryField()
|
||||
|
||||
|
@ -23,20 +23,24 @@ class ManagedFile(SyncedDataMixin, models.Model):
|
||||
to provide additional functionality.
|
||||
"""
|
||||
created = models.DateTimeField(
|
||||
verbose_name=_('created'),
|
||||
auto_now_add=True
|
||||
)
|
||||
last_updated = models.DateTimeField(
|
||||
verbose_name=_('last updated'),
|
||||
editable=False,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
file_root = models.CharField(
|
||||
verbose_name=_('file root'),
|
||||
max_length=1000,
|
||||
choices=ManagedFileRootPathChoices
|
||||
)
|
||||
file_path = models.FilePathField(
|
||||
verbose_name=_('file path'),
|
||||
editable=False,
|
||||
help_text=_("File path relative to the designated root path")
|
||||
help_text=_('File path relative to the designated root path')
|
||||
)
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
|
@ -43,28 +43,34 @@ class Job(models.Model):
|
||||
for_concrete_model=False
|
||||
)
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=200
|
||||
)
|
||||
created = models.DateTimeField(
|
||||
verbose_name=_('created'),
|
||||
auto_now_add=True
|
||||
)
|
||||
scheduled = models.DateTimeField(
|
||||
verbose_name=_('scheduled'),
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
interval = models.PositiveIntegerField(
|
||||
verbose_name=_('interval'),
|
||||
blank=True,
|
||||
null=True,
|
||||
validators=(
|
||||
MinValueValidator(1),
|
||||
),
|
||||
help_text=_("Recurrence interval (in minutes)")
|
||||
help_text=_('Recurrence interval (in minutes)')
|
||||
)
|
||||
started = models.DateTimeField(
|
||||
verbose_name=_('started'),
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
completed = models.DateTimeField(
|
||||
verbose_name=_('completed'),
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
@ -76,15 +82,18 @@ class Job(models.Model):
|
||||
null=True
|
||||
)
|
||||
status = models.CharField(
|
||||
verbose_name=_('status'),
|
||||
max_length=30,
|
||||
choices=JobStatusChoices,
|
||||
default=JobStatusChoices.STATUS_PENDING
|
||||
)
|
||||
data = models.JSONField(
|
||||
verbose_name=_('data'),
|
||||
null=True,
|
||||
blank=True
|
||||
)
|
||||
job_id = models.UUIDField(
|
||||
verbose_name=_('job id'),
|
||||
unique=True
|
||||
)
|
||||
|
||||
|
@ -8,6 +8,7 @@ from django.db import models
|
||||
from django.db.models import Sum
|
||||
from django.dispatch import Signal
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dcim.choices import *
|
||||
from dcim.constants import *
|
||||
@ -40,11 +41,13 @@ class Cable(PrimaryModel):
|
||||
A physical connection between two endpoints.
|
||||
"""
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=CableTypeChoices,
|
||||
blank=True
|
||||
)
|
||||
status = models.CharField(
|
||||
verbose_name=_('status'),
|
||||
max_length=50,
|
||||
choices=LinkStatusChoices,
|
||||
default=LinkStatusChoices.STATUS_CONNECTED
|
||||
@ -57,19 +60,23 @@ class Cable(PrimaryModel):
|
||||
null=True
|
||||
)
|
||||
label = models.CharField(
|
||||
verbose_name=_('label'),
|
||||
max_length=100,
|
||||
blank=True
|
||||
)
|
||||
color = ColorField(
|
||||
verbose_name=_('color'),
|
||||
blank=True
|
||||
)
|
||||
length = models.DecimalField(
|
||||
verbose_name=_('length'),
|
||||
max_digits=8,
|
||||
decimal_places=2,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
length_unit = models.CharField(
|
||||
verbose_name=_('length unit'),
|
||||
max_length=50,
|
||||
choices=CableLengthUnitChoices,
|
||||
blank=True,
|
||||
@ -235,7 +242,7 @@ class CableTermination(ChangeLoggedModel):
|
||||
cable_end = models.CharField(
|
||||
max_length=1,
|
||||
choices=CableEndChoices,
|
||||
verbose_name='End'
|
||||
verbose_name=_('End')
|
||||
)
|
||||
termination_type = models.ForeignKey(
|
||||
to=ContentType,
|
||||
@ -403,15 +410,19 @@ class CablePath(models.Model):
|
||||
`_nodes` retains a flattened list of all nodes within the path to enable simple filtering.
|
||||
"""
|
||||
path = models.JSONField(
|
||||
verbose_name=_('path'),
|
||||
default=list
|
||||
)
|
||||
is_active = models.BooleanField(
|
||||
verbose_name=_('is active'),
|
||||
default=False
|
||||
)
|
||||
is_complete = models.BooleanField(
|
||||
verbose_name=_('is complete'),
|
||||
default=False
|
||||
)
|
||||
is_split = models.BooleanField(
|
||||
verbose_name=_('is split'),
|
||||
default=False
|
||||
)
|
||||
_nodes = PathField()
|
||||
|
@ -3,7 +3,7 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from mptt.models import MPTTModel, TreeForeignKey
|
||||
|
||||
from dcim.choices import *
|
||||
@ -41,10 +41,11 @@ class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin):
|
||||
related_name='%(class)ss'
|
||||
)
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=64,
|
||||
help_text="""
|
||||
help_text=_("""
|
||||
{module} is accepted as a substitution for the module bay position when attached to a module type.
|
||||
"""
|
||||
""")
|
||||
)
|
||||
_name = NaturalOrderingField(
|
||||
target_field='name',
|
||||
@ -52,9 +53,10 @@ class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin):
|
||||
blank=True
|
||||
)
|
||||
label = models.CharField(
|
||||
verbose_name=_('label'),
|
||||
max_length=64,
|
||||
blank=True,
|
||||
help_text=_("Physical label")
|
||||
help_text=_('Physical label')
|
||||
)
|
||||
description = models.CharField(
|
||||
max_length=200,
|
||||
@ -98,7 +100,7 @@ class ComponentTemplateModel(ChangeLoggedModel, TrackingModelMixin):
|
||||
|
||||
if self.pk is not None and self._original_device_type != self.device_type_id:
|
||||
raise ValidationError({
|
||||
"device_type": "Component templates cannot be moved to a different device type."
|
||||
"device_type": _("Component templates cannot be moved to a different device type.")
|
||||
})
|
||||
|
||||
|
||||
@ -149,11 +151,11 @@ class ModularComponentTemplateModel(ComponentTemplateModel):
|
||||
# A component template must belong to a DeviceType *or* to a ModuleType
|
||||
if self.device_type and self.module_type:
|
||||
raise ValidationError(
|
||||
"A component template cannot be associated with both a device type and a module type."
|
||||
_("A component template cannot be associated with both a device type and a module type.")
|
||||
)
|
||||
if not self.device_type and not self.module_type:
|
||||
raise ValidationError(
|
||||
"A component template must be associated with either a device type or a module type."
|
||||
_("A component template must be associated with either a device type or a module type.")
|
||||
)
|
||||
|
||||
def resolve_name(self, module):
|
||||
@ -172,6 +174,7 @@ class ConsolePortTemplate(ModularComponentTemplateModel):
|
||||
A template for a ConsolePort to be created for a new Device.
|
||||
"""
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=ConsolePortTypeChoices,
|
||||
blank=True
|
||||
@ -201,6 +204,7 @@ class ConsoleServerPortTemplate(ModularComponentTemplateModel):
|
||||
A template for a ConsoleServerPort to be created for a new Device.
|
||||
"""
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=ConsolePortTypeChoices,
|
||||
blank=True
|
||||
@ -231,21 +235,24 @@ class PowerPortTemplate(ModularComponentTemplateModel):
|
||||
A template for a PowerPort to be created for a new Device.
|
||||
"""
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=PowerPortTypeChoices,
|
||||
blank=True
|
||||
)
|
||||
maximum_draw = models.PositiveIntegerField(
|
||||
verbose_name=_('maximum draw'),
|
||||
blank=True,
|
||||
null=True,
|
||||
validators=[MinValueValidator(1)],
|
||||
help_text=_("Maximum power draw (watts)")
|
||||
help_text=_('Maximum power draw (watts)')
|
||||
)
|
||||
allocated_draw = models.PositiveIntegerField(
|
||||
verbose_name=_('allocated draw'),
|
||||
blank=True,
|
||||
null=True,
|
||||
validators=[MinValueValidator(1)],
|
||||
help_text=_("Allocated power draw (watts)")
|
||||
help_text=_('Allocated power draw (watts)')
|
||||
)
|
||||
|
||||
component_model = PowerPort
|
||||
@ -267,7 +274,7 @@ class PowerPortTemplate(ModularComponentTemplateModel):
|
||||
if self.maximum_draw is not None and self.allocated_draw is not None:
|
||||
if self.allocated_draw > self.maximum_draw:
|
||||
raise ValidationError({
|
||||
'allocated_draw': f"Allocated draw cannot exceed the maximum draw ({self.maximum_draw}W)."
|
||||
'allocated_draw': _("Allocated draw cannot exceed the maximum draw ({maximum_draw}W).").format(maximum_draw=self.maximum_draw)
|
||||
})
|
||||
|
||||
def to_yaml(self):
|
||||
@ -286,6 +293,7 @@ class PowerOutletTemplate(ModularComponentTemplateModel):
|
||||
A template for a PowerOutlet to be created for a new Device.
|
||||
"""
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=PowerOutletTypeChoices,
|
||||
blank=True
|
||||
@ -298,10 +306,11 @@ class PowerOutletTemplate(ModularComponentTemplateModel):
|
||||
related_name='poweroutlet_templates'
|
||||
)
|
||||
feed_leg = models.CharField(
|
||||
verbose_name=_('feed leg'),
|
||||
max_length=50,
|
||||
choices=PowerOutletFeedLegChoices,
|
||||
blank=True,
|
||||
help_text=_("Phase (for three-phase feeds)")
|
||||
help_text=_('Phase (for three-phase feeds)')
|
||||
)
|
||||
|
||||
component_model = PowerOutlet
|
||||
@ -313,11 +322,11 @@ class PowerOutletTemplate(ModularComponentTemplateModel):
|
||||
if self.power_port:
|
||||
if self.device_type and self.power_port.device_type != self.device_type:
|
||||
raise ValidationError(
|
||||
f"Parent power port ({self.power_port}) must belong to the same device type"
|
||||
_("Parent power port ({power_port}) must belong to the same device type").format(power_port=self.power_port)
|
||||
)
|
||||
if self.module_type and self.power_port.module_type != self.module_type:
|
||||
raise ValidationError(
|
||||
f"Parent power port ({self.power_port}) must belong to the same module type"
|
||||
_("Parent power port ({power_port}) must belong to the same module type").format(power_port=self.power_port)
|
||||
)
|
||||
|
||||
def instantiate(self, **kwargs):
|
||||
@ -359,15 +368,17 @@ class InterfaceTemplate(ModularComponentTemplateModel):
|
||||
blank=True
|
||||
)
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=InterfaceTypeChoices
|
||||
)
|
||||
enabled = models.BooleanField(
|
||||
verbose_name=_('enabled'),
|
||||
default=True
|
||||
)
|
||||
mgmt_only = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name='Management only'
|
||||
verbose_name=_('Management only')
|
||||
)
|
||||
bridge = models.ForeignKey(
|
||||
to='self',
|
||||
@ -375,19 +386,19 @@ class InterfaceTemplate(ModularComponentTemplateModel):
|
||||
related_name='bridge_interfaces',
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name='Bridge interface'
|
||||
verbose_name=_('Bridge interface')
|
||||
)
|
||||
poe_mode = models.CharField(
|
||||
max_length=50,
|
||||
choices=InterfacePoEModeChoices,
|
||||
blank=True,
|
||||
verbose_name='PoE mode'
|
||||
verbose_name=_('PoE mode')
|
||||
)
|
||||
poe_type = models.CharField(
|
||||
max_length=50,
|
||||
choices=InterfacePoETypeChoices,
|
||||
blank=True,
|
||||
verbose_name='PoE type'
|
||||
verbose_name=_('PoE type')
|
||||
)
|
||||
rf_role = models.CharField(
|
||||
max_length=30,
|
||||
@ -403,14 +414,14 @@ class InterfaceTemplate(ModularComponentTemplateModel):
|
||||
|
||||
if self.bridge:
|
||||
if self.pk and self.bridge_id == self.pk:
|
||||
raise ValidationError({'bridge': "An interface cannot be bridged to itself."})
|
||||
raise ValidationError({'bridge': _("An interface cannot be bridged to itself.")})
|
||||
if self.device_type and self.device_type != self.bridge.device_type:
|
||||
raise ValidationError({
|
||||
'bridge': f"Bridge interface ({self.bridge}) must belong to the same device type"
|
||||
'bridge': _("Bridge interface ({bridge}) must belong to the same device type").format(bridge=self.bridge)
|
||||
})
|
||||
if self.module_type and self.module_type != self.bridge.module_type:
|
||||
raise ValidationError({
|
||||
'bridge': f"Bridge interface ({self.bridge}) must belong to the same module type"
|
||||
'bridge': _("Bridge interface ({bridge}) must belong to the same module type").format(bridge=self.bridge)
|
||||
})
|
||||
|
||||
if self.rf_role and self.type not in WIRELESS_IFACE_TYPES:
|
||||
@ -452,10 +463,12 @@ class FrontPortTemplate(ModularComponentTemplateModel):
|
||||
Template for a pass-through port on the front of a new Device.
|
||||
"""
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=PortTypeChoices
|
||||
)
|
||||
color = ColorField(
|
||||
verbose_name=_('color'),
|
||||
blank=True
|
||||
)
|
||||
rear_port = models.ForeignKey(
|
||||
@ -464,6 +477,7 @@ class FrontPortTemplate(ModularComponentTemplateModel):
|
||||
related_name='frontport_templates'
|
||||
)
|
||||
rear_port_position = models.PositiveSmallIntegerField(
|
||||
verbose_name=_('rear port position'),
|
||||
default=1,
|
||||
validators=[
|
||||
MinValueValidator(REARPORT_POSITIONS_MIN),
|
||||
@ -497,13 +511,13 @@ class FrontPortTemplate(ModularComponentTemplateModel):
|
||||
# Validate rear port assignment
|
||||
if self.rear_port.device_type != self.device_type:
|
||||
raise ValidationError(
|
||||
"Rear port ({}) must belong to the same device type".format(self.rear_port)
|
||||
_("Rear port ({}) must belong to the same device type").format(self.rear_port)
|
||||
)
|
||||
|
||||
# Validate rear port position assignment
|
||||
if self.rear_port_position > self.rear_port.positions:
|
||||
raise ValidationError(
|
||||
"Invalid rear port position ({}); rear port {} has only {} positions".format(
|
||||
_("Invalid rear port position ({}); rear port {} has only {} positions").format(
|
||||
self.rear_port_position, self.rear_port.name, self.rear_port.positions
|
||||
)
|
||||
)
|
||||
@ -545,13 +559,16 @@ class RearPortTemplate(ModularComponentTemplateModel):
|
||||
Template for a pass-through port on the rear of a new Device.
|
||||
"""
|
||||
type = models.CharField(
|
||||
verbose_name=_('type'),
|
||||
max_length=50,
|
||||
choices=PortTypeChoices
|
||||
)
|
||||
color = ColorField(
|
||||
verbose_name=_('color'),
|
||||
blank=True
|
||||
)
|
||||
positions = models.PositiveSmallIntegerField(
|
||||
verbose_name=_('positions'),
|
||||
default=1,
|
||||
validators=[
|
||||
MinValueValidator(REARPORT_POSITIONS_MIN),
|
||||
@ -588,6 +605,7 @@ class ModuleBayTemplate(ComponentTemplateModel):
|
||||
A template for a ModuleBay to be created for a new parent Device.
|
||||
"""
|
||||
position = models.CharField(
|
||||
verbose_name=_('position'),
|
||||
max_length=30,
|
||||
blank=True,
|
||||
help_text=_('Identifier to reference when renaming installed components')
|
||||
@ -630,7 +648,7 @@ class DeviceBayTemplate(ComponentTemplateModel):
|
||||
def clean(self):
|
||||
if self.device_type and self.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT:
|
||||
raise ValidationError(
|
||||
f"Subdevice role of device type ({self.device_type}) must be set to \"parent\" to allow device bays."
|
||||
_("Subdevice role of device type ({device_type}) must be set to \"parent\" to allow device bays.").format(device_type=self.device_type)
|
||||
)
|
||||
|
||||
def to_yaml(self):
|
||||
@ -685,7 +703,7 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel):
|
||||
)
|
||||
part_id = models.CharField(
|
||||
max_length=50,
|
||||
verbose_name='Part ID',
|
||||
verbose_name=_('Part ID'),
|
||||
blank=True,
|
||||
help_text=_('Manufacturer-assigned part identifier')
|
||||
)
|
||||
|
@ -2,6 +2,7 @@ from django.conf import settings
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.core.validators import ValidationError
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from mptt.models import MPTTModel, TreeForeignKey
|
||||
|
||||
from netbox.models.features import *
|
||||
@ -94,10 +95,12 @@ class PrimaryModel(NetBoxModel):
|
||||
Primary models represent real objects within the infrastructure being modeled.
|
||||
"""
|
||||
description = models.CharField(
|
||||
verbose_name=_('description'),
|
||||
max_length=200,
|
||||
blank=True
|
||||
)
|
||||
comments = models.TextField(
|
||||
verbose_name=_('comments'),
|
||||
blank=True
|
||||
)
|
||||
|
||||
@ -119,12 +122,15 @@ class NestedGroupModel(CloningMixin, NetBoxFeatureSet, MPTTModel):
|
||||
db_index=True
|
||||
)
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=100
|
||||
)
|
||||
slug = models.SlugField(
|
||||
verbose_name=_('slug'),
|
||||
max_length=100
|
||||
)
|
||||
description = models.CharField(
|
||||
verbose_name=_('description'),
|
||||
max_length=200,
|
||||
blank=True
|
||||
)
|
||||
@ -160,14 +166,17 @@ class OrganizationalModel(NetBoxFeatureSet, models.Model):
|
||||
- Optional description
|
||||
"""
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=100,
|
||||
unique=True
|
||||
)
|
||||
slug = models.SlugField(
|
||||
verbose_name=_('slug'),
|
||||
max_length=100,
|
||||
unique=True
|
||||
)
|
||||
description = models.CharField(
|
||||
verbose_name=_('description'),
|
||||
max_length=200,
|
||||
blank=True
|
||||
)
|
||||
|
@ -9,7 +9,7 @@ from django.db import models
|
||||
from django.db.models.signals import class_prepared
|
||||
from django.dispatch import receiver
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from core.choices import JobStatusChoices
|
||||
@ -46,11 +46,13 @@ class ChangeLoggingMixin(models.Model):
|
||||
Provides change logging support for a model. Adds the `created` and `last_updated` fields.
|
||||
"""
|
||||
created = models.DateTimeField(
|
||||
verbose_name=_('created'),
|
||||
auto_now_add=True,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
last_updated = models.DateTimeField(
|
||||
verbose_name=_('last updated'),
|
||||
auto_now=True,
|
||||
blank=True,
|
||||
null=True
|
||||
@ -144,6 +146,7 @@ class CustomFieldsMixin(models.Model):
|
||||
Enables support for custom fields.
|
||||
"""
|
||||
custom_field_data = models.JSONField(
|
||||
verbose_name=_('custom field data'),
|
||||
encoder=CustomFieldJSONEncoder,
|
||||
blank=True,
|
||||
default=dict
|
||||
@ -401,16 +404,19 @@ class SyncedDataMixin(models.Model):
|
||||
related_name='+'
|
||||
)
|
||||
data_path = models.CharField(
|
||||
verbose_name=_('data path'),
|
||||
max_length=1000,
|
||||
blank=True,
|
||||
editable=False,
|
||||
help_text=_("Path to remote file (relative to data source root)")
|
||||
)
|
||||
auto_sync_enabled = models.BooleanField(
|
||||
verbose_name=_('auto sync enabled'),
|
||||
default=False,
|
||||
help_text=_("Enable automatic synchronization of data when the data file is updated")
|
||||
)
|
||||
data_synced = models.DateTimeField(
|
||||
verbose_name=_('date synced'),
|
||||
blank=True,
|
||||
null=True,
|
||||
editable=False
|
||||
|
Loading…
Reference in New Issue
Block a user