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