13132 add gettext_lazy to models

This commit is contained in:
Arthur 2023-07-11 10:20:56 +07:00 committed by Jeremy Stretch
parent 0c2e3ff898
commit 2eb2703219
9 changed files with 121 additions and 47 deletions

View File

@ -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
)

View File

@ -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:

View File

@ -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()

View File

@ -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()

View File

@ -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
)

View File

@ -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()

View File

@ -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')
)

View File

@ -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
)

View File

@ -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