mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Closes #13132: Wrap verbose_name and other model text with gettext_lazy() (i18n)
--------- Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
@ -5,6 +5,7 @@ from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.db.models.functions import Lower
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from dcim.models import BaseInterface
|
||||
from extras.models import ConfigContextModel
|
||||
@ -63,6 +64,7 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
null=True
|
||||
)
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=64
|
||||
)
|
||||
_name = NaturalOrderingField(
|
||||
@ -74,7 +76,7 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
max_length=50,
|
||||
choices=VirtualMachineStatusChoices,
|
||||
default=VirtualMachineStatusChoices.STATUS_ACTIVE,
|
||||
verbose_name='Status'
|
||||
verbose_name=_('status')
|
||||
)
|
||||
role = models.ForeignKey(
|
||||
to='dcim.DeviceRole',
|
||||
@ -90,7 +92,7 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
related_name='+',
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Primary IPv4'
|
||||
verbose_name=_('primary IPv4')
|
||||
)
|
||||
primary_ip6 = models.OneToOneField(
|
||||
to='ipam.IPAddress',
|
||||
@ -98,14 +100,14 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
related_name='+',
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Primary IPv6'
|
||||
verbose_name=_('primary IPv6')
|
||||
)
|
||||
vcpus = models.DecimalField(
|
||||
max_digits=6,
|
||||
decimal_places=2,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='vCPUs',
|
||||
verbose_name=_('vCPUs'),
|
||||
validators=(
|
||||
MinValueValidator(0.01),
|
||||
)
|
||||
@ -113,12 +115,12 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
memory = models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Memory (MB)'
|
||||
verbose_name=_('memory (MB)')
|
||||
)
|
||||
disk = models.PositiveIntegerField(
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='Disk (GB)'
|
||||
verbose_name=_('disk (GB)')
|
||||
)
|
||||
|
||||
# Counter fields
|
||||
@ -152,7 +154,7 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
Lower('name'), 'cluster',
|
||||
name='%(app_label)s_%(class)s_unique_name_cluster',
|
||||
condition=Q(tenant__isnull=True),
|
||||
violation_error_message="Virtual machine name must be unique per cluster."
|
||||
violation_error_message=_("Virtual machine name must be unique per cluster.")
|
||||
),
|
||||
)
|
||||
|
||||
@ -168,23 +170,27 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
# Must be assigned to a site and/or cluster
|
||||
if not self.site and not self.cluster:
|
||||
raise ValidationError({
|
||||
'cluster': f'A virtual machine must be assigned to a site and/or cluster.'
|
||||
'cluster': _('A virtual machine must be assigned to a site and/or cluster.')
|
||||
})
|
||||
|
||||
# Validate site for cluster & device
|
||||
if self.cluster and self.site and self.cluster.site != self.site:
|
||||
raise ValidationError({
|
||||
'cluster': f'The selected cluster ({self.cluster}) is not assigned to this site ({self.site}).'
|
||||
'cluster': _(
|
||||
'The selected cluster ({cluster}) is not assigned to this site ({site}).'
|
||||
).format(cluster=self.cluster, site=self.site)
|
||||
})
|
||||
|
||||
# Validate assigned cluster device
|
||||
if self.device and not self.cluster:
|
||||
raise ValidationError({
|
||||
'device': f'Must specify a cluster when assigning a host device.'
|
||||
'device': _('Must specify a cluster when assigning a host device.')
|
||||
})
|
||||
if self.device and self.device not in self.cluster.devices.all():
|
||||
raise ValidationError({
|
||||
'device': f'The selected device ({self.device}) is not assigned to this cluster ({self.cluster}).'
|
||||
'device': _(
|
||||
"The selected device ({device}) is not assigned to this cluster ({cluster})."
|
||||
).format(device=self.device, cluster=self.cluster)
|
||||
})
|
||||
|
||||
# Validate primary IP addresses
|
||||
@ -195,7 +201,9 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
if ip is not None:
|
||||
if ip.address.version != family:
|
||||
raise ValidationError({
|
||||
field: f"Must be an IPv{family} address. ({ip} is an IPv{ip.address.version} address.)",
|
||||
field: _(
|
||||
"Must be an IPv{family} address. ({ip} is an IPv{version} address.)"
|
||||
).format(family=family, ip=ip, version=ip.address.version)
|
||||
})
|
||||
if ip.assigned_object in interfaces:
|
||||
pass
|
||||
@ -203,7 +211,7 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
pass
|
||||
else:
|
||||
raise ValidationError({
|
||||
field: f"The specified IP address ({ip}) is not assigned to this VM.",
|
||||
field: _("The specified IP address ({ip}) is not assigned to this VM.").format(ip=ip),
|
||||
})
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
@ -236,6 +244,7 @@ class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
|
||||
related_name='interfaces'
|
||||
)
|
||||
name = models.CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=64
|
||||
)
|
||||
_name = NaturalOrderingField(
|
||||
@ -245,6 +254,7 @@ class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
|
||||
blank=True
|
||||
)
|
||||
description = models.CharField(
|
||||
verbose_name=_('description'),
|
||||
max_length=200,
|
||||
blank=True
|
||||
)
|
||||
@ -254,13 +264,13 @@ class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
|
||||
related_name='vminterfaces_as_untagged',
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name='Untagged VLAN'
|
||||
verbose_name=_('untagged VLAN')
|
||||
)
|
||||
tagged_vlans = models.ManyToManyField(
|
||||
to='ipam.VLAN',
|
||||
related_name='vminterfaces_as_tagged',
|
||||
blank=True,
|
||||
verbose_name='Tagged VLANs'
|
||||
verbose_name=_('tagged VLANs')
|
||||
)
|
||||
ip_addresses = GenericRelation(
|
||||
to='ipam.IPAddress',
|
||||
@ -274,7 +284,7 @@ class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
|
||||
related_name='vminterfaces',
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name='VRF'
|
||||
verbose_name=_('VRF')
|
||||
)
|
||||
fhrp_group_assignments = GenericRelation(
|
||||
to='ipam.FHRPGroupAssignment',
|
||||
@ -312,26 +322,30 @@ class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
|
||||
|
||||
# An interface cannot be its own parent
|
||||
if self.pk and self.parent_id == self.pk:
|
||||
raise ValidationError({'parent': "An interface cannot be its own parent."})
|
||||
raise ValidationError({'parent': _("An interface cannot be its own parent.")})
|
||||
|
||||
# An interface's parent must belong to the same virtual machine
|
||||
if self.parent and self.parent.virtual_machine != self.virtual_machine:
|
||||
raise ValidationError({
|
||||
'parent': f"The selected parent interface ({self.parent}) belongs to a different virtual machine "
|
||||
f"({self.parent.virtual_machine})."
|
||||
'parent': _(
|
||||
"The selected parent interface ({parent}) belongs to a different virtual machine "
|
||||
"({virtual_machine})."
|
||||
).format(parent=self.parent, virtual_machine=self.parent.virtual_machine)
|
||||
})
|
||||
|
||||
# Bridge validation
|
||||
|
||||
# An interface cannot be bridged to itself
|
||||
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.")})
|
||||
|
||||
# A bridged interface belong to the same virtual machine
|
||||
if self.bridge and self.bridge.virtual_machine != self.virtual_machine:
|
||||
raise ValidationError({
|
||||
'bridge': f"The selected bridge interface ({self.bridge}) belongs to a different virtual machine "
|
||||
f"({self.bridge.virtual_machine})."
|
||||
'bridge': _(
|
||||
"The selected bridge interface ({bridge}) belongs to a different virtual machine "
|
||||
"({virtual_machine})."
|
||||
).format(bridge=self.bridge, virtual_machine=self.bridge.virtual_machine)
|
||||
})
|
||||
|
||||
# VLAN validation
|
||||
@ -339,8 +353,10 @@ class VMInterface(NetBoxModel, BaseInterface, TrackingModelMixin):
|
||||
# Validate untagged VLAN
|
||||
if self.untagged_vlan and self.untagged_vlan.site not in [self.virtual_machine.site, None]:
|
||||
raise ValidationError({
|
||||
'untagged_vlan': f"The untagged VLAN ({self.untagged_vlan}) must belong to the same site as the "
|
||||
f"interface's parent virtual machine, or it must be global."
|
||||
'untagged_vlan': _(
|
||||
"The untagged VLAN ({untagged_vlan}) must belong to the same site as the interface's parent "
|
||||
"virtual machine, or it must be global."
|
||||
).format(untagged_vlan=self.untagged_vlan)
|
||||
})
|
||||
|
||||
def to_objectchange(self, action):
|
||||
|
Reference in New Issue
Block a user