10300 initial translation support use gettext

This commit is contained in:
Arthur 2022-11-03 11:58:26 -07:00 committed by Jeremy Stretch
parent 2cc2d2cc37
commit 6eba5d4d96
67 changed files with 1192 additions and 1134 deletions

View File

@ -1,5 +1,6 @@
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _
from dcim.filtersets import CabledObjectFilterSet from dcim.filtersets import CabledObjectFilterSet
from dcim.models import Region, Site, SiteGroup from dcim.models import Region, Site, SiteGroup
@ -24,43 +25,43 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='circuits__terminations__site__region', field_name='circuits__terminations__site__region',
lookup_expr='in', lookup_expr='in',
label='Region (ID)', label=_('Region (ID)'),
) )
region = TreeNodeMultipleChoiceFilter( region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='circuits__terminations__site__region', field_name='circuits__terminations__site__region',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Region (slug)', label=_('Region (slug)'),
) )
site_group_id = TreeNodeMultipleChoiceFilter( site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='circuits__terminations__site__group', field_name='circuits__terminations__site__group',
lookup_expr='in', lookup_expr='in',
label='Site group (ID)', label=_('Site group (ID)'),
) )
site_group = TreeNodeMultipleChoiceFilter( site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='circuits__terminations__site__group', field_name='circuits__terminations__site__group',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Site group (slug)', label=_('Site group (slug)'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
field_name='circuits__terminations__site', field_name='circuits__terminations__site',
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site', label=_('Site'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='circuits__terminations__site__slug', field_name='circuits__terminations__site__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
asn_id = django_filters.ModelMultipleChoiceFilter( asn_id = django_filters.ModelMultipleChoiceFilter(
field_name='asns', field_name='asns',
queryset=ASN.objects.all(), queryset=ASN.objects.all(),
label='ASN (ID)', label=_('ASN (ID)'),
) )
class Meta: class Meta:
@ -80,13 +81,13 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
class ProviderNetworkFilterSet(NetBoxModelFilterSet): class ProviderNetworkFilterSet(NetBoxModelFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter( provider_id = django_filters.ModelMultipleChoiceFilter(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
label='Provider (ID)', label=_('Provider (ID)'),
) )
provider = django_filters.ModelMultipleChoiceFilter( provider = django_filters.ModelMultipleChoiceFilter(
field_name='provider__slug', field_name='provider__slug',
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Provider (slug)', label=_('Provider (slug)'),
) )
class Meta: class Meta:
@ -114,28 +115,28 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet):
class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet): class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter( provider_id = django_filters.ModelMultipleChoiceFilter(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
label='Provider (ID)', label=_('Provider (ID)'),
) )
provider = django_filters.ModelMultipleChoiceFilter( provider = django_filters.ModelMultipleChoiceFilter(
field_name='provider__slug', field_name='provider__slug',
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Provider (slug)', label=_('Provider (slug)'),
) )
provider_network_id = django_filters.ModelMultipleChoiceFilter( provider_network_id = django_filters.ModelMultipleChoiceFilter(
field_name='terminations__provider_network', field_name='terminations__provider_network',
queryset=ProviderNetwork.objects.all(), queryset=ProviderNetwork.objects.all(),
label='ProviderNetwork (ID)', label=_('ProviderNetwork (ID)'),
) )
type_id = django_filters.ModelMultipleChoiceFilter( type_id = django_filters.ModelMultipleChoiceFilter(
queryset=CircuitType.objects.all(), queryset=CircuitType.objects.all(),
label='Circuit type (ID)', label=_('Circuit type (ID)'),
) )
type = django_filters.ModelMultipleChoiceFilter( type = django_filters.ModelMultipleChoiceFilter(
field_name='type__slug', field_name='type__slug',
queryset=CircuitType.objects.all(), queryset=CircuitType.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Circuit type (slug)', label=_('Circuit type (slug)'),
) )
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=CircuitStatusChoices, choices=CircuitStatusChoices,
@ -145,38 +146,38 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='terminations__site__region', field_name='terminations__site__region',
lookup_expr='in', lookup_expr='in',
label='Region (ID)', label=_('Region (ID)'),
) )
region = TreeNodeMultipleChoiceFilter( region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='terminations__site__region', field_name='terminations__site__region',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Region (slug)', label=_('Region (slug)'),
) )
site_group_id = TreeNodeMultipleChoiceFilter( site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='terminations__site__group', field_name='terminations__site__group',
lookup_expr='in', lookup_expr='in',
label='Site group (ID)', label=_('Site group (ID)'),
) )
site_group = TreeNodeMultipleChoiceFilter( site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='terminations__site__group', field_name='terminations__site__group',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Site group (slug)', label=_('Site group (slug)'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
field_name='terminations__site', field_name='terminations__site',
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label=_('Site (ID)'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='terminations__site__slug', field_name='terminations__site__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
class Meta: class Meta:
@ -199,25 +200,25 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet): class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
circuit_id = django_filters.ModelMultipleChoiceFilter( circuit_id = django_filters.ModelMultipleChoiceFilter(
queryset=Circuit.objects.all(), queryset=Circuit.objects.all(),
label='Circuit', label=_('Circuit'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label=_('Site (ID)'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='site__slug', field_name='site__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
provider_network_id = django_filters.ModelMultipleChoiceFilter( provider_network_id = django_filters.ModelMultipleChoiceFilter(
queryset=ProviderNetwork.objects.all(), queryset=ProviderNetwork.objects.all(),
label='ProviderNetwork (ID)', label=_('ProviderNetwork (ID)'),
) )
class Meta: class Meta:

View File

@ -28,7 +28,7 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm):
account = forms.CharField( account = forms.CharField(
max_length=30, max_length=30,
required=False, required=False,
label='Account number' label=_('Account number')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -36,7 +36,7 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm):
) )
comments = CommentField( comments = CommentField(
widget=SmallTextarea, widget=SmallTextarea,
label='Comments' label=_('Comments')
) )
model = Provider model = Provider
@ -56,7 +56,7 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
service_id = forms.CharField( service_id = forms.CharField(
max_length=100, max_length=100,
required=False, required=False,
label='Service ID' label=_('Service ID')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -64,7 +64,7 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
) )
comments = CommentField( comments = CommentField(
widget=SmallTextarea, widget=SmallTextarea,
label='Comments' label=_('Comments')
) )
model = ProviderNetwork model = ProviderNetwork
@ -118,7 +118,7 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm):
) )
commit_rate = forms.IntegerField( commit_rate = forms.IntegerField(
required=False, required=False,
label='Commit rate (Kbps)' label=_('Commit rate (Kbps)')
) )
description = forms.CharField( description = forms.CharField(
max_length=100, max_length=100,
@ -126,7 +126,7 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm):
) )
comments = CommentField( comments = CommentField(
widget=SmallTextarea, widget=SmallTextarea,
label='Comments' label=_('Comments')
) )
model = Circuit model = Circuit

View File

@ -1,5 +1,6 @@
from circuits.choices import CircuitStatusChoices from circuits.choices import CircuitStatusChoices
from circuits.models import * from circuits.models import *
from django.utils.translation import gettext as _
from netbox.forms import NetBoxModelCSVForm from netbox.forms import NetBoxModelCSVForm
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField
@ -26,7 +27,7 @@ class ProviderNetworkCSVForm(NetBoxModelCSVForm):
provider = CSVModelChoiceField( provider = CSVModelChoiceField(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Assigned provider' help_text=_('Assigned provider')
) )
class Meta: class Meta:
@ -43,7 +44,7 @@ class CircuitTypeCSVForm(NetBoxModelCSVForm):
model = CircuitType model = CircuitType
fields = ('name', 'slug', 'description', 'tags') fields = ('name', 'slug', 'description', 'tags')
help_texts = { help_texts = {
'name': 'Name of circuit type', 'name': _('Name of circuit type'),
} }
@ -51,22 +52,22 @@ class CircuitCSVForm(NetBoxModelCSVForm):
provider = CSVModelChoiceField( provider = CSVModelChoiceField(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Assigned provider' help_text=_('Assigned provider')
) )
type = CSVModelChoiceField( type = CSVModelChoiceField(
queryset=CircuitType.objects.all(), queryset=CircuitType.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Type of circuit' help_text=_('Type of circuit')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=CircuitStatusChoices, choices=CircuitStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:

View File

@ -39,7 +39,7 @@ class ProviderForm(NetBoxModelForm):
'name', 'slug', 'account', 'asns', 'description', 'comments', 'tags', 'name', 'slug', 'account', 'asns', 'description', 'comments', 'tags',
] ]
help_texts = { help_texts = {
'name': "Full name of the provider", 'name': _("Full name of the provider"),
} }
@ -98,8 +98,8 @@ class CircuitForm(TenancyForm, NetBoxModelForm):
'tenant_group', 'tenant', 'comments', 'tags', 'tenant_group', 'tenant', 'comments', 'tags',
] ]
help_texts = { help_texts = {
'cid': "Unique circuit ID", 'cid': _("Unique circuit ID"),
'commit_rate': "Committed rate", 'commit_rate': _("Committed rate"),
} }
widgets = { widgets = {
'status': StaticSelect(), 'status': StaticSelect(),
@ -157,9 +157,9 @@ class CircuitTerminationForm(NetBoxModelForm):
'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'tags', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description', 'tags',
] ]
help_texts = { help_texts = {
'port_speed': "Physical circuit speed", 'port_speed': _("Physical circuit speed"),
'xconnect_id': "ID of the local cross-connect", 'xconnect_id': _("ID of the local cross-connect"),
'pp_info': "Patch panel ID and port number(s)" 'pp_info': _("Patch panel ID and port number(s)")
} }
widgets = { widgets = {
'term_side': StaticSelect(), 'term_side': StaticSelect(),

View File

@ -3,6 +3,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 circuits.choices import * from circuits.choices import *
from dcim.models import CabledObjectModel from dcim.models import CabledObjectModel
@ -168,7 +169,7 @@ class CircuitTermination(
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,

View File

@ -1,6 +1,7 @@
import decimal import decimal
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _
from drf_yasg.utils import swagger_serializer_method from drf_yasg.utils import swagger_serializer_method
from rest_framework import serializers from rest_framework import serializers
from timezone_field.rest_framework import TimeZoneSerializerField from timezone_field.rest_framework import TimeZoneSerializerField
@ -197,7 +198,7 @@ class RackSerializer(NetBoxModelSerializer):
status = ChoiceField(choices=RackStatusChoices, required=False) status = ChoiceField(choices=RackStatusChoices, required=False)
role = NestedRackRoleSerializer(required=False, allow_null=True) role = NestedRackRoleSerializer(required=False, allow_null=True)
type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False) type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False)
facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label='Facility ID', facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label=_('Facility ID'),
default=None) default=None)
width = ChoiceField(choices=RackWidthChoices, required=False) width = ChoiceField(choices=RackWidthChoices, required=False)
outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False) outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False)
@ -311,7 +312,7 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
u_height = serializers.DecimalField( u_height = serializers.DecimalField(
max_digits=4, max_digits=4,
decimal_places=1, decimal_places=1,
label='Position (U)', label=_('Position (U)'),
min_value=0, min_value=0,
default=1.0 default=1.0
) )
@ -636,7 +637,7 @@ class DeviceSerializer(NetBoxModelSerializer):
max_digits=4, max_digits=4,
decimal_places=1, decimal_places=1,
allow_null=True, allow_null=True,
label='Position (U)', label=_('Position (U)'),
min_value=decimal.Decimal(0.5), min_value=decimal.Decimal(0.5),
default=None default=None
) )

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,7 @@
from django import forms from django import forms
from dcim.models import * from dcim.models import *
from django.utils.translation import gettext as _
from extras.forms import CustomFieldsMixin from extras.forms import CustomFieldsMixin
from extras.models import Tag from extras.models import Tag
from utilities.forms import BootstrapMixin, DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model from utilities.forms import BootstrapMixin, DynamicModelMultipleChoiceField, ExpandableNameField, form_from_model
@ -105,9 +106,9 @@ class ModuleBayBulkCreateForm(DeviceBulkAddComponentForm):
field_order = ('name', 'label', 'position_pattern', 'description', 'tags') field_order = ('name', 'label', 'position_pattern', 'description', 'tags')
replication_fields = ('name', 'label', 'position') replication_fields = ('name', 'label', 'position')
position_pattern = ExpandableNameField( position_pattern = ExpandableNameField(
label='Position', label=_('Position'),
required=False, required=False,
help_text='Alphanumeric ranges are supported. (Must match the number of names being created.)' help_text=_('Alphanumeric ranges are supported. (Must match the number of names being created.)')
) )

View File

@ -1,6 +1,6 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import gettext as _
from timezone_field import TimeZoneFormField from timezone_field import TimeZoneFormField
from dcim.choices import * from dcim.choices import *
@ -126,7 +126,7 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm):
) )
contact_email = forms.EmailField( contact_email = forms.EmailField(
required=False, required=False,
label='Contact E-mail' label=_('Contact E-mail')
) )
time_zone = TimeZoneFormField( time_zone = TimeZoneFormField(
choices=add_blank_choice(TimeZoneFormField().choices), choices=add_blank_choice(TimeZoneFormField().choices),
@ -248,7 +248,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
serial = forms.CharField( serial = forms.CharField(
max_length=50, max_length=50,
required=False, required=False,
label='Serial Number' label=_('Serial Number')
) )
asset_tag = forms.CharField( asset_tag = forms.CharField(
max_length=50, max_length=50,
@ -266,12 +266,12 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
) )
u_height = forms.IntegerField( u_height = forms.IntegerField(
required=False, required=False,
label='Height (U)' label=_('Height (U)')
) )
desc_units = forms.NullBooleanField( desc_units = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect, widget=BulkEditNullBooleanSelect,
label='Descending units' label=_('Descending units')
) )
outer_width = forms.IntegerField( outer_width = forms.IntegerField(
required=False, required=False,
@ -380,7 +380,7 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
is_full_depth = forms.NullBooleanField( is_full_depth = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label='Is full depth' label=_('Is full depth')
) )
airflow = forms.ChoiceField( airflow = forms.ChoiceField(
choices=add_blank_choice(DeviceAirflowChoices), choices=add_blank_choice(DeviceAirflowChoices),
@ -456,7 +456,7 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
vm_role = forms.NullBooleanField( vm_role = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect, widget=BulkEditNullBooleanSelect,
label='VM role' label=_('VM role')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -540,7 +540,7 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm):
serial = forms.CharField( serial = forms.CharField(
max_length=50, max_length=50,
required=False, required=False,
label='Serial Number' label=_('Serial Number')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -577,7 +577,7 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm):
serial = forms.CharField( serial = forms.CharField(
max_length=50, max_length=50,
required=False, required=False,
label='Serial Number' label=_('Serial Number')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -767,7 +767,7 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
) )
comments = CommentField( comments = CommentField(
widget=SmallTextarea, widget=SmallTextarea,
label='Comments' label=_('Comments')
) )
model = PowerFeed model = PowerFeed
@ -838,12 +838,12 @@ class PowerPortTemplateBulkEditForm(BulkEditForm):
maximum_draw = forms.IntegerField( maximum_draw = forms.IntegerField(
min_value=1, min_value=1,
required=False, required=False,
help_text="Maximum power draw (watts)" help_text=_("Maximum power draw (watts)")
) )
allocated_draw = forms.IntegerField( allocated_draw = forms.IntegerField(
min_value=1, min_value=1,
required=False, required=False,
help_text="Allocated power draw (watts)" help_text=_("Allocated power draw (watts)")
) )
description = forms.CharField( description = forms.CharField(
required=False required=False
@ -916,7 +916,7 @@ class InterfaceTemplateBulkEditForm(BulkEditForm):
mgmt_only = forms.NullBooleanField( mgmt_only = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect, widget=BulkEditNullBooleanSelect,
label='Management only' label=_('Management only')
) )
description = forms.CharField( description = forms.CharField(
required=False required=False
@ -926,14 +926,14 @@ class InterfaceTemplateBulkEditForm(BulkEditForm):
required=False, required=False,
initial='', initial='',
widget=StaticSelect(), widget=StaticSelect(),
label='PoE mode' label=_('PoE mode')
) )
poe_type = forms.ChoiceField( poe_type = forms.ChoiceField(
choices=add_blank_choice(InterfacePoETypeChoices), choices=add_blank_choice(InterfacePoETypeChoices),
required=False, required=False,
initial='', initial='',
widget=StaticSelect(), widget=StaticSelect(),
label='PoE type' label=_('PoE type')
) )
nullable_fields = ('label', 'description', 'poe_mode', 'poe_type') nullable_fields = ('label', 'description', 'poe_mode', 'poe_type')
@ -1174,31 +1174,31 @@ class InterfaceBulkEditForm(
query_params={ query_params={
'type': 'lag', 'type': 'lag',
}, },
label='LAG' label=_('LAG')
) )
speed = forms.IntegerField( speed = forms.IntegerField(
required=False, required=False,
widget=SelectSpeedWidget(), widget=SelectSpeedWidget(),
label='Speed' label=_('Speed')
) )
mgmt_only = forms.NullBooleanField( mgmt_only = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect, widget=BulkEditNullBooleanSelect,
label='Management only' label=_('Management only')
) )
poe_mode = forms.ChoiceField( poe_mode = forms.ChoiceField(
choices=add_blank_choice(InterfacePoEModeChoices), choices=add_blank_choice(InterfacePoEModeChoices),
required=False, required=False,
initial='', initial='',
widget=StaticSelect(), widget=StaticSelect(),
label='PoE mode' label=_('PoE mode')
) )
poe_type = forms.ChoiceField( poe_type = forms.ChoiceField(
choices=add_blank_choice(InterfacePoETypeChoices), choices=add_blank_choice(InterfacePoETypeChoices),
required=False, required=False,
initial='', initial='',
widget=StaticSelect(), widget=StaticSelect(),
label='PoE type' label=_('PoE type')
) )
mark_connected = forms.NullBooleanField( mark_connected = forms.NullBooleanField(
required=False, required=False,
@ -1213,7 +1213,7 @@ class InterfaceBulkEditForm(
vlan_group = DynamicModelChoiceField( vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
label='VLAN group' label=_('VLAN group')
) )
untagged_vlan = DynamicModelChoiceField( untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
@ -1221,7 +1221,7 @@ class InterfaceBulkEditForm(
query_params={ query_params={
'group_id': '$vlan_group', 'group_id': '$vlan_group',
}, },
label='Untagged VLAN' label=_('Untagged VLAN')
) )
tagged_vlans = DynamicModelMultipleChoiceField( tagged_vlans = DynamicModelMultipleChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
@ -1229,12 +1229,12 @@ class InterfaceBulkEditForm(
query_params={ query_params={
'group_id': '$vlan_group', 'group_id': '$vlan_group',
}, },
label='Tagged VLANs' label=_('Tagged VLANs')
) )
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
model = Interface model = Interface

View File

@ -3,6 +3,7 @@ from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.forms.array import SimpleArrayField from django.contrib.postgres.forms.array import SimpleArrayField
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
@ -52,7 +53,7 @@ class RegionCSVForm(NetBoxModelCSVForm):
queryset=Region.objects.all(), queryset=Region.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Name of parent region' help_text=_('Name of parent region')
) )
class Meta: class Meta:
@ -65,7 +66,7 @@ class SiteGroupCSVForm(NetBoxModelCSVForm):
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Name of parent site group' help_text=_('Name of parent site group')
) )
class Meta: class Meta:
@ -76,25 +77,25 @@ class SiteGroupCSVForm(NetBoxModelCSVForm):
class SiteCSVForm(NetBoxModelCSVForm): class SiteCSVForm(NetBoxModelCSVForm):
status = CSVChoiceField( status = CSVChoiceField(
choices=SiteStatusChoices, choices=SiteStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
region = CSVModelChoiceField( region = CSVModelChoiceField(
queryset=Region.objects.all(), queryset=Region.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned region' help_text=_('Assigned region')
) )
group = CSVModelChoiceField( group = CSVModelChoiceField(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned group' help_text=_('Assigned group')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:
@ -105,7 +106,7 @@ class SiteCSVForm(NetBoxModelCSVForm):
) )
help_texts = { help_texts = {
'time_zone': mark_safe( 'time_zone': mark_safe(
'Time zone (<a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">available options</a>)' _('Time zone (<a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">available options</a>)')
) )
} }
@ -114,26 +115,26 @@ class LocationCSVForm(NetBoxModelCSVForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Assigned site' help_text=_('Assigned site')
) )
parent = CSVModelChoiceField( parent = CSVModelChoiceField(
queryset=Location.objects.all(), queryset=Location.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent location', help_text=_('Parent location'),
error_messages={ error_messages={
'invalid_choice': 'Location not found.', 'invalid_choice': _('Location not found.'),
} }
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=LocationStatusChoices, choices=LocationStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:
@ -148,7 +149,7 @@ class RackRoleCSVForm(NetBoxModelCSVForm):
model = RackRole model = RackRole
fields = ('name', 'slug', 'color', 'description', 'tags') fields = ('name', 'slug', 'color', 'description', 'tags')
help_texts = { help_texts = {
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'), 'color': mark_safe(_('RGB color in hexadecimal (e.g. <code>00ff00</code>)')),
} }
@ -166,31 +167,31 @@ class RackCSVForm(NetBoxModelCSVForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Name of assigned tenant' help_text=_('Name of assigned tenant')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=RackStatusChoices, choices=RackStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
role = CSVModelChoiceField( role = CSVModelChoiceField(
queryset=RackRole.objects.all(), queryset=RackRole.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Name of assigned role' help_text=_('Name of assigned role')
) )
type = CSVChoiceField( type = CSVChoiceField(
choices=RackTypeChoices, choices=RackTypeChoices,
required=False, required=False,
help_text='Rack type' help_text=_('Rack type')
) )
width = forms.ChoiceField( width = forms.ChoiceField(
choices=RackWidthChoices, choices=RackWidthChoices,
help_text='Rail-to-rail width (in inches)' help_text=_('Rail-to-rail width (in inches)')
) )
outer_unit = CSVChoiceField( outer_unit = CSVChoiceField(
choices=RackDimensionUnitChoices, choices=RackDimensionUnitChoices,
required=False, required=False,
help_text='Unit for outer dimensions' help_text=_('Unit for outer dimensions')
) )
class Meta: class Meta:
@ -215,29 +216,29 @@ class RackReservationCSVForm(NetBoxModelCSVForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Parent site' help_text=_('Parent site')
) )
location = CSVModelChoiceField( location = CSVModelChoiceField(
queryset=Location.objects.all(), queryset=Location.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text="Rack's location (if any)" help_text=_("Rack's location (if any)")
) )
rack = CSVModelChoiceField( rack = CSVModelChoiceField(
queryset=Rack.objects.all(), queryset=Rack.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Rack' help_text=_('Rack')
) )
units = SimpleArrayField( units = SimpleArrayField(
base_field=forms.IntegerField(), base_field=forms.IntegerField(),
required=True, required=True,
help_text='Comma-separated list of individual unit numbers' help_text=_('Comma-separated list of individual unit numbers')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:
@ -275,7 +276,7 @@ class DeviceRoleCSVForm(NetBoxModelCSVForm):
model = DeviceRole model = DeviceRole
fields = ('name', 'slug', 'color', 'vm_role', 'description', 'tags') fields = ('name', 'slug', 'color', 'vm_role', 'description', 'tags')
help_texts = { help_texts = {
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'), 'color': mark_safe(_('RGB color in hexadecimal (e.g. <code>00ff00</code>)')),
} }
@ -285,7 +286,7 @@ class PlatformCSVForm(NetBoxModelCSVForm):
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Limit platform assignments to this manufacturer' help_text=_('Limit platform assignments to this manufacturer')
) )
class Meta: class Meta:
@ -297,45 +298,45 @@ class BaseDeviceCSVForm(NetBoxModelCSVForm):
device_role = CSVModelChoiceField( device_role = CSVModelChoiceField(
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Assigned role' help_text=_('Assigned role')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
manufacturer = CSVModelChoiceField( manufacturer = CSVModelChoiceField(
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Device type manufacturer' help_text=_('Device type manufacturer')
) )
device_type = CSVModelChoiceField( device_type = CSVModelChoiceField(
queryset=DeviceType.objects.all(), queryset=DeviceType.objects.all(),
to_field_name='model', to_field_name='model',
help_text='Device type model' help_text=_('Device type model')
) )
platform = CSVModelChoiceField( platform = CSVModelChoiceField(
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned platform' help_text=_('Assigned platform')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=DeviceStatusChoices, choices=DeviceStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
virtual_chassis = CSVModelChoiceField( virtual_chassis = CSVModelChoiceField(
queryset=VirtualChassis.objects.all(), queryset=VirtualChassis.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Virtual chassis' help_text=_('Virtual chassis')
) )
cluster = CSVModelChoiceField( cluster = CSVModelChoiceField(
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Virtualization cluster' help_text=_('Virtualization cluster')
) )
class Meta: class Meta:
@ -360,29 +361,29 @@ class DeviceCSVForm(BaseDeviceCSVForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Assigned site' help_text=_('Assigned site')
) )
location = CSVModelChoiceField( location = CSVModelChoiceField(
queryset=Location.objects.all(), queryset=Location.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text="Assigned location (if any)" help_text=_("Assigned location (if any)")
) )
rack = CSVModelChoiceField( rack = CSVModelChoiceField(
queryset=Rack.objects.all(), queryset=Rack.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text="Assigned rack (if any)" help_text=_("Assigned rack (if any)")
) )
face = CSVChoiceField( face = CSVChoiceField(
choices=DeviceFaceChoices, choices=DeviceFaceChoices,
required=False, required=False,
help_text='Mounted rack face' help_text=_('Mounted rack face')
) )
airflow = CSVChoiceField( airflow = CSVChoiceField(
choices=DeviceAirflowChoices, choices=DeviceAirflowChoices,
required=False, required=False,
help_text='Airflow direction' help_text=_('Airflow direction')
) )
class Meta(BaseDeviceCSVForm.Meta): class Meta(BaseDeviceCSVForm.Meta):
@ -442,12 +443,12 @@ class ChildDeviceCSVForm(BaseDeviceCSVForm):
parent = CSVModelChoiceField( parent = CSVModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Parent device' help_text=_('Parent device')
) )
device_bay = CSVModelChoiceField( device_bay = CSVModelChoiceField(
queryset=DeviceBay.objects.all(), queryset=DeviceBay.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Device bay in which this device is installed' help_text=_('Device bay in which this device is installed')
) )
class Meta(BaseDeviceCSVForm.Meta): class Meta(BaseDeviceCSVForm.Meta):
@ -492,14 +493,14 @@ class ConsolePortCSVForm(NetBoxModelCSVForm):
type = CSVChoiceField( type = CSVChoiceField(
choices=ConsolePortTypeChoices, choices=ConsolePortTypeChoices,
required=False, required=False,
help_text='Port type' help_text=_('Port type')
) )
speed = CSVTypedChoiceField( speed = CSVTypedChoiceField(
choices=ConsolePortSpeedChoices, choices=ConsolePortSpeedChoices,
coerce=int, coerce=int,
empty_value=None, empty_value=None,
required=False, required=False,
help_text='Port speed in bps' help_text=_('Port speed in bps')
) )
class Meta: class Meta:
@ -515,14 +516,14 @@ class ConsoleServerPortCSVForm(NetBoxModelCSVForm):
type = CSVChoiceField( type = CSVChoiceField(
choices=ConsolePortTypeChoices, choices=ConsolePortTypeChoices,
required=False, required=False,
help_text='Port type' help_text=_('Port type')
) )
speed = CSVTypedChoiceField( speed = CSVTypedChoiceField(
choices=ConsolePortSpeedChoices, choices=ConsolePortSpeedChoices,
coerce=int, coerce=int,
empty_value=None, empty_value=None,
required=False, required=False,
help_text='Port speed in bps' help_text=_('Port speed in bps')
) )
class Meta: class Meta:
@ -538,7 +539,7 @@ class PowerPortCSVForm(NetBoxModelCSVForm):
type = CSVChoiceField( type = CSVChoiceField(
choices=PowerPortTypeChoices, choices=PowerPortTypeChoices,
required=False, required=False,
help_text='Port type' help_text=_('Port type')
) )
class Meta: class Meta:
@ -556,18 +557,18 @@ class PowerOutletCSVForm(NetBoxModelCSVForm):
type = CSVChoiceField( type = CSVChoiceField(
choices=PowerOutletTypeChoices, choices=PowerOutletTypeChoices,
required=False, required=False,
help_text='Outlet type' help_text=_('Outlet type')
) )
power_port = CSVModelChoiceField( power_port = CSVModelChoiceField(
queryset=PowerPort.objects.all(), queryset=PowerPort.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Local power port which feeds this outlet' help_text=_('Local power port which feeds this outlet')
) )
feed_leg = CSVChoiceField( feed_leg = CSVChoiceField(
choices=PowerOutletFeedLegChoices, choices=PowerOutletFeedLegChoices,
required=False, required=False,
help_text='Electrical phase (for three-phase circuits)' help_text=_('Electrical phase (for three-phase circuits)')
) )
class Meta: class Meta:
@ -606,23 +607,23 @@ class InterfaceCSVForm(NetBoxModelCSVForm):
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent interface' help_text=_('Parent interface')
) )
bridge = CSVModelChoiceField( bridge = CSVModelChoiceField(
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Bridged interface' help_text=_('Bridged interface')
) )
lag = CSVModelChoiceField( lag = CSVModelChoiceField(
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent LAG interface' help_text=_('Parent LAG interface')
) )
type = CSVChoiceField( type = CSVChoiceField(
choices=InterfaceTypeChoices, choices=InterfaceTypeChoices,
help_text='Physical medium' help_text=_('Physical medium')
) )
duplex = CSVChoiceField( duplex = CSVChoiceField(
choices=InterfaceDuplexChoices, choices=InterfaceDuplexChoices,
@ -631,28 +632,28 @@ class InterfaceCSVForm(NetBoxModelCSVForm):
poe_mode = CSVChoiceField( poe_mode = CSVChoiceField(
choices=InterfacePoEModeChoices, choices=InterfacePoEModeChoices,
required=False, required=False,
help_text='PoE mode' help_text=_('PoE mode')
) )
poe_type = CSVChoiceField( poe_type = CSVChoiceField(
choices=InterfacePoETypeChoices, choices=InterfacePoETypeChoices,
required=False, required=False,
help_text='PoE type' help_text=_('PoE type')
) )
mode = CSVChoiceField( mode = CSVChoiceField(
choices=InterfaceModeChoices, choices=InterfaceModeChoices,
required=False, required=False,
help_text='IEEE 802.1Q operational mode (for L2 interfaces)' help_text=_('IEEE 802.1Q operational mode (for L2 interfaces)')
) )
vrf = CSVModelChoiceField( vrf = CSVModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
to_field_name='rd', to_field_name='rd',
help_text='Assigned VRF' help_text=_('Assigned VRF')
) )
rf_role = CSVChoiceField( rf_role = CSVChoiceField(
choices=WirelessRoleChoices, choices=WirelessRoleChoices,
required=False, required=False,
help_text='Wireless role (AP/station)' help_text=_('Wireless role (AP/station)')
) )
class Meta: class Meta:
@ -692,11 +693,11 @@ class FrontPortCSVForm(NetBoxModelCSVForm):
rear_port = CSVModelChoiceField( rear_port = CSVModelChoiceField(
queryset=RearPort.objects.all(), queryset=RearPort.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Corresponding rear port' help_text=_('Corresponding rear port')
) )
type = CSVChoiceField( type = CSVChoiceField(
choices=PortTypeChoices, choices=PortTypeChoices,
help_text='Physical medium classification' help_text=_('Physical medium classification')
) )
class Meta: class Meta:
@ -706,7 +707,7 @@ class FrontPortCSVForm(NetBoxModelCSVForm):
'description', 'tags' 'description', 'tags'
) )
help_texts = { help_texts = {
'rear_port_position': 'Mapped position on corresponding rear port', 'rear_port_position': _('Mapped position on corresponding rear port'),
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -738,7 +739,7 @@ class RearPortCSVForm(NetBoxModelCSVForm):
to_field_name='name' to_field_name='name'
) )
type = CSVChoiceField( type = CSVChoiceField(
help_text='Physical medium classification', help_text=_('Physical medium classification'),
choices=PortTypeChoices, choices=PortTypeChoices,
) )
@ -746,7 +747,7 @@ class RearPortCSVForm(NetBoxModelCSVForm):
model = RearPort model = RearPort
fields = ('device', 'name', 'label', 'type', 'color', 'mark_connected', 'positions', 'description', 'tags') fields = ('device', 'name', 'label', 'type', 'color', 'mark_connected', 'positions', 'description', 'tags')
help_texts = { help_texts = {
'positions': 'Number of front ports which may be mapped' 'positions': _('Number of front ports which may be mapped')
} }
@ -770,9 +771,9 @@ class DeviceBayCSVForm(NetBoxModelCSVForm):
queryset=Device.objects.all(), queryset=Device.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Child device installed within this bay', help_text=_('Child device installed within this bay'),
error_messages={ error_messages={
'invalid_choice': 'Child device not found.', 'invalid_choice': _('Child device not found.'),
} }
) )
@ -826,7 +827,7 @@ class InventoryItemCSVForm(NetBoxModelCSVForm):
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Parent inventory item' help_text=_('Parent inventory item')
) )
class Meta: class Meta:
@ -863,7 +864,7 @@ class InventoryItemRoleCSVForm(NetBoxModelCSVForm):
model = InventoryItemRole model = InventoryItemRole
fields = ('name', 'slug', 'color', 'description') fields = ('name', 'slug', 'color', 'description')
help_texts = { help_texts = {
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'), 'color': mark_safe(_('RGB color in hexadecimal (e.g. <code>00ff00</code>)')),
} }
@ -876,53 +877,53 @@ class CableCSVForm(NetBoxModelCSVForm):
side_a_device = CSVModelChoiceField( side_a_device = CSVModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Side A device' help_text=_('Side A device')
) )
side_a_type = CSVContentTypeField( side_a_type = CSVContentTypeField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=CABLE_TERMINATION_MODELS, limit_choices_to=CABLE_TERMINATION_MODELS,
help_text='Side A type' help_text=_('Side A type')
) )
side_a_name = forms.CharField( side_a_name = forms.CharField(
help_text='Side A component name' help_text=_('Side A component name')
) )
# Termination B # Termination B
side_b_device = CSVModelChoiceField( side_b_device = CSVModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Side B device' help_text=_('Side B device')
) )
side_b_type = CSVContentTypeField( side_b_type = CSVContentTypeField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=CABLE_TERMINATION_MODELS, limit_choices_to=CABLE_TERMINATION_MODELS,
help_text='Side B type' help_text=_('Side B type')
) )
side_b_name = forms.CharField( side_b_name = forms.CharField(
help_text='Side B component name' help_text=_('Side B component name')
) )
# Cable attributes # Cable attributes
status = CSVChoiceField( status = CSVChoiceField(
choices=LinkStatusChoices, choices=LinkStatusChoices,
required=False, required=False,
help_text='Connection status' help_text=_('Connection status')
) )
type = CSVChoiceField( type = CSVChoiceField(
choices=CableTypeChoices, choices=CableTypeChoices,
required=False, required=False,
help_text='Physical medium classification' help_text=_('Physical medium classification')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
length_unit = CSVChoiceField( length_unit = CSVChoiceField(
choices=CableLengthUnitChoices, choices=CableLengthUnitChoices,
required=False, required=False,
help_text='Length unit' help_text=_('Length unit')
) )
class Meta: class Meta:
@ -932,7 +933,7 @@ class CableCSVForm(NetBoxModelCSVForm):
'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', 'comments', 'tags', 'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', 'comments', 'tags',
] ]
help_texts = { help_texts = {
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'), 'color': mark_safe(_('RGB color in hexadecimal (e.g. <code>00ff00</code>)')),
} }
def _clean_side(self, side): def _clean_side(self, side):
@ -981,7 +982,7 @@ class VirtualChassisCSVForm(NetBoxModelCSVForm):
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Master device' help_text=_('Master device')
) )
class Meta: class Meta:
@ -997,7 +998,7 @@ class PowerPanelCSVForm(NetBoxModelCSVForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Name of parent site' help_text=_('Name of parent site')
) )
location = CSVModelChoiceField( location = CSVModelChoiceField(
queryset=Location.objects.all(), queryset=Location.objects.all(),
@ -1023,40 +1024,40 @@ class PowerFeedCSVForm(NetBoxModelCSVForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Assigned site' help_text=_('Assigned site')
) )
power_panel = CSVModelChoiceField( power_panel = CSVModelChoiceField(
queryset=PowerPanel.objects.all(), queryset=PowerPanel.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Upstream power panel' help_text=_('Upstream power panel')
) )
location = CSVModelChoiceField( location = CSVModelChoiceField(
queryset=Location.objects.all(), queryset=Location.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text="Rack's location (if any)" help_text=_("Rack's location (if any)")
) )
rack = CSVModelChoiceField( rack = CSVModelChoiceField(
queryset=Rack.objects.all(), queryset=Rack.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Rack' help_text=_('Rack')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=PowerFeedStatusChoices, choices=PowerFeedStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
type = CSVChoiceField( type = CSVChoiceField(
choices=PowerFeedTypeChoices, choices=PowerFeedTypeChoices,
help_text='Primary or redundant' help_text=_('Primary or redundant')
) )
supply = CSVChoiceField( supply = CSVChoiceField(
choices=PowerFeedSupplyChoices, choices=PowerFeedSupplyChoices,
help_text='Supply type (AC/DC)' help_text=_('Supply type (AC/DC)')
) )
phase = CSVChoiceField( phase = CSVChoiceField(
choices=PowerFeedPhaseChoices, choices=PowerFeedPhaseChoices,
help_text='Single or three-phase' help_text=_('Single or three-phase')
) )
class Meta: class Meta:

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
@ -12,13 +13,13 @@ class InterfaceCommonForm(forms.Form):
mac_address = forms.CharField( mac_address = forms.CharField(
empty_value=None, empty_value=None,
required=False, required=False,
label='MAC address' label=_('MAC address')
) )
mtu = forms.IntegerField( mtu = forms.IntegerField(
required=False, required=False,
min_value=INTERFACE_MTU_MIN, min_value=INTERFACE_MTU_MIN,
max_value=INTERFACE_MTU_MAX, max_value=INTERFACE_MTU_MAX,
label='MTU' label=_('MTU')
) )
def clean(self): def clean(self):

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from circuits.models import Circuit, CircuitTermination, Provider from circuits.models import Circuit, CircuitTermination, Provider
from dcim.models import * from dcim.models import *
@ -16,7 +17,7 @@ def get_cable_form(a_type, b_type):
attrs[f'termination_{cable_end}_region'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_region'] = DynamicModelChoiceField(
queryset=Region.objects.all(), queryset=Region.objects.all(),
label='Region', label=_('Region'),
required=False, required=False,
initial_params={ initial_params={
'sites': f'$termination_{cable_end}_site' 'sites': f'$termination_{cable_end}_site'
@ -24,7 +25,7 @@ def get_cable_form(a_type, b_type):
) )
attrs[f'termination_{cable_end}_sitegroup'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_sitegroup'] = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
label='Site group', label=_('Site group'),
required=False, required=False,
initial_params={ initial_params={
'sites': f'$termination_{cable_end}_site' 'sites': f'$termination_{cable_end}_site'
@ -32,7 +33,7 @@ def get_cable_form(a_type, b_type):
) )
attrs[f'termination_{cable_end}_site'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_site'] = DynamicModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site', label=_('Site'),
required=False, required=False,
query_params={ query_params={
'region_id': f'$termination_{cable_end}_region', 'region_id': f'$termination_{cable_end}_region',
@ -41,7 +42,7 @@ def get_cable_form(a_type, b_type):
) )
attrs[f'termination_{cable_end}_location'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_location'] = DynamicModelChoiceField(
queryset=Location.objects.all(), queryset=Location.objects.all(),
label='Location', label=_('Location'),
required=False, required=False,
null_option='None', null_option='None',
query_params={ query_params={
@ -54,7 +55,7 @@ def get_cable_form(a_type, b_type):
attrs[f'termination_{cable_end}_rack'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_rack'] = DynamicModelChoiceField(
queryset=Rack.objects.all(), queryset=Rack.objects.all(),
label='Rack', label=_('Rack'),
required=False, required=False,
null_option='None', null_option='None',
initial_params={ initial_params={
@ -67,7 +68,7 @@ def get_cable_form(a_type, b_type):
) )
attrs[f'termination_{cable_end}_device'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_device'] = DynamicModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label='Device', label=_('Device'),
required=False, required=False,
initial_params={ initial_params={
f'{term_cls._meta.model_name}s__in': f'${cable_end}_terminations' f'{term_cls._meta.model_name}s__in': f'${cable_end}_terminations'
@ -93,7 +94,7 @@ def get_cable_form(a_type, b_type):
attrs[f'termination_{cable_end}_powerpanel'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_powerpanel'] = DynamicModelChoiceField(
queryset=PowerPanel.objects.all(), queryset=PowerPanel.objects.all(),
label='Power Panel', label=_('Power Panel'),
required=False, required=False,
initial_params={ initial_params={
'powerfeeds__in': f'${cable_end}_terminations' 'powerfeeds__in': f'${cable_end}_terminations'
@ -105,7 +106,7 @@ def get_cable_form(a_type, b_type):
) )
attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField(
queryset=term_cls.objects.all(), queryset=term_cls.objects.all(),
label='Power Feed', label=_('Power Feed'),
disabled_indicator='_occupied', disabled_indicator='_occupied',
query_params={ query_params={
'power_panel_id': f'$termination_{cable_end}_powerpanel', 'power_panel_id': f'$termination_{cable_end}_powerpanel',
@ -117,7 +118,7 @@ def get_cable_form(a_type, b_type):
attrs[f'termination_{cable_end}_provider'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_provider'] = DynamicModelChoiceField(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
label='Provider', label=_('Provider'),
initial_params={ initial_params={
'circuits': f'$termination_{cable_end}_circuit' 'circuits': f'$termination_{cable_end}_circuit'
}, },
@ -125,7 +126,7 @@ def get_cable_form(a_type, b_type):
) )
attrs[f'termination_{cable_end}_circuit'] = DynamicModelChoiceField( attrs[f'termination_{cable_end}_circuit'] = DynamicModelChoiceField(
queryset=Circuit.objects.all(), queryset=Circuit.objects.all(),
label='Circuit', label=_('Circuit'),
initial_params={ initial_params={
'terminations__in': f'${cable_end}_terminations' 'terminations__in': f'${cable_end}_terminations'
}, },
@ -136,7 +137,7 @@ def get_cable_form(a_type, b_type):
) )
attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField( attrs[f'{cable_end}_terminations'] = DynamicModelMultipleChoiceField(
queryset=term_cls.objects.all(), queryset=term_cls.objects.all(),
label='Side', label=_('Side'),
disabled_indicator='_occupied', disabled_indicator='_occupied',
query_params={ query_params={
'circuit_id': f'$termination_{cable_end}_circuit', 'circuit_id': f'$termination_{cable_end}_circuit',

View File

@ -1,7 +1,7 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _
from timezone_field import TimeZoneFormField from timezone_field import TimeZoneFormField
from dcim.choices import * from dcim.choices import *
@ -163,14 +163,14 @@ class SiteForm(TenancyForm, NetBoxModelForm):
'time_zone': StaticSelect(), 'time_zone': StaticSelect(),
} }
help_texts = { help_texts = {
'name': "Full name of the site", 'name': _("Full name of the site"),
'facility': "Data center provider and facility (e.g. Equinix NY7)", 'facility': _("Data center provider and facility (e.g. Equinix NY7)"),
'time_zone': "Local time zone", 'time_zone': _("Local time zone"),
'description': "Short description (will appear in sites list)", 'description': _("Short description (will appear in sites list)"),
'physical_address': "Physical location of the building (e.g. for GPS)", 'physical_address': _("Physical location of the building (e.g. for GPS)"),
'shipping_address': "If different from the physical address", 'shipping_address': _("If different from the physical address"),
'latitude': "Latitude in decimal format (xx.yyyyyy)", 'latitude': _("Latitude in decimal format (xx.yyyyyy)"),
'longitude': "Longitude in decimal format (xx.yyyyyy)" 'longitude': _("Longitude in decimal format (xx.yyyyyy)")
} }
@ -282,10 +282,10 @@ class RackForm(TenancyForm, NetBoxModelForm):
'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'description', 'comments', 'tags', 'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'description', 'comments', 'tags',
] ]
help_texts = { help_texts = {
'site': "The site at which the rack exists", 'site': _("The site at which the rack exists"),
'name': "Organizational rack name", 'name': _("Organizational rack name"),
'facility_id': "The unique rack ID assigned by the facility", 'facility_id': _("The unique rack ID assigned by the facility"),
'u_height': "Height in rack units", 'u_height': _("Height in rack units"),
} }
widgets = { widgets = {
'status': StaticSelect(), 'status': StaticSelect(),
@ -335,7 +335,7 @@ class RackReservationForm(TenancyForm, NetBoxModelForm):
) )
units = NumericArrayField( units = NumericArrayField(
base_field=forms.IntegerField(), base_field=forms.IntegerField(),
help_text="Comma-separated list of numeric unit IDs. A range may be specified using a hyphen." help_text=_("Comma-separated list of numeric unit IDs. A range may be specified using a hyphen.")
) )
user = forms.ModelChoiceField( user = forms.ModelChoiceField(
queryset=User.objects.order_by( queryset=User.objects.order_by(
@ -519,7 +519,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
) )
position = forms.DecimalField( position = forms.DecimalField(
required=False, required=False,
help_text="The lowest-numbered unit occupied by the device", help_text=_("The lowest-numbered unit occupied by the device"),
widget=APISelect( widget=APISelect(
api_url='/api/dcim/racks/{{rack}}/elevation/', api_url='/api/dcim/racks/{{rack}}/elevation/',
attrs={ attrs={
@ -577,13 +577,13 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
) )
vc_position = forms.IntegerField( vc_position = forms.IntegerField(
required=False, required=False,
label='Position', label=_('Position'),
help_text="The position in the virtual chassis this device is identified by" help_text=_("The position in the virtual chassis this device is identified by")
) )
vc_priority = forms.IntegerField( vc_priority = forms.IntegerField(
required=False, required=False,
label='Priority', label=_('Priority'),
help_text="The priority of the device in the virtual chassis" help_text=_("The priority of the device in the virtual chassis")
) )
class Meta: class Meta:
@ -595,10 +595,10 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
'description', 'comments', 'tags', 'local_context_data' 'description', 'comments', 'tags', 'local_context_data'
] ]
help_texts = { help_texts = {
'device_role': "The function this device serves", 'device_role': _("The function this device serves"),
'serial': "Chassis serial number", 'serial': _("Chassis serial number"),
'local_context_data': "Local config context data overwrites all source contexts in the final rendered " 'local_context_data': _("Local config context data overwrites all source contexts in the final rendered "
"config context", "config context"),
} }
widgets = { widgets = {
'face': StaticSelect(), 'face': StaticSelect(),
@ -695,13 +695,13 @@ class ModuleForm(NetBoxModelForm):
replicate_components = forms.BooleanField( replicate_components = forms.BooleanField(
required=False, required=False,
initial=True, initial=True,
help_text="Automatically populate components associated with this module type" help_text=_("Automatically populate components associated with this module type")
) )
adopt_components = forms.BooleanField( adopt_components = forms.BooleanField(
required=False, required=False,
initial=False, initial=False,
help_text="Adopt already existing components" help_text=_("Adopt already existing components")
) )
fieldsets = ( fieldsets = (
@ -1390,7 +1390,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
required=False, required=False,
label='Parent interface', label=_('Parent interface'),
query_params={ query_params={
'device_id': '$device', 'device_id': '$device',
} }
@ -1398,7 +1398,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
bridge = DynamicModelChoiceField( bridge = DynamicModelChoiceField(
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
required=False, required=False,
label='Bridged interface', label=_('Bridged interface'),
query_params={ query_params={
'device_id': '$device', 'device_id': '$device',
} }
@ -1406,7 +1406,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
lag = DynamicModelChoiceField( lag = DynamicModelChoiceField(
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
required=False, required=False,
label='LAG interface', label=_('LAG interface'),
query_params={ query_params={
'device_id': '$device', 'device_id': '$device',
'type': 'lag', 'type': 'lag',
@ -1415,12 +1415,12 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
wireless_lan_group = DynamicModelChoiceField( wireless_lan_group = DynamicModelChoiceField(
queryset=WirelessLANGroup.objects.all(), queryset=WirelessLANGroup.objects.all(),
required=False, required=False,
label='Wireless LAN group' label=_('Wireless LAN group')
) )
wireless_lans = DynamicModelMultipleChoiceField( wireless_lans = DynamicModelMultipleChoiceField(
queryset=WirelessLAN.objects.all(), queryset=WirelessLAN.objects.all(),
required=False, required=False,
label='Wireless LANs', label=_('Wireless LANs'),
query_params={ query_params={
'group_id': '$wireless_lan_group', 'group_id': '$wireless_lan_group',
} }
@ -1428,12 +1428,12 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
vlan_group = DynamicModelChoiceField( vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
label='VLAN group' label=_('VLAN group')
) )
untagged_vlan = DynamicModelChoiceField( untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
label='Untagged VLAN', label=_('Untagged VLAN'),
query_params={ query_params={
'group_id': '$vlan_group', 'group_id': '$vlan_group',
'available_on_device': '$device', 'available_on_device': '$device',
@ -1442,7 +1442,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
tagged_vlans = DynamicModelMultipleChoiceField( tagged_vlans = DynamicModelMultipleChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
label='Tagged VLANs', label=_('Tagged VLANs'),
query_params={ query_params={
'group_id': '$vlan_group', 'group_id': '$vlan_group',
'available_on_device': '$device', 'available_on_device': '$device',
@ -1451,13 +1451,13 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
wwn = forms.CharField( wwn = forms.CharField(
empty_value=None, empty_value=None,
required=False, required=False,
label='WWN' label=_('WWN')
) )
fieldsets = ( fieldsets = (
@ -1495,8 +1495,8 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
} }
help_texts = { help_texts = {
'mode': INTERFACE_MODE_HELP_TEXT, 'mode': INTERFACE_MODE_HELP_TEXT,
'rf_channel_frequency': "Populated by selected channel (if set)", 'rf_channel_frequency': _("Populated by selected channel (if set)"),
'rf_channel_width': "Populated by selected channel (if set)", 'rf_channel_width': _("Populated by selected channel (if set)"),
} }
@ -1570,8 +1570,8 @@ class DeviceBayForm(DeviceComponentForm):
class PopulateDeviceBayForm(BootstrapMixin, forms.Form): class PopulateDeviceBayForm(BootstrapMixin, forms.Form):
installed_device = forms.ModelChoiceField( installed_device = forms.ModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label='Child Device', label=_('Child Device'),
help_text="Child devices must first be created and assigned to the site/rack of the parent device.", help_text=_("Child devices must first be created and assigned to the site/rack of the parent device."),
widget=StaticSelect(), widget=StaticSelect(),
) )

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from dcim.models import * from dcim.models import *
from netbox.forms import NetBoxModelForm from netbox.forms import NetBoxModelForm
@ -39,7 +40,7 @@ class ComponentCreateForm(forms.Form):
name = ExpandableNameField() name = ExpandableNameField()
label = ExpandableNameField( label = ExpandableNameField(
required=False, required=False,
help_text='Alphanumeric ranges are supported. (Must match the number of objects being created.)' help_text=_('Alphanumeric ranges are supported. (Must match the number of objects being created.)')
) )
# Identify the fields which support replication (i.e. ExpandableNameFields). This is referenced by # Identify the fields which support replication (i.e. ExpandableNameFields). This is referenced by
@ -97,8 +98,8 @@ class InterfaceTemplateCreateForm(ComponentCreateForm, model_forms.InterfaceTemp
class FrontPortTemplateCreateForm(ComponentCreateForm, model_forms.FrontPortTemplateForm): class FrontPortTemplateCreateForm(ComponentCreateForm, model_forms.FrontPortTemplateForm):
rear_port = forms.MultipleChoiceField( rear_port = forms.MultipleChoiceField(
choices=[], choices=[],
label='Rear ports', label=_('Rear ports'),
help_text='Select one rear port assignment for each front port being created.', help_text=_('Select one rear port assignment for each front port being created.'),
) )
# Override fieldsets from FrontPortTemplateForm to omit rear_port_position # Override fieldsets from FrontPortTemplateForm to omit rear_port_position
@ -166,9 +167,9 @@ class DeviceBayTemplateCreateForm(ComponentCreateForm, model_forms.DeviceBayTemp
class ModuleBayTemplateCreateForm(ComponentCreateForm, model_forms.ModuleBayTemplateForm): class ModuleBayTemplateCreateForm(ComponentCreateForm, model_forms.ModuleBayTemplateForm):
position = ExpandableNameField( position = ExpandableNameField(
label='Position', label=_('Position'),
required=False, required=False,
help_text='Alphanumeric ranges are supported. (Must match the number of objects being created.)' help_text=_('Alphanumeric ranges are supported. (Must match the number of objects being created.)')
) )
replication_fields = ('name', 'label', 'position') replication_fields = ('name', 'label', 'position')
@ -226,8 +227,8 @@ class InterfaceCreateForm(ComponentCreateForm, model_forms.InterfaceForm):
class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm): class FrontPortCreateForm(ComponentCreateForm, model_forms.FrontPortForm):
rear_port = forms.MultipleChoiceField( rear_port = forms.MultipleChoiceField(
choices=[], choices=[],
label='Rear ports', label=_('Rear ports'),
help_text='Select one rear port assignment for each front port being created.', help_text=_('Select one rear port assignment for each front port being created.'),
) )
# Override fieldsets from FrontPortForm to omit rear_port_position # Override fieldsets from FrontPortForm to omit rear_port_position
@ -290,9 +291,9 @@ class DeviceBayCreateForm(ComponentCreateForm, model_forms.DeviceBayForm):
class ModuleBayCreateForm(ComponentCreateForm, model_forms.ModuleBayForm): class ModuleBayCreateForm(ComponentCreateForm, model_forms.ModuleBayForm):
position = ExpandableNameField( position = ExpandableNameField(
label='Position', label=_('Position'),
required=False, required=False,
help_text='Alphanumeric ranges are supported. (Must match the number of objects being created.)' help_text=_('Alphanumeric ranges are supported. (Must match the number of objects being created.)')
) )
replication_fields = ('name', 'label', 'position') replication_fields = ('name', 'label', 'position')
@ -352,7 +353,7 @@ class VirtualChassisCreateForm(NetBoxModelForm):
initial_position = forms.IntegerField( initial_position = forms.IntegerField(
initial=1, initial=1,
required=False, required=False,
help_text='Position of the first member device. Increases by one for each additional member.' help_text=_('Position of the first member device. Increases by one for each additional member.')
) )
class Meta: class Meta:

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices
from dcim.models import * from dcim.models import *
@ -115,12 +116,12 @@ class InterfaceTemplateImportForm(ComponentTemplateImportForm):
poe_mode = forms.ChoiceField( poe_mode = forms.ChoiceField(
choices=InterfacePoEModeChoices, choices=InterfacePoEModeChoices,
required=False, required=False,
label='PoE mode' label=_('PoE mode')
) )
poe_type = forms.ChoiceField( poe_type = forms.ChoiceField(
choices=InterfacePoETypeChoices, choices=InterfacePoETypeChoices,
required=False, required=False,
label='PoE type' label=_('PoE type')
) )
class Meta: class Meta:

View File

@ -3,6 +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 mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel, TreeForeignKey
from dcim.choices import * from dcim.choices import *
@ -52,7 +53,7 @@ class ComponentTemplateModel(WebhooksMixin, ChangeLoggedModel):
label = models.CharField( label = models.CharField(
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,
@ -222,13 +223,13 @@ class PowerPortTemplate(ModularComponentTemplateModel):
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.PositiveSmallIntegerField( allocated_draw = models.PositiveSmallIntegerField(
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
@ -283,7 +284,7 @@ class PowerOutletTemplate(ModularComponentTemplateModel):
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
@ -526,7 +527,7 @@ class ModuleBayTemplate(ComponentTemplateModel):
position = models.CharField( position = models.CharField(
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')
) )
component_model = ModuleBay component_model = ModuleBay
@ -621,7 +622,7 @@ class InventoryItemTemplate(MPTTModel, ComponentTemplateModel):
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')
) )
objects = TreeManager() objects = TreeManager()

View File

@ -7,6 +7,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.db.models import Sum from django.db.models import Sum
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext as _
from mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel, TreeForeignKey
from dcim.choices import * from dcim.choices import *
@ -60,7 +61,7 @@ class ComponentModel(NetBoxModel):
label = models.CharField( label = models.CharField(
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,
@ -129,7 +130,7 @@ class CabledObjectModel(models.Model):
) )
mark_connected = models.BooleanField( mark_connected = models.BooleanField(
default=False, default=False,
help_text="Treat as if a cable is connected" help_text=_("Treat as if a cable is connected")
) )
cable_terminations = GenericRelation( cable_terminations = GenericRelation(
@ -261,13 +262,13 @@ class ConsolePort(ModularComponentModel, CabledObjectModel, PathEndpoint):
max_length=50, max_length=50,
choices=ConsolePortTypeChoices, choices=ConsolePortTypeChoices,
blank=True, blank=True,
help_text='Physical port type' help_text=_('Physical port type')
) )
speed = models.PositiveIntegerField( speed = models.PositiveIntegerField(
choices=ConsolePortSpeedChoices, choices=ConsolePortSpeedChoices,
blank=True, blank=True,
null=True, null=True,
help_text='Port speed in bits per second' help_text=_('Port speed in bits per second')
) )
clone_fields = ('device', 'module', 'type', 'speed') clone_fields = ('device', 'module', 'type', 'speed')
@ -284,13 +285,13 @@ class ConsoleServerPort(ModularComponentModel, CabledObjectModel, PathEndpoint):
max_length=50, max_length=50,
choices=ConsolePortTypeChoices, choices=ConsolePortTypeChoices,
blank=True, blank=True,
help_text='Physical port type' help_text=_('Physical port type')
) )
speed = models.PositiveIntegerField( speed = models.PositiveIntegerField(
choices=ConsolePortSpeedChoices, choices=ConsolePortSpeedChoices,
blank=True, blank=True,
null=True, null=True,
help_text='Port speed in bits per second' help_text=_('Port speed in bits per second')
) )
clone_fields = ('device', 'module', 'type', 'speed') clone_fields = ('device', 'module', 'type', 'speed')
@ -311,19 +312,19 @@ class PowerPort(ModularComponentModel, CabledObjectModel, PathEndpoint):
max_length=50, max_length=50,
choices=PowerPortTypeChoices, choices=PowerPortTypeChoices,
blank=True, blank=True,
help_text='Physical port type' help_text=_('Physical port type')
) )
maximum_draw = models.PositiveSmallIntegerField( maximum_draw = models.PositiveSmallIntegerField(
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.PositiveSmallIntegerField( allocated_draw = models.PositiveSmallIntegerField(
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)")
) )
clone_fields = ('device', 'module', 'maximum_draw', 'allocated_draw') clone_fields = ('device', 'module', 'maximum_draw', 'allocated_draw')
@ -420,7 +421,7 @@ class PowerOutlet(ModularComponentModel, CabledObjectModel, PathEndpoint):
max_length=50, max_length=50,
choices=PowerOutletTypeChoices, choices=PowerOutletTypeChoices,
blank=True, blank=True,
help_text='Physical port type' help_text=_('Physical port type')
) )
power_port = models.ForeignKey( power_port = models.ForeignKey(
to='dcim.PowerPort', to='dcim.PowerPort',
@ -433,7 +434,7 @@ class PowerOutlet(ModularComponentModel, CabledObjectModel, PathEndpoint):
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)")
) )
clone_fields = ('device', 'module', 'type', 'power_port', 'feed_leg') clone_fields = ('device', 'module', 'type', 'power_port', 'feed_leg')
@ -550,7 +551,7 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd
mgmt_only = models.BooleanField( mgmt_only = models.BooleanField(
default=False, default=False,
verbose_name='Management only', verbose_name='Management only',
help_text='This interface is used only for out-of-band management' help_text=_('This interface is used only for out-of-band management')
) )
speed = models.PositiveIntegerField( speed = models.PositiveIntegerField(
blank=True, blank=True,
@ -567,7 +568,7 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd
null=True, null=True,
blank=True, blank=True,
verbose_name='WWN', verbose_name='WWN',
help_text='64-bit World Wide Name' help_text=_('64-bit World Wide Name')
) )
rf_role = models.CharField( rf_role = models.CharField(
max_length=30, max_length=30,
@ -970,7 +971,7 @@ class ModuleBay(ComponentModel):
position = models.CharField( position = models.CharField(
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')
) )
clone_fields = ('device',) clone_fields = ('device',)
@ -1084,7 +1085,7 @@ class InventoryItem(MPTTModel, ComponentModel):
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')
) )
serial = models.CharField( serial = models.CharField(
max_length=50, max_length=50,
@ -1097,11 +1098,11 @@ class InventoryItem(MPTTModel, ComponentModel):
blank=True, blank=True,
null=True, null=True,
verbose_name='Asset tag', verbose_name='Asset tag',
help_text='A unique tag used to identify this item' help_text=_('A unique tag used to identify this item')
) )
discovered = models.BooleanField( discovered = models.BooleanField(
default=False, default=False,
help_text='This item was automatically discovered' help_text=_('This item was automatically discovered')
) )
objects = TreeManager() objects = TreeManager()

View File

@ -12,6 +12,7 @@ from django.db.models import F, ProtectedError
from django.db.models.functions import Lower from django.db.models.functions import Lower
from django.urls import reverse from django.urls import reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
@ -84,7 +85,7 @@ class DeviceType(PrimaryModel, WeightMixin):
part_number = models.CharField( part_number = models.CharField(
max_length=50, max_length=50,
blank=True, blank=True,
help_text='Discrete part number (optional)' help_text=_('Discrete part number (optional)')
) )
u_height = models.DecimalField( u_height = models.DecimalField(
max_digits=4, max_digits=4,
@ -95,15 +96,15 @@ class DeviceType(PrimaryModel, WeightMixin):
is_full_depth = models.BooleanField( is_full_depth = models.BooleanField(
default=True, default=True,
verbose_name='Is full depth', verbose_name='Is full depth',
help_text='Device consumes both front and rear rack faces' help_text=_('Device consumes both front and rear rack faces')
) )
subdevice_role = models.CharField( subdevice_role = models.CharField(
max_length=50, max_length=50,
choices=SubdeviceRoleChoices, choices=SubdeviceRoleChoices,
blank=True, blank=True,
verbose_name='Parent/child status', verbose_name='Parent/child status',
help_text='Parent devices house child devices in device bays. Leave blank ' help_text=_('Parent devices house child devices in device bays. Leave blank '
'if this device type is neither a parent nor a child.' 'if this device type is neither a parent nor a child.')
) )
airflow = models.CharField( airflow = models.CharField(
max_length=50, max_length=50,
@ -314,7 +315,7 @@ class ModuleType(PrimaryModel, WeightMixin):
part_number = models.CharField( part_number = models.CharField(
max_length=50, max_length=50,
blank=True, blank=True,
help_text='Discrete part number (optional)' help_text=_('Discrete part number (optional)')
) )
# Generic relations # Generic relations
@ -400,7 +401,7 @@ class DeviceRole(OrganizationalModel):
vm_role = models.BooleanField( vm_role = models.BooleanField(
default=True, default=True,
verbose_name='VM Role', verbose_name='VM Role',
help_text='Virtual machines may be assigned to this role' help_text=_('Virtual machines may be assigned to this role')
) )
def get_absolute_url(self): def get_absolute_url(self):
@ -419,19 +420,19 @@ class Platform(OrganizationalModel):
related_name='platforms', related_name='platforms',
blank=True, blank=True,
null=True, null=True,
help_text='Optionally limit this platform to devices of a certain manufacturer' help_text=_('Optionally limit this platform to devices of a certain manufacturer')
) )
napalm_driver = models.CharField( napalm_driver = models.CharField(
max_length=50, max_length=50,
blank=True, blank=True,
verbose_name='NAPALM driver', verbose_name='NAPALM driver',
help_text='The name of the NAPALM driver to use when interacting with devices' help_text=_('The name of the NAPALM driver to use when interacting with devices')
) )
napalm_args = models.JSONField( napalm_args = models.JSONField(
blank=True, blank=True,
null=True, null=True,
verbose_name='NAPALM arguments', verbose_name='NAPALM arguments',
help_text='Additional arguments to pass when initiating the NAPALM driver (JSON format)' help_text=_('Additional arguments to pass when initiating the NAPALM driver (JSON format)')
) )
def get_absolute_url(self): def get_absolute_url(self):
@ -496,7 +497,7 @@ class Device(PrimaryModel, ConfigContextModel):
null=True, null=True,
unique=True, unique=True,
verbose_name='Asset tag', verbose_name='Asset tag',
help_text='A unique tag used to identify this device' help_text=_('A unique tag used to identify this device')
) )
site = models.ForeignKey( site = models.ForeignKey(
to='dcim.Site', to='dcim.Site',
@ -524,7 +525,7 @@ class Device(PrimaryModel, ConfigContextModel):
null=True, null=True,
validators=[MinValueValidator(1), MaxValueValidator(99.5)], validators=[MinValueValidator(1), MaxValueValidator(99.5)],
verbose_name='Position (U)', verbose_name='Position (U)',
help_text='The lowest-numbered unit occupied by the device' help_text=_('The lowest-numbered unit occupied by the device')
) )
face = models.CharField( face = models.CharField(
max_length=50, max_length=50,
@ -929,7 +930,7 @@ class Module(PrimaryModel, ConfigContextModel):
null=True, null=True,
unique=True, unique=True,
verbose_name='Asset tag', verbose_name='Asset tag',
help_text='A unique tag used to identify this device' help_text=_('A unique tag used to identify this device')
) )
clone_fields = ('device', 'module_type') clone_fields = ('device', 'module_type')

View File

@ -4,6 +4,7 @@ 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.urls import reverse from django.urls import reverse
from django.utils.translation import gettext as _
from dcim.choices import * from dcim.choices import *
from netbox.config import ConfigItem from netbox.config import ConfigItem
@ -125,7 +126,7 @@ class PowerFeed(PrimaryModel, PathEndpoint, CabledObjectModel):
max_utilization = models.PositiveSmallIntegerField( max_utilization = models.PositiveSmallIntegerField(
validators=[MinValueValidator(1), MaxValueValidator(100)], validators=[MinValueValidator(1), MaxValueValidator(100)],
default=ConfigItem('POWERFEED_DEFAULT_MAX_UTILIZATION'), default=ConfigItem('POWERFEED_DEFAULT_MAX_UTILIZATION'),
help_text="Maximum permissible draw (percentage)" help_text=_("Maximum permissible draw (percentage)")
) )
available_power = models.PositiveIntegerField( available_power = models.PositiveIntegerField(
default=0, default=0,

View File

@ -10,6 +10,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.db.models import Count from django.db.models import Count
from django.urls import reverse from django.urls import reverse
from django.utils.translation import gettext as _
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
@ -64,7 +65,7 @@ class Rack(PrimaryModel, WeightMixin):
blank=True, blank=True,
null=True, null=True,
verbose_name='Facility ID', verbose_name='Facility ID',
help_text='Locally-assigned identifier' help_text=_('Locally-assigned identifier')
) )
site = models.ForeignKey( site = models.ForeignKey(
to='dcim.Site', to='dcim.Site',
@ -96,7 +97,7 @@ class Rack(PrimaryModel, WeightMixin):
related_name='racks', related_name='racks',
blank=True, blank=True,
null=True, null=True,
help_text='Functional role' help_text=_('Functional role')
) )
serial = models.CharField( serial = models.CharField(
max_length=50, max_length=50,
@ -109,7 +110,7 @@ class Rack(PrimaryModel, WeightMixin):
null=True, null=True,
unique=True, unique=True,
verbose_name='Asset tag', verbose_name='Asset tag',
help_text='A unique tag used to identify this rack' help_text=_('A unique tag used to identify this rack')
) )
type = models.CharField( type = models.CharField(
choices=RackTypeChoices, choices=RackTypeChoices,
@ -121,28 +122,28 @@ class Rack(PrimaryModel, WeightMixin):
choices=RackWidthChoices, choices=RackWidthChoices,
default=RackWidthChoices.WIDTH_19IN, default=RackWidthChoices.WIDTH_19IN,
verbose_name='Width', verbose_name='Width',
help_text='Rail-to-rail width' help_text=_('Rail-to-rail width')
) )
u_height = models.PositiveSmallIntegerField( u_height = models.PositiveSmallIntegerField(
default=RACK_U_HEIGHT_DEFAULT, default=RACK_U_HEIGHT_DEFAULT,
verbose_name='Height (U)', verbose_name='Height (U)',
validators=[MinValueValidator(1), MaxValueValidator(100)], validators=[MinValueValidator(1), MaxValueValidator(100)],
help_text='Height in rack units' help_text=_('Height in rack units')
) )
desc_units = models.BooleanField( desc_units = models.BooleanField(
default=False, default=False,
verbose_name='Descending units', verbose_name='Descending units',
help_text='Units are numbered top-to-bottom' help_text=_('Units are numbered top-to-bottom')
) )
outer_width = models.PositiveSmallIntegerField( outer_width = models.PositiveSmallIntegerField(
blank=True, blank=True,
null=True, null=True,
help_text='Outer dimension of rack (width)' help_text=_('Outer dimension of rack (width)')
) )
outer_depth = models.PositiveSmallIntegerField( outer_depth = models.PositiveSmallIntegerField(
blank=True, blank=True,
null=True, null=True,
help_text='Outer dimension of rack (depth)' help_text=_('Outer dimension of rack (depth)')
) )
outer_unit = models.CharField( outer_unit = models.CharField(
max_length=50, max_length=50,
@ -153,8 +154,8 @@ class Rack(PrimaryModel, WeightMixin):
blank=True, blank=True,
null=True, null=True,
help_text=( help_text=(
'Maximum depth of a mounted device, in millimeters. For four-post racks, this is the ' _('Maximum depth of a mounted device, in millimeters. For four-post racks, this is the '
'distance between the front and rear rails.' 'distance between the front and rear rails.')
) )
) )

View File

@ -2,6 +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 timezone_field import TimeZoneField from timezone_field import TimeZoneField
from dcim.choices import * from dcim.choices import *
@ -178,7 +179,7 @@ class Site(PrimaryModel):
facility = models.CharField( facility = models.CharField(
max_length=50, max_length=50,
blank=True, blank=True,
help_text='Local facility ID or description' help_text=_('Local facility ID or description')
) )
asns = models.ManyToManyField( asns = models.ManyToManyField(
to='ipam.ASN', to='ipam.ASN',
@ -201,14 +202,14 @@ class Site(PrimaryModel):
decimal_places=6, decimal_places=6,
blank=True, blank=True,
null=True, null=True,
help_text='GPS coordinate (latitude)' help_text=_('GPS coordinate (latitude)')
) )
longitude = models.DecimalField( longitude = models.DecimalField(
max_digits=9, max_digits=9,
decimal_places=6, decimal_places=6,
blank=True, blank=True,
null=True, null=True,
help_text='GPS coordinate (longitude)' help_text=_('GPS coordinate (longitude)')
) )
# Generic relations # Generic relations

View File

@ -2,6 +2,7 @@ import django_filters
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet
@ -32,7 +33,7 @@ __all__ = (
class WebhookFilterSet(BaseFilterSet): class WebhookFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
content_type_id = MultiValueNumberFilter( content_type_id = MultiValueNumberFilter(
field_name='content_types__id' field_name='content_types__id'
@ -61,7 +62,7 @@ class WebhookFilterSet(BaseFilterSet):
class CustomFieldFilterSet(BaseFilterSet): class CustomFieldFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=CustomFieldTypeChoices choices=CustomFieldTypeChoices
@ -92,7 +93,7 @@ class CustomFieldFilterSet(BaseFilterSet):
class CustomLinkFilterSet(BaseFilterSet): class CustomLinkFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
content_type_id = MultiValueNumberFilter( content_type_id = MultiValueNumberFilter(
field_name='content_types__id' field_name='content_types__id'
@ -119,7 +120,7 @@ class CustomLinkFilterSet(BaseFilterSet):
class ExportTemplateFilterSet(BaseFilterSet): class ExportTemplateFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
content_type_id = MultiValueNumberFilter( content_type_id = MultiValueNumberFilter(
field_name='content_types__id' field_name='content_types__id'
@ -142,7 +143,7 @@ class ExportTemplateFilterSet(BaseFilterSet):
class SavedFilterFilterSet(BaseFilterSet): class SavedFilterFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
content_type_id = MultiValueNumberFilter( content_type_id = MultiValueNumberFilter(
field_name='content_types__id' field_name='content_types__id'
@ -150,13 +151,13 @@ class SavedFilterFilterSet(BaseFilterSet):
content_types = ContentTypeFilter() content_types = ContentTypeFilter()
user_id = django_filters.ModelMultipleChoiceFilter( user_id = django_filters.ModelMultipleChoiceFilter(
queryset=User.objects.all(), queryset=User.objects.all(),
label='User (ID)', label=_('User (ID)'),
) )
user = django_filters.ModelMultipleChoiceFilter( user = django_filters.ModelMultipleChoiceFilter(
field_name='user__username', field_name='user__username',
queryset=User.objects.all(), queryset=User.objects.all(),
to_field_name='username', to_field_name='username',
label='User (name)', label=_('User (name)'),
) )
usable = django_filters.BooleanFilter( usable = django_filters.BooleanFilter(
method='_usable' method='_usable'
@ -191,7 +192,7 @@ class SavedFilterFilterSet(BaseFilterSet):
class ImageAttachmentFilterSet(BaseFilterSet): class ImageAttachmentFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
created = django_filters.DateTimeFilter() created = django_filters.DateTimeFilter()
content_type = ContentTypeFilter() content_type = ContentTypeFilter()
@ -211,13 +212,13 @@ class JournalEntryFilterSet(NetBoxModelFilterSet):
assigned_object_type = ContentTypeFilter() assigned_object_type = ContentTypeFilter()
created_by_id = django_filters.ModelMultipleChoiceFilter( created_by_id = django_filters.ModelMultipleChoiceFilter(
queryset=User.objects.all(), queryset=User.objects.all(),
label='User (ID)', label=_('User (ID)'),
) )
created_by = django_filters.ModelMultipleChoiceFilter( created_by = django_filters.ModelMultipleChoiceFilter(
field_name='created_by__username', field_name='created_by__username',
queryset=User.objects.all(), queryset=User.objects.all(),
to_field_name='username', to_field_name='username',
label='User (name)', label=_('User (name)'),
) )
kind = django_filters.MultipleChoiceFilter( kind = django_filters.MultipleChoiceFilter(
choices=JournalEntryKindChoices choices=JournalEntryKindChoices
@ -236,7 +237,7 @@ class JournalEntryFilterSet(NetBoxModelFilterSet):
class TagFilterSet(ChangeLoggedModelFilterSet): class TagFilterSet(ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
content_type = MultiValueCharFilter( content_type = MultiValueCharFilter(
method='_content_type' method='_content_type'
@ -288,138 +289,138 @@ class TagFilterSet(ChangeLoggedModelFilterSet):
class ConfigContextFilterSet(ChangeLoggedModelFilterSet): class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
region_id = django_filters.ModelMultipleChoiceFilter( region_id = django_filters.ModelMultipleChoiceFilter(
field_name='regions', field_name='regions',
queryset=Region.objects.all(), queryset=Region.objects.all(),
label='Region', label=_('Region'),
) )
region = django_filters.ModelMultipleChoiceFilter( region = django_filters.ModelMultipleChoiceFilter(
field_name='regions__slug', field_name='regions__slug',
queryset=Region.objects.all(), queryset=Region.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Region (slug)', label=_('Region (slug)'),
) )
site_group = django_filters.ModelMultipleChoiceFilter( site_group = django_filters.ModelMultipleChoiceFilter(
field_name='site_groups__slug', field_name='site_groups__slug',
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site group (slug)', label=_('Site group (slug)'),
) )
site_group_id = django_filters.ModelMultipleChoiceFilter( site_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='site_groups', field_name='site_groups',
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
label='Site group', label=_('Site group'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
field_name='sites', field_name='sites',
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site', label=_('Site'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='sites__slug', field_name='sites__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
location_id = django_filters.ModelMultipleChoiceFilter( location_id = django_filters.ModelMultipleChoiceFilter(
field_name='locations', field_name='locations',
queryset=Location.objects.all(), queryset=Location.objects.all(),
label='Location', label=_('Location'),
) )
location = django_filters.ModelMultipleChoiceFilter( location = django_filters.ModelMultipleChoiceFilter(
field_name='locations__slug', field_name='locations__slug',
queryset=Location.objects.all(), queryset=Location.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Location (slug)', label=_('Location (slug)'),
) )
device_type_id = django_filters.ModelMultipleChoiceFilter( device_type_id = django_filters.ModelMultipleChoiceFilter(
field_name='device_types', field_name='device_types',
queryset=DeviceType.objects.all(), queryset=DeviceType.objects.all(),
label='Device type', label=_('Device type'),
) )
role_id = django_filters.ModelMultipleChoiceFilter( role_id = django_filters.ModelMultipleChoiceFilter(
field_name='roles', field_name='roles',
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
label='Role', label=_('Role'),
) )
role = django_filters.ModelMultipleChoiceFilter( role = django_filters.ModelMultipleChoiceFilter(
field_name='roles__slug', field_name='roles__slug',
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Role (slug)', label=_('Role (slug)'),
) )
platform_id = django_filters.ModelMultipleChoiceFilter( platform_id = django_filters.ModelMultipleChoiceFilter(
field_name='platforms', field_name='platforms',
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
label='Platform', label=_('Platform'),
) )
platform = django_filters.ModelMultipleChoiceFilter( platform = django_filters.ModelMultipleChoiceFilter(
field_name='platforms__slug', field_name='platforms__slug',
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Platform (slug)', label=_('Platform (slug)'),
) )
cluster_type_id = django_filters.ModelMultipleChoiceFilter( cluster_type_id = django_filters.ModelMultipleChoiceFilter(
field_name='cluster_types', field_name='cluster_types',
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
label='Cluster type', label=_('Cluster type'),
) )
cluster_type = django_filters.ModelMultipleChoiceFilter( cluster_type = django_filters.ModelMultipleChoiceFilter(
field_name='cluster_types__slug', field_name='cluster_types__slug',
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Cluster type (slug)', label=_('Cluster type (slug)'),
) )
cluster_group_id = django_filters.ModelMultipleChoiceFilter( cluster_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='cluster_groups', field_name='cluster_groups',
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
label='Cluster group', label=_('Cluster group'),
) )
cluster_group = django_filters.ModelMultipleChoiceFilter( cluster_group = django_filters.ModelMultipleChoiceFilter(
field_name='cluster_groups__slug', field_name='cluster_groups__slug',
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Cluster group (slug)', label=_('Cluster group (slug)'),
) )
cluster_id = django_filters.ModelMultipleChoiceFilter( cluster_id = django_filters.ModelMultipleChoiceFilter(
field_name='clusters', field_name='clusters',
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
label='Cluster', label=_('Cluster'),
) )
tenant_group_id = django_filters.ModelMultipleChoiceFilter( tenant_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='tenant_groups', field_name='tenant_groups',
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
label='Tenant group', label=_('Tenant group'),
) )
tenant_group = django_filters.ModelMultipleChoiceFilter( tenant_group = django_filters.ModelMultipleChoiceFilter(
field_name='tenant_groups__slug', field_name='tenant_groups__slug',
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Tenant group (slug)', label=_('Tenant group (slug)'),
) )
tenant_id = django_filters.ModelMultipleChoiceFilter( tenant_id = django_filters.ModelMultipleChoiceFilter(
field_name='tenants', field_name='tenants',
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
label='Tenant', label=_('Tenant'),
) )
tenant = django_filters.ModelMultipleChoiceFilter( tenant = django_filters.ModelMultipleChoiceFilter(
field_name='tenants__slug', field_name='tenants__slug',
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Tenant (slug)', label=_('Tenant (slug)'),
) )
tag_id = django_filters.ModelMultipleChoiceFilter( tag_id = django_filters.ModelMultipleChoiceFilter(
field_name='tags', field_name='tags',
queryset=Tag.objects.all(), queryset=Tag.objects.all(),
label='Tag', label=_('Tag'),
) )
tag = django_filters.ModelMultipleChoiceFilter( tag = django_filters.ModelMultipleChoiceFilter(
field_name='tags__slug', field_name='tags__slug',
queryset=Tag.objects.all(), queryset=Tag.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Tag (slug)', label=_('Tag (slug)'),
) )
class Meta: class Meta:
@ -443,7 +444,7 @@ class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
class LocalConfigContextFilterSet(django_filters.FilterSet): class LocalConfigContextFilterSet(django_filters.FilterSet):
local_context_data = django_filters.BooleanFilter( local_context_data = django_filters.BooleanFilter(
method='_local_context_data', method='_local_context_data',
label='Has local config context data', label=_('Has local config context data'),
) )
def _local_context_data(self, queryset, name, value): def _local_context_data(self, queryset, name, value):
@ -453,19 +454,19 @@ class LocalConfigContextFilterSet(django_filters.FilterSet):
class ObjectChangeFilterSet(BaseFilterSet): class ObjectChangeFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
time = django_filters.DateTimeFromToRangeFilter() time = django_filters.DateTimeFromToRangeFilter()
changed_object_type = ContentTypeFilter() changed_object_type = ContentTypeFilter()
user_id = django_filters.ModelMultipleChoiceFilter( user_id = django_filters.ModelMultipleChoiceFilter(
queryset=User.objects.all(), queryset=User.objects.all(),
label='User (ID)', label=_('User (ID)'),
) )
user = django_filters.ModelMultipleChoiceFilter( user = django_filters.ModelMultipleChoiceFilter(
field_name='user__username', field_name='user__username',
queryset=User.objects.all(), queryset=User.objects.all(),
to_field_name='username', to_field_name='username',
label='User name', label=_('User name'),
) )
class Meta: class Meta:
@ -491,7 +492,7 @@ class ObjectChangeFilterSet(BaseFilterSet):
class JobResultFilterSet(BaseFilterSet): class JobResultFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
created = django_filters.DateTimeFilter() created = django_filters.DateTimeFilter()
created__before = django_filters.DateTimeFilter( created__before = django_filters.DateTimeFilter(
@ -547,7 +548,7 @@ class JobResultFilterSet(BaseFilterSet):
class ContentTypeFilterSet(django_filters.FilterSet): class ContentTypeFilterSet(django_filters.FilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
class Meta: class Meta:

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from extras.choices import * from extras.choices import *
from extras.models import * from extras.models import *
@ -37,7 +38,7 @@ class CustomFieldBulkEditForm(BulkEditForm):
required=False required=False
) )
ui_visibility = forms.ChoiceField( ui_visibility = forms.ChoiceField(
label="UI visibility", label=_("UI visibility"),
choices=add_blank_choice(CustomFieldVisibilityChoices), choices=add_blank_choice(CustomFieldVisibilityChoices),
required=False, required=False,
initial='', initial='',
@ -143,23 +144,23 @@ class WebhookBulkEditForm(BulkEditForm):
http_method = forms.ChoiceField( http_method = forms.ChoiceField(
choices=add_blank_choice(WebhookHttpMethodChoices), choices=add_blank_choice(WebhookHttpMethodChoices),
required=False, required=False,
label='HTTP method' label=_('HTTP method')
) )
payload_url = forms.CharField( payload_url = forms.CharField(
required=False, required=False,
label='Payload URL' label=_('Payload URL')
) )
ssl_verification = forms.NullBooleanField( ssl_verification = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label='SSL verification' label=_('SSL verification')
) )
secret = forms.CharField( secret = forms.CharField(
required=False required=False
) )
ca_file_path = forms.CharField( ca_file_path = forms.CharField(
required=False, required=False,
label='CA file path' label=_('CA file path')
) )
nullable_fields = ('secret', 'conditions', 'ca_file_path') nullable_fields = ('secret', 'conditions', 'ca_file_path')

View File

@ -2,6 +2,7 @@ from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.forms import SimpleArrayField from django.contrib.postgres.forms import SimpleArrayField
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from extras.choices import CustomFieldVisibilityChoices, CustomFieldTypeChoices from extras.choices import CustomFieldVisibilityChoices, CustomFieldTypeChoices
from extras.models import * from extras.models import *
@ -22,26 +23,26 @@ class CustomFieldCSVForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
help_text="One or more assigned object types" help_text=_("One or more assigned object types")
) )
type = CSVChoiceField( type = CSVChoiceField(
choices=CustomFieldTypeChoices, choices=CustomFieldTypeChoices,
help_text='Field data type (e.g. text, integer, etc.)' help_text=_('Field data type (e.g. text, integer, etc.)')
) )
object_type = CSVContentTypeField( object_type = CSVContentTypeField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
required=False, required=False,
help_text="Object type (for object or multi-object fields)" help_text=_("Object type (for object or multi-object fields)")
) )
choices = SimpleArrayField( choices = SimpleArrayField(
base_field=forms.CharField(), base_field=forms.CharField(),
required=False, required=False,
help_text='Comma-separated list of field choices' help_text=_('Comma-separated list of field choices')
) )
ui_visibility = CSVChoiceField( ui_visibility = CSVChoiceField(
choices=CustomFieldVisibilityChoices, choices=CustomFieldVisibilityChoices,
help_text='How the custom field is displayed in the user interface' help_text=_('How the custom field is displayed in the user interface')
) )
class Meta: class Meta:
@ -57,7 +58,7 @@ class CustomLinkCSVForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_links'), limit_choices_to=FeatureQuery('custom_links'),
help_text="One or more assigned object types" help_text=_("One or more assigned object types")
) )
class Meta: class Meta:
@ -72,7 +73,7 @@ class ExportTemplateCSVForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('export_templates'), limit_choices_to=FeatureQuery('export_templates'),
help_text="One or more assigned object types" help_text=_("One or more assigned object types")
) )
class Meta: class Meta:
@ -85,7 +86,7 @@ class ExportTemplateCSVForm(CSVModelForm):
class SavedFilterCSVForm(CSVModelForm): class SavedFilterCSVForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
help_text="One or more assigned object types" help_text=_("One or more assigned object types")
) )
class Meta: class Meta:
@ -99,7 +100,7 @@ class WebhookCSVForm(CSVModelForm):
content_types = CSVMultipleContentTypeField( content_types = CSVMultipleContentTypeField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('webhooks'), limit_choices_to=FeatureQuery('webhooks'),
help_text="One or more assigned object types" help_text=_("One or more assigned object types")
) )
class Meta: class Meta:
@ -118,5 +119,5 @@ class TagCSVForm(CSVModelForm):
model = Tag model = Tag
fields = ('name', 'slug', 'color', 'description') fields = ('name', 'slug', 'color', 'description')
help_texts = { help_texts = {
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'), 'color': mark_safe(_('RGB color in hexadecimal (e.g. <code>00ff00</code>)')),
} }

View File

@ -41,7 +41,7 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
required=False, required=False,
label='Object type' label=_('Object type')
) )
type = MultipleChoiceField( type = MultipleChoiceField(
choices=CustomFieldTypeChoices, choices=CustomFieldTypeChoices,
@ -209,7 +209,7 @@ class WebhookFilterForm(SavedFiltersMixin, FilterForm):
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('webhooks'), limit_choices_to=FeatureQuery('webhooks'),
required=False, required=False,
label='Object type' label=_('Object type')
) )
http_method = MultipleChoiceField( http_method = MultipleChoiceField(
choices=WebhookHttpMethodChoices, choices=WebhookHttpMethodChoices,

View File

@ -1,5 +1,6 @@
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django import forms from django import forms
from django.utils.translation import gettext as _
from extras.models import * from extras.models import *
from extras.choices import CustomFieldVisibilityChoices from extras.choices import CustomFieldVisibilityChoices
@ -66,7 +67,7 @@ class SavedFiltersMixin(forms.Form):
filter = DynamicModelMultipleChoiceField( filter = DynamicModelMultipleChoiceField(
queryset=SavedFilter.objects.all(), queryset=SavedFilter.objects.all(),
required=False, required=False,
label='Saved Filter', label=_('Saved Filter'),
query_params={ query_params={
'usable': True, 'usable': True,
} }

View File

@ -1,6 +1,7 @@
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.http import QueryDict from django.http import QueryDict
from django.utils.translation import gettext as _
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
from extras.choices import * from extras.choices import *
@ -31,14 +32,14 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm):
content_types = ContentTypeMultipleChoiceField( content_types = ContentTypeMultipleChoiceField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
label='Model(s)' label=_('Model(s)')
) )
object_type = ContentTypeChoiceField( object_type = ContentTypeChoiceField(
queryset=ContentType.objects.all(), queryset=ContentType.objects.all(),
# TODO: Come up with a canonical way to register suitable models # TODO: Come up with a canonical way to register suitable models
limit_choices_to=FeatureQuery('webhooks'), limit_choices_to=FeatureQuery('webhooks'),
required=False, required=False,
help_text="Type of the related object (for object/multi-object fields only)" help_text=_("Type of the related object (for object/multi-object fields only)")
) )
fieldsets = ( fieldsets = (
@ -54,8 +55,8 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm):
model = CustomField model = CustomField
fields = '__all__' fields = '__all__'
help_texts = { help_texts = {
'type': "The type of data stored in this field. For object/multi-object fields, select the related object " 'type': _("The type of data stored in this field. For object/multi-object fields, select the related object "
"type below." "type below.")
} }
widgets = { widgets = {
'type': StaticSelect(), 'type': StaticSelect(),
@ -84,9 +85,9 @@ class CustomLinkForm(BootstrapMixin, forms.ModelForm):
'link_url': forms.Textarea(attrs={'class': 'font-monospace'}), 'link_url': forms.Textarea(attrs={'class': 'font-monospace'}),
} }
help_texts = { help_texts = {
'link_text': 'Jinja2 template code for the link text. Reference the object as <code>{{ object }}</code>. ' 'link_text': _('Jinja2 template code for the link text. Reference the object as <code>{{ object }}</code>. '
'Links which render as empty text will not be displayed.', 'Links which render as empty text will not be displayed.'),
'link_url': 'Jinja2 template code for the link URL. Reference the object as <code>{{ object }}</code>.', 'link_url': _('Jinja2 template code for the link URL. Reference the object as <code>{{ object }}</code>.'),
} }

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from utilities.forms import BootstrapMixin, DateTimePicker from utilities.forms import BootstrapMixin, DateTimePicker
@ -11,6 +12,6 @@ class ReportForm(BootstrapMixin, forms.Form):
schedule_at = forms.DateTimeField( schedule_at = forms.DateTimeField(
required=False, required=False,
widget=DateTimePicker(), widget=DateTimePicker(),
label="Schedule at", label=_("Schedule at"),
help_text="Schedule execution of report to a set time", help_text=_("Schedule execution of report to a set time"),
) )

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from utilities.forms import BootstrapMixin, DateTimePicker from utilities.forms import BootstrapMixin, DateTimePicker
@ -11,14 +12,14 @@ class ScriptForm(BootstrapMixin, forms.Form):
_commit = forms.BooleanField( _commit = forms.BooleanField(
required=False, required=False,
initial=True, initial=True,
label="Commit changes", label=_("Commit changes"),
help_text="Commit changes to the database (uncheck for a dry-run)" help_text=_("Commit changes to the database (uncheck for a dry-run)")
) )
_schedule_at = forms.DateTimeField( _schedule_at = forms.DateTimeField(
required=False, required=False,
widget=DateTimePicker(), widget=DateTimePicker(),
label="Schedule at", label=_("Schedule at"),
help_text="Schedule execution of script to a set time", help_text=_("Schedule execution of script to a set time"),
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@ -11,6 +11,7 @@ from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils.html import escape from django.utils.html import escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext as _
from extras.choices import * from extras.choices import *
from extras.utils import FeatureQuery from extras.utils import FeatureQuery
@ -57,25 +58,25 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge
to=ContentType, to=ContentType,
related_name='custom_fields', related_name='custom_fields',
limit_choices_to=FeatureQuery('custom_fields'), limit_choices_to=FeatureQuery('custom_fields'),
help_text='The object(s) to which this field applies.' help_text=_('The object(s) to which this field applies.')
) )
type = models.CharField( type = models.CharField(
max_length=50, max_length=50,
choices=CustomFieldTypeChoices, choices=CustomFieldTypeChoices,
default=CustomFieldTypeChoices.TYPE_TEXT, default=CustomFieldTypeChoices.TYPE_TEXT,
help_text='The type of data this custom field holds' help_text=_('The type of data this custom field holds')
) )
object_type = models.ForeignKey( object_type = models.ForeignKey(
to=ContentType, to=ContentType,
on_delete=models.PROTECT, on_delete=models.PROTECT,
blank=True, blank=True,
null=True, null=True,
help_text='The type of NetBox object this field maps to (for object fields)' help_text=_('The type of NetBox object this field maps to (for object fields)')
) )
name = models.CharField( name = models.CharField(
max_length=50, max_length=50,
unique=True, unique=True,
help_text='Internal field name', help_text=_('Internal field name'),
validators=( validators=(
RegexValidator( RegexValidator(
regex=r'^[a-z0-9_]+$', regex=r'^[a-z0-9_]+$',
@ -87,13 +88,13 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge
label = models.CharField( label = models.CharField(
max_length=50, max_length=50,
blank=True, blank=True,
help_text='Name of the field as displayed to users (if not provided, ' help_text=_('Name of the field as displayed to users (if not provided, '
'the field\'s name will be used)' 'the field\'s name will be used)')
) )
group_name = models.CharField( group_name = models.CharField(
max_length=50, max_length=50,
blank=True, blank=True,
help_text="Custom fields within the same group will be displayed together" help_text=_("Custom fields within the same group will be displayed together")
) )
description = models.CharField( description = models.CharField(
max_length=200, max_length=200,
@ -101,64 +102,64 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge
) )
required = models.BooleanField( required = models.BooleanField(
default=False, default=False,
help_text='If true, this field is required when creating new objects ' help_text=_('If true, this field is required when creating new objects '
'or editing an existing object.' 'or editing an existing object.')
) )
search_weight = models.PositiveSmallIntegerField( search_weight = models.PositiveSmallIntegerField(
default=1000, default=1000,
help_text='Weighting for search. Lower values are considered more important. ' help_text=_('Weighting for search. Lower values are considered more important. '
'Fields with a search weight of zero will be ignored.' 'Fields with a search weight of zero will be ignored.')
) )
filter_logic = models.CharField( filter_logic = models.CharField(
max_length=50, max_length=50,
choices=CustomFieldFilterLogicChoices, choices=CustomFieldFilterLogicChoices,
default=CustomFieldFilterLogicChoices.FILTER_LOOSE, default=CustomFieldFilterLogicChoices.FILTER_LOOSE,
help_text='Loose matches any instance of a given string; exact ' help_text=_('Loose matches any instance of a given string; exact '
'matches the entire field.' 'matches the entire field.')
) )
default = models.JSONField( default = models.JSONField(
blank=True, blank=True,
null=True, null=True,
help_text='Default value for the field (must be a JSON value). Encapsulate ' help_text=_('Default value for the field (must be a JSON value). Encapsulate '
'strings with double quotes (e.g. "Foo").' 'strings with double quotes (e.g. "Foo").')
) )
weight = models.PositiveSmallIntegerField( weight = models.PositiveSmallIntegerField(
default=100, default=100,
verbose_name='Display weight', verbose_name='Display weight',
help_text='Fields with higher weights appear lower in a form.' help_text=_('Fields with higher weights appear lower in a form.')
) )
validation_minimum = models.IntegerField( validation_minimum = models.IntegerField(
blank=True, blank=True,
null=True, null=True,
verbose_name='Minimum value', verbose_name='Minimum value',
help_text='Minimum allowed value (for numeric fields)' help_text=_('Minimum allowed value (for numeric fields)')
) )
validation_maximum = models.IntegerField( validation_maximum = models.IntegerField(
blank=True, blank=True,
null=True, null=True,
verbose_name='Maximum value', verbose_name='Maximum value',
help_text='Maximum allowed value (for numeric fields)' help_text=_('Maximum allowed value (for numeric fields)')
) )
validation_regex = models.CharField( validation_regex = models.CharField(
blank=True, blank=True,
validators=[validate_regex], validators=[validate_regex],
max_length=500, max_length=500,
verbose_name='Validation regex', verbose_name='Validation regex',
help_text='Regular expression to enforce on text field values. Use ^ and $ to force matching of entire string. ' help_text=_('Regular expression to enforce on text field values. Use ^ and $ to force matching of entire string. '
'For example, <code>^[A-Z]{3}$</code> will limit values to exactly three uppercase letters.' 'For example, <code>^[A-Z]{3}$</code> will limit values to exactly three uppercase letters.')
) )
choices = ArrayField( choices = ArrayField(
base_field=models.CharField(max_length=100), base_field=models.CharField(max_length=100),
blank=True, blank=True,
null=True, null=True,
help_text='Comma-separated list of available choices (for selection fields)' help_text=_('Comma-separated list of available choices (for selection fields)')
) )
ui_visibility = models.CharField( ui_visibility = models.CharField(
max_length=50, max_length=50,
choices=CustomFieldVisibilityChoices, choices=CustomFieldVisibilityChoices,
default=CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE, default=CustomFieldVisibilityChoices.VISIBILITY_READ_WRITE,
verbose_name='UI visibility', verbose_name='UI visibility',
help_text='Specifies the visibility of custom field in the UI' help_text=_('Specifies the visibility of custom field in the UI')
) )
objects = CustomFieldManager() objects = CustomFieldManager()

View File

@ -12,6 +12,7 @@ from django.http import HttpResponse, QueryDict
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from django.utils.formats import date_format from django.utils.formats import date_format
from django.utils.translation import gettext as _
from rest_framework.utils.encoders import JSONEncoder from rest_framework.utils.encoders import JSONEncoder
import django_rq import django_rq
@ -51,7 +52,7 @@ class Webhook(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
related_name='webhooks', related_name='webhooks',
verbose_name='Object types', verbose_name='Object types',
limit_choices_to=FeatureQuery('webhooks'), limit_choices_to=FeatureQuery('webhooks'),
help_text="The object(s) to which this Webhook applies." help_text=_("The object(s) to which this Webhook applies.")
) )
name = models.CharField( name = models.CharField(
max_length=150, max_length=150,
@ -59,21 +60,21 @@ class Webhook(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
) )
type_create = models.BooleanField( type_create = models.BooleanField(
default=False, default=False,
help_text="Call this webhook when a matching object is created." help_text=_("Call this webhook when a matching object is created.")
) )
type_update = models.BooleanField( type_update = models.BooleanField(
default=False, default=False,
help_text="Call this webhook when a matching object is updated." help_text=_("Call this webhook when a matching object is updated.")
) )
type_delete = models.BooleanField( type_delete = models.BooleanField(
default=False, default=False,
help_text="Call this webhook when a matching object is deleted." help_text=_("Call this webhook when a matching object is deleted.")
) )
payload_url = models.CharField( payload_url = models.CharField(
max_length=500, max_length=500,
verbose_name='URL', verbose_name='URL',
help_text='This URL will be called using the HTTP method defined when the webhook is called. ' help_text=_('This URL will be called using the HTTP method defined when the webhook is called. '
'Jinja2 template processing is supported with the same context as the request body.' 'Jinja2 template processing is supported with the same context as the request body.')
) )
enabled = models.BooleanField( enabled = models.BooleanField(
default=True default=True
@ -88,46 +89,46 @@ class Webhook(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
max_length=100, max_length=100,
default=HTTP_CONTENT_TYPE_JSON, default=HTTP_CONTENT_TYPE_JSON,
verbose_name='HTTP content type', verbose_name='HTTP content type',
help_text='The complete list of official content types is available ' help_text=_('The complete list of official content types is available '
'<a href="https://www.iana.org/assignments/media-types/media-types.xhtml">here</a>.' '<a href="https://www.iana.org/assignments/media-types/media-types.xhtml">here</a>.')
) )
additional_headers = models.TextField( additional_headers = models.TextField(
blank=True, blank=True,
help_text="User-supplied HTTP headers to be sent with the request in addition to the HTTP content type. " help_text=_("User-supplied HTTP headers to be sent with the request in addition to the HTTP content type. "
"Headers should be defined in the format <code>Name: Value</code>. Jinja2 template processing is " "Headers should be defined in the format <code>Name: Value</code>. Jinja2 template processing is "
"supported with the same context as the request body (below)." "supported with the same context as the request body (below).")
) )
body_template = models.TextField( body_template = models.TextField(
blank=True, blank=True,
help_text='Jinja2 template for a custom request body. If blank, a JSON object representing the change will be ' help_text=_('Jinja2 template for a custom request body. If blank, a JSON object representing the change will be '
'included. Available context data includes: <code>event</code>, <code>model</code>, ' 'included. Available context data includes: <code>event</code>, <code>model</code>, '
'<code>timestamp</code>, <code>username</code>, <code>request_id</code>, and <code>data</code>.' '<code>timestamp</code>, <code>username</code>, <code>request_id</code>, and <code>data</code>.')
) )
secret = models.CharField( secret = models.CharField(
max_length=255, max_length=255,
blank=True, blank=True,
help_text="When provided, the request will include a 'X-Hook-Signature' " help_text=_("When provided, the request will include a 'X-Hook-Signature' "
"header containing a HMAC hex digest of the payload body using " "header containing a HMAC hex digest of the payload body using "
"the secret as the key. The secret is not transmitted in " "the secret as the key. The secret is not transmitted in "
"the request." "the request.")
) )
conditions = models.JSONField( conditions = models.JSONField(
blank=True, blank=True,
null=True, null=True,
help_text="A set of conditions which determine whether the webhook will be generated." help_text=_("A set of conditions which determine whether the webhook will be generated.")
) )
ssl_verification = models.BooleanField( ssl_verification = models.BooleanField(
default=True, default=True,
verbose_name='SSL verification', verbose_name='SSL verification',
help_text="Enable SSL certificate verification. Disable with caution!" help_text=_("Enable SSL certificate verification. Disable with caution!")
) )
ca_file_path = models.CharField( ca_file_path = models.CharField(
max_length=4096, max_length=4096,
null=True, null=True,
blank=True, blank=True,
verbose_name='CA File Path', verbose_name='CA File Path',
help_text='The specific CA certificate file to use for SSL verification. ' help_text=_('The specific CA certificate file to use for SSL verification. '
'Leave blank to use the system defaults.' 'Leave blank to use the system defaults.')
) )
class Meta: class Meta:
@ -201,7 +202,7 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogged
content_types = models.ManyToManyField( content_types = models.ManyToManyField(
to=ContentType, to=ContentType,
related_name='custom_links', related_name='custom_links',
help_text='The object type(s) to which this link applies.' help_text=_('The object type(s) to which this link applies.')
) )
name = models.CharField( name = models.CharField(
max_length=100, max_length=100,
@ -211,11 +212,11 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogged
default=True default=True
) )
link_text = models.TextField( link_text = models.TextField(
help_text="Jinja2 template code for link text" help_text=_("Jinja2 template code for link text")
) )
link_url = models.TextField( link_url = models.TextField(
verbose_name='Link URL', verbose_name='Link URL',
help_text="Jinja2 template code for link URL" help_text=_("Jinja2 template code for link URL")
) )
weight = models.PositiveSmallIntegerField( weight = models.PositiveSmallIntegerField(
default=100 default=100
@ -223,17 +224,17 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogged
group_name = models.CharField( group_name = models.CharField(
max_length=50, max_length=50,
blank=True, blank=True,
help_text="Links with the same group will appear as a dropdown menu" help_text=_("Links with the same group will appear as a dropdown menu")
) )
button_class = models.CharField( button_class = models.CharField(
max_length=30, max_length=30,
choices=CustomLinkButtonClassChoices, choices=CustomLinkButtonClassChoices,
default=CustomLinkButtonClassChoices.DEFAULT, default=CustomLinkButtonClassChoices.DEFAULT,
help_text="The class of the first link in a group will be used for the dropdown button" help_text=_("The class of the first link in a group will be used for the dropdown button")
) )
new_window = models.BooleanField( new_window = models.BooleanField(
default=False, default=False,
help_text="Force link to open in a new window" help_text=_("Force link to open in a new window")
) )
clone_fields = ( clone_fields = (
@ -272,7 +273,7 @@ class ExportTemplate(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
content_types = models.ManyToManyField( content_types = models.ManyToManyField(
to=ContentType, to=ContentType,
related_name='export_templates', related_name='export_templates',
help_text='The object type(s) to which this template applies.' help_text=_('The object type(s) to which this template applies.')
) )
name = models.CharField( name = models.CharField(
max_length=100 max_length=100
@ -282,23 +283,23 @@ class ExportTemplate(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
blank=True blank=True
) )
template_code = models.TextField( template_code = models.TextField(
help_text='Jinja2 template code. The list of objects being exported is passed as a context variable named ' help_text=_('Jinja2 template code. The list of objects being exported is passed as a context variable named '
'<code>queryset</code>.' '<code>queryset</code>.')
) )
mime_type = models.CharField( mime_type = models.CharField(
max_length=50, max_length=50,
blank=True, blank=True,
verbose_name='MIME type', verbose_name='MIME type',
help_text='Defaults to <code>text/plain</code>' help_text=_('Defaults to <code>text/plain</code>')
) )
file_extension = models.CharField( file_extension = models.CharField(
max_length=15, max_length=15,
blank=True, blank=True,
help_text='Extension to append to the rendered filename' help_text=_('Extension to append to the rendered filename')
) )
as_attachment = models.BooleanField( as_attachment = models.BooleanField(
default=True, default=True,
help_text="Download file as attachment" help_text=_("Download file as attachment")
) )
class Meta: class Meta:
@ -358,7 +359,7 @@ class SavedFilter(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge
content_types = models.ManyToManyField( content_types = models.ManyToManyField(
to=ContentType, to=ContentType,
related_name='saved_filters', related_name='saved_filters',
help_text='The object type(s) to which this filter applies.' help_text=_('The object type(s) to which this filter applies.')
) )
name = models.CharField( name = models.CharField(
max_length=100, max_length=100,
@ -553,7 +554,7 @@ class JobResult(models.Model):
related_name='job_results', related_name='job_results',
verbose_name='Object types', verbose_name='Object types',
limit_choices_to=FeatureQuery('job_results'), limit_choices_to=FeatureQuery('job_results'),
help_text="The object type to which this job result applies", help_text=_("The object type to which this job result applies"),
on_delete=models.CASCADE, on_delete=models.CASCADE,
) )
created = models.DateTimeField( created = models.DateTimeField(

View File

@ -1,3 +1,4 @@
from django.utils.translation import gettext as _
from extras.plugins import PluginMenu, PluginMenuButton, PluginMenuItem from extras.plugins import PluginMenu, PluginMenuButton, PluginMenuItem
@ -25,7 +26,7 @@ items = (
) )
menu = PluginMenu( menu = PluginMenu(
label='Dummy', label=_('Dummy'),
groups=(('Group 1', items),), groups=(('Group 1', items),),
) )
menu_items = items menu_items = items

View File

@ -3,6 +3,7 @@ import netaddr
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _
from netaddr.core import AddrFormatError from netaddr.core import AddrFormatError
from dcim.models import Device, Interface, Region, Site, SiteGroup from dcim.models import Device, Interface, Region, Site, SiteGroup
@ -41,24 +42,24 @@ class VRFFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
import_target_id = django_filters.ModelMultipleChoiceFilter( import_target_id = django_filters.ModelMultipleChoiceFilter(
field_name='import_targets', field_name='import_targets',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
label='Import target', label=_('Import target'),
) )
import_target = django_filters.ModelMultipleChoiceFilter( import_target = django_filters.ModelMultipleChoiceFilter(
field_name='import_targets__name', field_name='import_targets__name',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
to_field_name='name', to_field_name='name',
label='Import target (name)', label=_('Import target (name)'),
) )
export_target_id = django_filters.ModelMultipleChoiceFilter( export_target_id = django_filters.ModelMultipleChoiceFilter(
field_name='export_targets', field_name='export_targets',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
label='Export target', label=_('Export target'),
) )
export_target = django_filters.ModelMultipleChoiceFilter( export_target = django_filters.ModelMultipleChoiceFilter(
field_name='export_targets__name', field_name='export_targets__name',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
to_field_name='name', to_field_name='name',
label='Export target (name)', label=_('Export target (name)'),
) )
def search(self, queryset, name, value): def search(self, queryset, name, value):
@ -79,24 +80,24 @@ class RouteTargetFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
importing_vrf_id = django_filters.ModelMultipleChoiceFilter( importing_vrf_id = django_filters.ModelMultipleChoiceFilter(
field_name='importing_vrfs', field_name='importing_vrfs',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
label='Importing VRF', label=_('Importing VRF'),
) )
importing_vrf = django_filters.ModelMultipleChoiceFilter( importing_vrf = django_filters.ModelMultipleChoiceFilter(
field_name='importing_vrfs__rd', field_name='importing_vrfs__rd',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='rd', to_field_name='rd',
label='Import VRF (RD)', label=_('Import VRF (RD)'),
) )
exporting_vrf_id = django_filters.ModelMultipleChoiceFilter( exporting_vrf_id = django_filters.ModelMultipleChoiceFilter(
field_name='exporting_vrfs', field_name='exporting_vrfs',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
label='Exporting VRF', label=_('Exporting VRF'),
) )
exporting_vrf = django_filters.ModelMultipleChoiceFilter( exporting_vrf = django_filters.ModelMultipleChoiceFilter(
field_name='exporting_vrfs__rd', field_name='exporting_vrfs__rd',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='rd', to_field_name='rd',
label='Export VRF (RD)', label=_('Export VRF (RD)'),
) )
def search(self, queryset, name, value): def search(self, queryset, name, value):
@ -126,17 +127,17 @@ class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
) )
prefix = django_filters.CharFilter( prefix = django_filters.CharFilter(
method='filter_prefix', method='filter_prefix',
label='Prefix', label=_('Prefix'),
) )
rir_id = django_filters.ModelMultipleChoiceFilter( rir_id = django_filters.ModelMultipleChoiceFilter(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
label='RIR (ID)', label=_('RIR (ID)'),
) )
rir = django_filters.ModelMultipleChoiceFilter( rir = django_filters.ModelMultipleChoiceFilter(
field_name='rir__slug', field_name='rir__slug',
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
to_field_name='slug', to_field_name='slug',
label='RIR (slug)', label=_('RIR (slug)'),
) )
class Meta: class Meta:
@ -169,24 +170,24 @@ class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
class ASNFilterSet(OrganizationalModelFilterSet, TenancyFilterSet): class ASNFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
rir_id = django_filters.ModelMultipleChoiceFilter( rir_id = django_filters.ModelMultipleChoiceFilter(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
label='RIR (ID)', label=_('RIR (ID)'),
) )
rir = django_filters.ModelMultipleChoiceFilter( rir = django_filters.ModelMultipleChoiceFilter(
field_name='rir__slug', field_name='rir__slug',
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
to_field_name='slug', to_field_name='slug',
label='RIR (slug)', label=_('RIR (slug)'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
field_name='sites', field_name='sites',
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label=_('Site (ID)'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='sites__slug', field_name='sites__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
class Meta: class Meta:
@ -218,19 +219,19 @@ class PrefixFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
) )
prefix = MultiValueCharFilter( prefix = MultiValueCharFilter(
method='filter_prefix', method='filter_prefix',
label='Prefix', label=_('Prefix'),
) )
within = django_filters.CharFilter( within = django_filters.CharFilter(
method='search_within', method='search_within',
label='Within prefix', label=_('Within prefix'),
) )
within_include = django_filters.CharFilter( within_include = django_filters.CharFilter(
method='search_within_include', method='search_within_include',
label='Within and including prefix', label=_('Within and including prefix'),
) )
contains = django_filters.CharFilter( contains = django_filters.CharFilter(
method='search_contains', method='search_contains',
label='Prefixes which contain this prefix or IP', label=_('Prefixes which contain this prefix or IP'),
) )
depth = MultiValueNumberFilter( depth = MultiValueNumberFilter(
field_name='_depth' field_name='_depth'
@ -252,78 +253,78 @@ class PrefixFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
) )
vrf_id = django_filters.ModelMultipleChoiceFilter( vrf_id = django_filters.ModelMultipleChoiceFilter(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
label='VRF', label=_('VRF'),
) )
vrf = django_filters.ModelMultipleChoiceFilter( vrf = django_filters.ModelMultipleChoiceFilter(
field_name='vrf__rd', field_name='vrf__rd',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='rd', to_field_name='rd',
label='VRF (RD)', label=_('VRF (RD)'),
) )
present_in_vrf_id = django_filters.ModelChoiceFilter( present_in_vrf_id = django_filters.ModelChoiceFilter(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
method='filter_present_in_vrf', method='filter_present_in_vrf',
label='VRF' label=_('VRF')
) )
present_in_vrf = django_filters.ModelChoiceFilter( present_in_vrf = django_filters.ModelChoiceFilter(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
method='filter_present_in_vrf', method='filter_present_in_vrf',
to_field_name='rd', to_field_name='rd',
label='VRF (RD)', label=_('VRF (RD)'),
) )
region_id = TreeNodeMultipleChoiceFilter( region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
lookup_expr='in', lookup_expr='in',
label='Region (ID)', label=_('Region (ID)'),
) )
region = TreeNodeMultipleChoiceFilter( region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Region (slug)', label=_('Region (slug)'),
) )
site_group_id = TreeNodeMultipleChoiceFilter( site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='site__group', field_name='site__group',
lookup_expr='in', lookup_expr='in',
label='Site group (ID)', label=_('Site group (ID)'),
) )
site_group = TreeNodeMultipleChoiceFilter( site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='site__group', field_name='site__group',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Site group (slug)', label=_('Site group (slug)'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label=_('Site (ID)'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='site__slug', field_name='site__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
vlan_id = django_filters.ModelMultipleChoiceFilter( vlan_id = django_filters.ModelMultipleChoiceFilter(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
label='VLAN (ID)', label=_('VLAN (ID)'),
) )
vlan_vid = django_filters.NumberFilter( vlan_vid = django_filters.NumberFilter(
field_name='vlan__vid', field_name='vlan__vid',
label='VLAN number (1-4094)', label=_('VLAN number (1-4094)'),
) )
role_id = django_filters.ModelMultipleChoiceFilter( role_id = django_filters.ModelMultipleChoiceFilter(
queryset=Role.objects.all(), queryset=Role.objects.all(),
label='Role (ID)', label=_('Role (ID)'),
) )
role = django_filters.ModelMultipleChoiceFilter( role = django_filters.ModelMultipleChoiceFilter(
field_name='role__slug', field_name='role__slug',
queryset=Role.objects.all(), queryset=Role.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Role (slug)', label=_('Role (slug)'),
) )
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=PrefixStatusChoices, choices=PrefixStatusChoices,
@ -406,27 +407,27 @@ class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
) )
contains = django_filters.CharFilter( contains = django_filters.CharFilter(
method='search_contains', method='search_contains',
label='Ranges which contain this prefix or IP', label=_('Ranges which contain this prefix or IP'),
) )
vrf_id = django_filters.ModelMultipleChoiceFilter( vrf_id = django_filters.ModelMultipleChoiceFilter(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
label='VRF', label=_('VRF'),
) )
vrf = django_filters.ModelMultipleChoiceFilter( vrf = django_filters.ModelMultipleChoiceFilter(
field_name='vrf__rd', field_name='vrf__rd',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='rd', to_field_name='rd',
label='VRF (RD)', label=_('VRF (RD)'),
) )
role_id = django_filters.ModelMultipleChoiceFilter( role_id = django_filters.ModelMultipleChoiceFilter(
queryset=Role.objects.all(), queryset=Role.objects.all(),
label='Role (ID)', label=_('Role (ID)'),
) )
role = django_filters.ModelMultipleChoiceFilter( role = django_filters.ModelMultipleChoiceFilter(
field_name='role__slug', field_name='role__slug',
queryset=Role.objects.all(), queryset=Role.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Role (slug)', label=_('Role (slug)'),
) )
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=IPRangeStatusChoices, choices=IPRangeStatusChoices,
@ -468,87 +469,87 @@ class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
) )
parent = MultiValueCharFilter( parent = MultiValueCharFilter(
method='search_by_parent', method='search_by_parent',
label='Parent prefix', label=_('Parent prefix'),
) )
address = MultiValueCharFilter( address = MultiValueCharFilter(
method='filter_address', method='filter_address',
label='Address', label=_('Address'),
) )
mask_length = django_filters.NumberFilter( mask_length = django_filters.NumberFilter(
method='filter_mask_length', method='filter_mask_length',
label='Mask length', label=_('Mask length'),
) )
vrf_id = django_filters.ModelMultipleChoiceFilter( vrf_id = django_filters.ModelMultipleChoiceFilter(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
label='VRF', label=_('VRF'),
) )
vrf = django_filters.ModelMultipleChoiceFilter( vrf = django_filters.ModelMultipleChoiceFilter(
field_name='vrf__rd', field_name='vrf__rd',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='rd', to_field_name='rd',
label='VRF (RD)', label=_('VRF (RD)'),
) )
present_in_vrf_id = django_filters.ModelChoiceFilter( present_in_vrf_id = django_filters.ModelChoiceFilter(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
method='filter_present_in_vrf', method='filter_present_in_vrf',
label='VRF' label=_('VRF')
) )
present_in_vrf = django_filters.ModelChoiceFilter( present_in_vrf = django_filters.ModelChoiceFilter(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
method='filter_present_in_vrf', method='filter_present_in_vrf',
to_field_name='rd', to_field_name='rd',
label='VRF (RD)', label=_('VRF (RD)'),
) )
device = MultiValueCharFilter( device = MultiValueCharFilter(
method='filter_device', method='filter_device',
field_name='name', field_name='name',
label='Device (name)', label=_('Device (name)'),
) )
device_id = MultiValueNumberFilter( device_id = MultiValueNumberFilter(
method='filter_device', method='filter_device',
field_name='pk', field_name='pk',
label='Device (ID)', label=_('Device (ID)'),
) )
virtual_machine = MultiValueCharFilter( virtual_machine = MultiValueCharFilter(
method='filter_virtual_machine', method='filter_virtual_machine',
field_name='name', field_name='name',
label='Virtual machine (name)', label=_('Virtual machine (name)'),
) )
virtual_machine_id = MultiValueNumberFilter( virtual_machine_id = MultiValueNumberFilter(
method='filter_virtual_machine', method='filter_virtual_machine',
field_name='pk', field_name='pk',
label='Virtual machine (ID)', label=_('Virtual machine (ID)'),
) )
interface = django_filters.ModelMultipleChoiceFilter( interface = django_filters.ModelMultipleChoiceFilter(
field_name='interface__name', field_name='interface__name',
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
to_field_name='name', to_field_name='name',
label='Interface (name)', label=_('Interface (name)'),
) )
interface_id = django_filters.ModelMultipleChoiceFilter( interface_id = django_filters.ModelMultipleChoiceFilter(
field_name='interface', field_name='interface',
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
label='Interface (ID)', label=_('Interface (ID)'),
) )
vminterface = django_filters.ModelMultipleChoiceFilter( vminterface = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface__name', field_name='vminterface__name',
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
to_field_name='name', to_field_name='name',
label='VM interface (name)', label=_('VM interface (name)'),
) )
vminterface_id = django_filters.ModelMultipleChoiceFilter( vminterface_id = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface', field_name='vminterface',
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
label='VM interface (ID)', label=_('VM interface (ID)'),
) )
fhrpgroup_id = django_filters.ModelMultipleChoiceFilter( fhrpgroup_id = django_filters.ModelMultipleChoiceFilter(
field_name='fhrpgroup', field_name='fhrpgroup',
queryset=FHRPGroup.objects.all(), queryset=FHRPGroup.objects.all(),
label='FHRP group (ID)', label=_('FHRP group (ID)'),
) )
assigned_to_interface = django_filters.BooleanFilter( assigned_to_interface = django_filters.BooleanFilter(
method='_assigned_to_interface', method='_assigned_to_interface',
label='Is assigned to an interface', label=_('Is assigned to an interface'),
) )
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=IPAddressStatusChoices, choices=IPAddressStatusChoices,
@ -688,27 +689,27 @@ class FHRPGroupAssignmentFilterSet(ChangeLoggedModelFilterSet):
interface_type = ContentTypeFilter() interface_type = ContentTypeFilter()
group_id = django_filters.ModelMultipleChoiceFilter( group_id = django_filters.ModelMultipleChoiceFilter(
queryset=FHRPGroup.objects.all(), queryset=FHRPGroup.objects.all(),
label='Group (ID)', label=_('Group (ID)'),
) )
device = MultiValueCharFilter( device = MultiValueCharFilter(
method='filter_device', method='filter_device',
field_name='name', field_name='name',
label='Device (name)', label=_('Device (name)'),
) )
device_id = MultiValueNumberFilter( device_id = MultiValueNumberFilter(
method='filter_device', method='filter_device',
field_name='pk', field_name='pk',
label='Device (ID)', label=_('Device (ID)'),
) )
virtual_machine = MultiValueCharFilter( virtual_machine = MultiValueCharFilter(
method='filter_virtual_machine', method='filter_virtual_machine',
field_name='name', field_name='name',
label='Virtual machine (name)', label=_('Virtual machine (name)'),
) )
virtual_machine_id = MultiValueNumberFilter( virtual_machine_id = MultiValueNumberFilter(
method='filter_virtual_machine', method='filter_virtual_machine',
field_name='pk', field_name='pk',
label='Virtual machine (ID)', label=_('Virtual machine (ID)'),
) )
class Meta: class Meta:
@ -787,57 +788,57 @@ class VLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
lookup_expr='in', lookup_expr='in',
label='Region (ID)', label=_('Region (ID)'),
) )
region = TreeNodeMultipleChoiceFilter( region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Region (slug)', label=_('Region (slug)'),
) )
site_group_id = TreeNodeMultipleChoiceFilter( site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='site__group', field_name='site__group',
lookup_expr='in', lookup_expr='in',
label='Site group (ID)', label=_('Site group (ID)'),
) )
site_group = TreeNodeMultipleChoiceFilter( site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='site__group', field_name='site__group',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Site group (slug)', label=_('Site group (slug)'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label=_('Site (ID)'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='site__slug', field_name='site__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
group_id = django_filters.ModelMultipleChoiceFilter( group_id = django_filters.ModelMultipleChoiceFilter(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
label='Group (ID)', label=_('Group (ID)'),
) )
group = django_filters.ModelMultipleChoiceFilter( group = django_filters.ModelMultipleChoiceFilter(
field_name='group__slug', field_name='group__slug',
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Group', label=_('Group'),
) )
role_id = django_filters.ModelMultipleChoiceFilter( role_id = django_filters.ModelMultipleChoiceFilter(
queryset=Role.objects.all(), queryset=Role.objects.all(),
label='Role (ID)', label=_('Role (ID)'),
) )
role = django_filters.ModelMultipleChoiceFilter( role = django_filters.ModelMultipleChoiceFilter(
field_name='role__slug', field_name='role__slug',
queryset=Role.objects.all(), queryset=Role.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Role (slug)', label=_('Role (slug)'),
) )
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=VLANStatusChoices, choices=VLANStatusChoices,
@ -893,23 +894,23 @@ class ServiceTemplateFilterSet(NetBoxModelFilterSet):
class ServiceFilterSet(NetBoxModelFilterSet): class ServiceFilterSet(NetBoxModelFilterSet):
device_id = django_filters.ModelMultipleChoiceFilter( device_id = django_filters.ModelMultipleChoiceFilter(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label='Device (ID)', label=_('Device (ID)'),
) )
device = django_filters.ModelMultipleChoiceFilter( device = django_filters.ModelMultipleChoiceFilter(
field_name='device__name', field_name='device__name',
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
label='Device (name)', label=_('Device (name)'),
) )
virtual_machine_id = django_filters.ModelMultipleChoiceFilter( virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
label='Virtual machine (ID)', label=_('Virtual machine (ID)'),
) )
virtual_machine = django_filters.ModelMultipleChoiceFilter( virtual_machine = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine__name', field_name='virtual_machine__name',
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
to_field_name='name', to_field_name='name',
label='Virtual machine (name)', label=_('Virtual machine (name)'),
) )
port = NumericArrayFilter( port = NumericArrayFilter(
field_name='ports', field_name='ports',
@ -939,24 +940,24 @@ class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
import_target_id = django_filters.ModelMultipleChoiceFilter( import_target_id = django_filters.ModelMultipleChoiceFilter(
field_name='import_targets', field_name='import_targets',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
label='Import target', label=_('Import target'),
) )
import_target = django_filters.ModelMultipleChoiceFilter( import_target = django_filters.ModelMultipleChoiceFilter(
field_name='import_targets__name', field_name='import_targets__name',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
to_field_name='name', to_field_name='name',
label='Import target (name)', label=_('Import target (name)'),
) )
export_target_id = django_filters.ModelMultipleChoiceFilter( export_target_id = django_filters.ModelMultipleChoiceFilter(
field_name='export_targets', field_name='export_targets',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
label='Export target', label=_('Export target'),
) )
export_target = django_filters.ModelMultipleChoiceFilter( export_target = django_filters.ModelMultipleChoiceFilter(
field_name='export_targets__name', field_name='export_targets__name',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
to_field_name='name', to_field_name='name',
label='Export target (name)', label=_('Export target (name)'),
) )
class Meta: class Meta:
@ -977,92 +978,92 @@ class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
class L2VPNTerminationFilterSet(NetBoxModelFilterSet): class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
l2vpn_id = django_filters.ModelMultipleChoiceFilter( l2vpn_id = django_filters.ModelMultipleChoiceFilter(
queryset=L2VPN.objects.all(), queryset=L2VPN.objects.all(),
label='L2VPN (ID)', label=_('L2VPN (ID)'),
) )
l2vpn = django_filters.ModelMultipleChoiceFilter( l2vpn = django_filters.ModelMultipleChoiceFilter(
field_name='l2vpn__slug', field_name='l2vpn__slug',
queryset=L2VPN.objects.all(), queryset=L2VPN.objects.all(),
to_field_name='slug', to_field_name='slug',
label='L2VPN (slug)', label=_('L2VPN (slug)'),
) )
region = MultiValueCharFilter( region = MultiValueCharFilter(
method='filter_region', method='filter_region',
field_name='slug', field_name='slug',
label='Region (slug)', label=_('Region (slug)'),
) )
region_id = MultiValueNumberFilter( region_id = MultiValueNumberFilter(
method='filter_region', method='filter_region',
field_name='pk', field_name='pk',
label='Region (ID)', label=_('Region (ID)'),
) )
site = MultiValueCharFilter( site = MultiValueCharFilter(
method='filter_site', method='filter_site',
field_name='slug', field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
site_id = MultiValueNumberFilter( site_id = MultiValueNumberFilter(
method='filter_site', method='filter_site',
field_name='pk', field_name='pk',
label='Site (ID)', label=_('Site (ID)'),
) )
device = django_filters.ModelMultipleChoiceFilter( device = django_filters.ModelMultipleChoiceFilter(
field_name='interface__device__name', field_name='interface__device__name',
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
label='Device (name)', label=_('Device (name)'),
) )
device_id = django_filters.ModelMultipleChoiceFilter( device_id = django_filters.ModelMultipleChoiceFilter(
field_name='interface__device', field_name='interface__device',
queryset=Device.objects.all(), queryset=Device.objects.all(),
label='Device (ID)', label=_('Device (ID)'),
) )
virtual_machine = django_filters.ModelMultipleChoiceFilter( virtual_machine = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface__virtual_machine__name', field_name='vminterface__virtual_machine__name',
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
to_field_name='name', to_field_name='name',
label='Virtual machine (name)', label=_('Virtual machine (name)'),
) )
virtual_machine_id = django_filters.ModelMultipleChoiceFilter( virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface__virtual_machine', field_name='vminterface__virtual_machine',
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
label='Virtual machine (ID)', label=_('Virtual machine (ID)'),
) )
interface = django_filters.ModelMultipleChoiceFilter( interface = django_filters.ModelMultipleChoiceFilter(
field_name='interface__name', field_name='interface__name',
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
to_field_name='name', to_field_name='name',
label='Interface (name)', label=_('Interface (name)'),
) )
interface_id = django_filters.ModelMultipleChoiceFilter( interface_id = django_filters.ModelMultipleChoiceFilter(
field_name='interface', field_name='interface',
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
label='Interface (ID)', label=_('Interface (ID)'),
) )
vminterface = django_filters.ModelMultipleChoiceFilter( vminterface = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface__name', field_name='vminterface__name',
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
to_field_name='name', to_field_name='name',
label='VM interface (name)', label=_('VM interface (name)'),
) )
vminterface_id = django_filters.ModelMultipleChoiceFilter( vminterface_id = django_filters.ModelMultipleChoiceFilter(
field_name='vminterface', field_name='vminterface',
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
label='VM Interface (ID)', label=_('VM Interface (ID)'),
) )
vlan = django_filters.ModelMultipleChoiceFilter( vlan = django_filters.ModelMultipleChoiceFilter(
field_name='vlan__name', field_name='vlan__name',
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
to_field_name='name', to_field_name='name',
label='VLAN (name)', label=_('VLAN (name)'),
) )
vlan_vid = django_filters.NumberFilter( vlan_vid = django_filters.NumberFilter(
field_name='vlan__vid', field_name='vlan__vid',
label='VLAN number (1-4094)', label=_('VLAN number (1-4094)'),
) )
vlan_id = django_filters.ModelMultipleChoiceFilter( vlan_id = django_filters.ModelMultipleChoiceFilter(
field_name='vlan', field_name='vlan',
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
label='VLAN (ID)', label=_('VLAN (ID)'),
) )
assigned_object_type = ContentTypeFilter() assigned_object_type = ContentTypeFilter()

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from utilities.forms import BootstrapMixin, ExpandableIPAddressField from utilities.forms import BootstrapMixin, ExpandableIPAddressField
@ -9,5 +10,5 @@ __all__ = (
class IPAddressBulkCreateForm(BootstrapMixin, forms.Form): class IPAddressBulkCreateForm(BootstrapMixin, forms.Form):
pattern = ExpandableIPAddressField( pattern = ExpandableIPAddressField(
label='Address pattern' label=_('Address pattern')
) )

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from dcim.models import Region, Site, SiteGroup from dcim.models import Region, Site, SiteGroup
from ipam.choices import * from ipam.choices import *
@ -40,7 +41,7 @@ class VRFBulkEditForm(NetBoxModelBulkEditForm):
enforce_unique = forms.NullBooleanField( enforce_unique = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label='Enforce unique space' label=_('Enforce unique space')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -104,7 +105,7 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
required=False, required=False,
label='RIR' label=_('RIR')
) )
tenant = DynamicModelChoiceField( tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@ -130,7 +131,7 @@ class AggregateBulkEditForm(NetBoxModelBulkEditForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
required=False, required=False,
label='RIR' label=_('RIR')
) )
tenant = DynamicModelChoiceField( tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@ -191,7 +192,7 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
prefix_length = forms.IntegerField( prefix_length = forms.IntegerField(
min_value=PREFIX_LENGTH_MIN, min_value=PREFIX_LENGTH_MIN,
@ -214,12 +215,12 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm):
is_pool = forms.NullBooleanField( is_pool = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label='Is a pool' label=_('Is a pool')
) )
mark_utilized = forms.NullBooleanField( mark_utilized = forms.NullBooleanField(
required=False, required=False,
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label='Treat as 100% utilized' label=_('Treat as 100% utilized')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -245,7 +246,7 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
tenant = DynamicModelChoiceField( tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@ -282,7 +283,7 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
mask_length = forms.IntegerField( mask_length = forms.IntegerField(
min_value=IPADDRESS_MASK_LENGTH_MIN, min_value=IPADDRESS_MASK_LENGTH_MIN,
@ -306,7 +307,7 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm):
dns_name = forms.CharField( dns_name = forms.CharField(
max_length=255, max_length=255,
required=False, required=False,
label='DNS name' label=_('DNS name')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -336,18 +337,18 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm):
group_id = forms.IntegerField( group_id = forms.IntegerField(
min_value=0, min_value=0,
required=False, required=False,
label='Group ID' label=_('Group ID')
) )
auth_type = forms.ChoiceField( auth_type = forms.ChoiceField(
choices=add_blank_choice(FHRPGroupAuthTypeChoices), choices=add_blank_choice(FHRPGroupAuthTypeChoices),
required=False, required=False,
widget=StaticSelect(), widget=StaticSelect(),
label='Authentication type' label=_('Authentication type')
) )
auth_key = forms.CharField( auth_key = forms.CharField(
max_length=255, max_length=255,
required=False, required=False,
label='Authentication key' label=_('Authentication key')
) )
name = forms.CharField( name = forms.CharField(
max_length=100, max_length=100,
@ -379,13 +380,13 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
min_value=VLAN_VID_MIN, min_value=VLAN_VID_MIN,
max_value=VLAN_VID_MAX, max_value=VLAN_VID_MAX,
required=False, required=False,
label='Minimum child VLAN VID' label=_('Minimum child VLAN VID')
) )
max_vid = forms.IntegerField( max_vid = forms.IntegerField(
min_value=VLAN_VID_MIN, min_value=VLAN_VID_MIN,
max_value=VLAN_VID_MAX, max_value=VLAN_VID_MAX,
required=False, required=False,
label='Maximum child VLAN VID' label=_('Maximum child VLAN VID')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,

View File

@ -1,6 +1,7 @@
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
from dcim.models import Device, Interface, Site from dcim.models import Device, Interface, Site
from ipam.choices import * from ipam.choices import *
@ -36,7 +37,7 @@ class VRFCSVForm(NetBoxModelCSVForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:
@ -49,7 +50,7 @@ class RouteTargetCSVForm(NetBoxModelCSVForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:
@ -64,7 +65,7 @@ class RIRCSVForm(NetBoxModelCSVForm):
model = RIR model = RIR
fields = ('name', 'slug', 'is_private', 'description', 'tags') fields = ('name', 'slug', 'is_private', 'description', 'tags')
help_texts = { help_texts = {
'name': 'RIR name', 'name': _('RIR name'),
} }
@ -72,13 +73,13 @@ class AggregateCSVForm(NetBoxModelCSVForm):
rir = CSVModelChoiceField( rir = CSVModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Assigned RIR' help_text=_('Assigned RIR')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:
@ -90,13 +91,13 @@ class ASNCSVForm(NetBoxModelCSVForm):
rir = CSVModelChoiceField( rir = CSVModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Assigned RIR' help_text=_('Assigned RIR')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:
@ -117,41 +118,41 @@ class PrefixCSVForm(NetBoxModelCSVForm):
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned VRF' help_text=_('Assigned VRF')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
site = CSVModelChoiceField( site = CSVModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned site' help_text=_('Assigned site')
) )
vlan_group = CSVModelChoiceField( vlan_group = CSVModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text="VLAN's group (if any)" help_text=_("VLAN's group (if any)")
) )
vlan = CSVModelChoiceField( vlan = CSVModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
to_field_name='vid', to_field_name='vid',
help_text="Assigned VLAN" help_text=_("Assigned VLAN")
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=PrefixStatusChoices, choices=PrefixStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
role = CSVModelChoiceField( role = CSVModelChoiceField(
queryset=Role.objects.all(), queryset=Role.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Functional role' help_text=_('Functional role')
) )
class Meta: class Meta:
@ -181,23 +182,23 @@ class IPRangeCSVForm(NetBoxModelCSVForm):
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned VRF' help_text=_('Assigned VRF')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=IPRangeStatusChoices, choices=IPRangeStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
role = CSVModelChoiceField( role = CSVModelChoiceField(
queryset=Role.objects.all(), queryset=Role.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Functional role' help_text=_('Functional role')
) )
class Meta: class Meta:
@ -212,43 +213,43 @@ class IPAddressCSVForm(NetBoxModelCSVForm):
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned VRF' help_text=_('Assigned VRF')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=IPAddressStatusChoices, choices=IPAddressStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
role = CSVChoiceField( role = CSVChoiceField(
choices=IPAddressRoleChoices, choices=IPAddressRoleChoices,
required=False, required=False,
help_text='Functional role' help_text=_('Functional role')
) )
device = CSVModelChoiceField( device = CSVModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent device of assigned interface (if any)' help_text=_('Parent device of assigned interface (if any)')
) )
virtual_machine = CSVModelChoiceField( virtual_machine = CSVModelChoiceField(
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent VM of assigned interface (if any)' help_text=_('Parent VM of assigned interface (if any)')
) )
interface = CSVModelChoiceField( interface = CSVModelChoiceField(
queryset=Interface.objects.none(), # Can also refer to VMInterface queryset=Interface.objects.none(), # Can also refer to VMInterface
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned interface' help_text=_('Assigned interface')
) )
is_primary = forms.BooleanField( is_primary = forms.BooleanField(
help_text='Make this the primary IP for the assigned device', help_text=_('Make this the primary IP for the assigned device'),
required=False required=False
) )
@ -333,7 +334,7 @@ class VLANGroupCSVForm(NetBoxModelCSVForm):
scope_type = CSVContentTypeField( scope_type = CSVContentTypeField(
queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES), queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
required=False, required=False,
label='Scope type (app & model)' label=_('Scope type (app & model)')
) )
min_vid = forms.IntegerField( min_vid = forms.IntegerField(
min_value=VLAN_VID_MIN, min_value=VLAN_VID_MIN,
@ -361,29 +362,29 @@ class VLANCSVForm(NetBoxModelCSVForm):
queryset=Site.objects.all(), queryset=Site.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned site' help_text=_('Assigned site')
) )
group = CSVModelChoiceField( group = CSVModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned VLAN group' help_text=_('Assigned VLAN group')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=VLANStatusChoices, choices=VLANStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
role = CSVModelChoiceField( role = CSVModelChoiceField(
queryset=Role.objects.all(), queryset=Role.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Functional role' help_text=_('Functional role')
) )
class Meta: class Meta:
@ -398,7 +399,7 @@ class VLANCSVForm(NetBoxModelCSVForm):
class ServiceTemplateCSVForm(NetBoxModelCSVForm): class ServiceTemplateCSVForm(NetBoxModelCSVForm):
protocol = CSVChoiceField( protocol = CSVChoiceField(
choices=ServiceProtocolChoices, choices=ServiceProtocolChoices,
help_text='IP protocol' help_text=_('IP protocol')
) )
class Meta: class Meta:
@ -411,17 +412,17 @@ class ServiceCSVForm(NetBoxModelCSVForm):
queryset=Device.objects.all(), queryset=Device.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Required if not assigned to a VM' help_text=_('Required if not assigned to a VM')
) )
virtual_machine = CSVModelChoiceField( virtual_machine = CSVModelChoiceField(
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Required if not assigned to a device' help_text=_('Required if not assigned to a device')
) )
protocol = CSVChoiceField( protocol = CSVChoiceField(
choices=ServiceProtocolChoices, choices=ServiceProtocolChoices,
help_text='IP protocol' help_text=_('IP protocol')
) )
class Meta: class Meta:
@ -437,7 +438,7 @@ class L2VPNCSVForm(NetBoxModelCSVForm):
) )
type = CSVChoiceField( type = CSVChoiceField(
choices=L2VPNTypeChoices, choices=L2VPNTypeChoices,
help_text='L2VPN type' help_text=_('L2VPN type')
) )
class Meta: class Meta:
@ -450,31 +451,31 @@ class L2VPNTerminationCSVForm(NetBoxModelCSVForm):
queryset=L2VPN.objects.all(), queryset=L2VPN.objects.all(),
required=True, required=True,
to_field_name='name', to_field_name='name',
label='L2VPN', label=_('L2VPN'),
) )
device = CSVModelChoiceField( device = CSVModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent device (for interface)' help_text=_('Parent device (for interface)')
) )
virtual_machine = CSVModelChoiceField( virtual_machine = CSVModelChoiceField(
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent virtual machine (for interface)' help_text=_('Parent virtual machine (for interface)')
) )
interface = CSVModelChoiceField( interface = CSVModelChoiceField(
queryset=Interface.objects.none(), # Can also refer to VMInterface queryset=Interface.objects.none(), # Can also refer to VMInterface
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned interface (device or VM)' help_text=_('Assigned interface (device or VM)')
) )
vlan = CSVModelChoiceField( vlan = CSVModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned VLAN' help_text=_('Assigned VLAN')
) )
class Meta: class Meta:

View File

@ -397,13 +397,13 @@ class VLANGroupFilterForm(NetBoxModelFilterSetForm):
required=False, required=False,
min_value=VLAN_VID_MIN, min_value=VLAN_VID_MIN,
max_value=VLAN_VID_MAX, max_value=VLAN_VID_MAX,
label='Minimum VID' label=_('Minimum VID')
) )
max_vid = forms.IntegerField( max_vid = forms.IntegerField(
required=False, required=False,
min_value=VLAN_VID_MIN, min_value=VLAN_VID_MIN,
max_value=VLAN_VID_MAX, max_value=VLAN_VID_MAX,
label='Maximum VID' label=_('Maximum VID')
) )
tag = TagFilterField(model) tag = TagFilterField(model)

View File

@ -1,6 +1,7 @@
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup from dcim.models import Device, Interface, Location, Rack, Region, Site, SiteGroup
from ipam.choices import * from ipam.choices import *
@ -67,7 +68,7 @@ class VRFForm(TenancyForm, NetBoxModelForm):
'rd': "RD", 'rd': "RD",
} }
help_texts = { help_texts = {
'rd': "Route distinguisher in any format", 'rd': _("Route distinguisher in any format"),
} }
@ -104,7 +105,7 @@ class RIRForm(NetBoxModelForm):
class AggregateForm(TenancyForm, NetBoxModelForm): class AggregateForm(TenancyForm, NetBoxModelForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
label='RIR' label=_('RIR')
) )
comments = CommentField() comments = CommentField()
@ -119,8 +120,8 @@ class AggregateForm(TenancyForm, NetBoxModelForm):
'prefix', 'rir', 'date_added', 'tenant_group', 'tenant', 'description', 'comments', 'tags', 'prefix', 'rir', 'date_added', 'tenant_group', 'tenant', 'description', 'comments', 'tags',
] ]
help_texts = { help_texts = {
'prefix': "IPv4 or IPv6 network", 'prefix': _("IPv4 or IPv6 network"),
'rir': "Regional Internet Registry responsible for this prefix", 'rir': _("Regional Internet Registry responsible for this prefix"),
} }
widgets = { widgets = {
'date_added': DatePicker(), 'date_added': DatePicker(),
@ -130,11 +131,11 @@ class AggregateForm(TenancyForm, NetBoxModelForm):
class ASNForm(TenancyForm, NetBoxModelForm): class ASNForm(TenancyForm, NetBoxModelForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
label='RIR', label=_('RIR'),
) )
sites = DynamicModelMultipleChoiceField( sites = DynamicModelMultipleChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Sites', label=_('Sites'),
required=False required=False
) )
comments = CommentField() comments = CommentField()
@ -150,8 +151,8 @@ class ASNForm(TenancyForm, NetBoxModelForm):
'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'comments', 'tags' 'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'comments', 'tags'
] ]
help_texts = { help_texts = {
'asn': "AS number", 'asn': _("AS number"),
'rir': "Regional Internet Registry responsible for this prefix", 'rir': _("Regional Internet Registry responsible for this prefix"),
} }
widgets = { widgets = {
'date_added': DatePicker(), 'date_added': DatePicker(),
@ -189,7 +190,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
region = DynamicModelChoiceField( region = DynamicModelChoiceField(
queryset=Region.objects.all(), queryset=Region.objects.all(),
@ -217,7 +218,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm):
vlan_group = DynamicModelChoiceField( vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
label='VLAN group', label=_('VLAN group'),
null_option='None', null_option='None',
query_params={ query_params={
'site': '$site' 'site': '$site'
@ -229,7 +230,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm):
vlan = DynamicModelChoiceField( vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
label='VLAN', label=_('VLAN'),
query_params={ query_params={
'site_id': '$site', 'site_id': '$site',
'group_id': '$vlan_group', 'group_id': '$vlan_group',
@ -262,7 +263,7 @@ class IPRangeForm(TenancyForm, NetBoxModelForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
role = DynamicModelChoiceField( role = DynamicModelChoiceField(
queryset=Role.objects.all(), queryset=Role.objects.all(),
@ -311,7 +312,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
vminterface = DynamicModelChoiceField( vminterface = DynamicModelChoiceField(
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
required=False, required=False,
label='Interface', label=_('Interface'),
query_params={ query_params={
'virtual_machine_id': '$virtual_machine' 'virtual_machine_id': '$virtual_machine'
} }
@ -319,17 +320,17 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
fhrpgroup = DynamicModelChoiceField( fhrpgroup = DynamicModelChoiceField(
queryset=FHRPGroup.objects.all(), queryset=FHRPGroup.objects.all(),
required=False, required=False,
label='FHRP Group' label=_('FHRP Group')
) )
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
nat_region = DynamicModelChoiceField( nat_region = DynamicModelChoiceField(
queryset=Region.objects.all(), queryset=Region.objects.all(),
required=False, required=False,
label='Region', label=_('Region'),
initial_params={ initial_params={
'sites': '$nat_site' 'sites': '$nat_site'
} }
@ -337,7 +338,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
nat_site_group = DynamicModelChoiceField( nat_site_group = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
required=False, required=False,
label='Site group', label=_('Site group'),
initial_params={ initial_params={
'sites': '$nat_site' 'sites': '$nat_site'
} }
@ -345,7 +346,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
nat_site = DynamicModelChoiceField( nat_site = DynamicModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
required=False, required=False,
label='Site', label=_('Site'),
query_params={ query_params={
'region_id': '$nat_region', 'region_id': '$nat_region',
'group_id': '$nat_site_group', 'group_id': '$nat_site_group',
@ -354,7 +355,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
nat_rack = DynamicModelChoiceField( nat_rack = DynamicModelChoiceField(
queryset=Rack.objects.all(), queryset=Rack.objects.all(),
required=False, required=False,
label='Rack', label=_('Rack'),
null_option='None', null_option='None',
query_params={ query_params={
'site_id': '$site' 'site_id': '$site'
@ -363,7 +364,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
nat_device = DynamicModelChoiceField( nat_device = DynamicModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
required=False, required=False,
label='Device', label=_('Device'),
query_params={ query_params={
'site_id': '$site', 'site_id': '$site',
'rack_id': '$nat_rack', 'rack_id': '$nat_rack',
@ -372,12 +373,12 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
nat_cluster = DynamicModelChoiceField( nat_cluster = DynamicModelChoiceField(
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
required=False, required=False,
label='Cluster' label=_('Cluster')
) )
nat_virtual_machine = DynamicModelChoiceField( nat_virtual_machine = DynamicModelChoiceField(
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
required=False, required=False,
label='Virtual Machine', label=_('Virtual Machine'),
query_params={ query_params={
'cluster_id': '$nat_cluster', 'cluster_id': '$nat_cluster',
} }
@ -385,12 +386,12 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
nat_vrf = DynamicModelChoiceField( nat_vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
nat_inside = DynamicModelChoiceField( nat_inside = DynamicModelChoiceField(
queryset=IPAddress.objects.all(), queryset=IPAddress.objects.all(),
required=False, required=False,
label='IP Address', label=_('IP Address'),
query_params={ query_params={
'device_id': '$nat_device', 'device_id': '$nat_device',
'virtual_machine_id': '$nat_virtual_machine', 'virtual_machine_id': '$nat_virtual_machine',
@ -399,7 +400,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
) )
primary_for_parent = forms.BooleanField( primary_for_parent = forms.BooleanField(
required=False, required=False,
label='Make this the primary IP for the device/VM' label=_('Make this the primary IP for the device/VM')
) )
comments = CommentField() comments = CommentField()
@ -500,7 +501,7 @@ class IPAddressBulkAddForm(TenancyForm, NetBoxModelForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
class Meta: class Meta:
@ -518,11 +519,11 @@ class IPAddressAssignForm(BootstrapMixin, forms.Form):
vrf_id = DynamicModelChoiceField( vrf_id = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
q = forms.CharField( q = forms.CharField(
required=False, required=False,
label='Search', label=_('Search'),
) )
@ -532,16 +533,16 @@ class FHRPGroupForm(NetBoxModelForm):
ip_vrf = DynamicModelChoiceField( ip_vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
ip_address = IPNetworkFormField( ip_address = IPNetworkFormField(
required=False, required=False,
label='Address' label=_('Address')
) )
ip_status = forms.ChoiceField( ip_status = forms.ChoiceField(
choices=add_blank_choice(IPAddressStatusChoices), choices=add_blank_choice(IPAddressStatusChoices),
required=False, required=False,
label='Status' label=_('Status')
) )
comments = CommentField() comments = CommentField()
@ -633,7 +634,7 @@ class VLANGroupForm(NetBoxModelForm):
initial_params={ initial_params={
'sites': '$site' 'sites': '$site'
}, },
label='Site group' label=_('Site group')
) )
site = DynamicModelChoiceField( site = DynamicModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
@ -670,7 +671,7 @@ class VLANGroupForm(NetBoxModelForm):
initial_params={ initial_params={
'clusters': '$cluster' 'clusters': '$cluster'
}, },
label='Cluster group' label=_('Cluster group')
) )
cluster = DynamicModelChoiceField( cluster = DynamicModelChoiceField(
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
@ -734,7 +735,7 @@ class VLANForm(TenancyForm, NetBoxModelForm):
), ),
required=False, required=False,
widget=StaticSelect, widget=StaticSelect,
label='Group scope' label=_('Group scope')
) )
group = DynamicModelChoiceField( group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
@ -742,7 +743,7 @@ class VLANForm(TenancyForm, NetBoxModelForm):
query_params={ query_params={
'scope_type': '$scope_type', 'scope_type': '$scope_type',
}, },
label='VLAN Group' label=_('VLAN Group')
) )
# Site assignment fields # Site assignment fields
@ -752,7 +753,7 @@ class VLANForm(TenancyForm, NetBoxModelForm):
initial_params={ initial_params={
'sites': '$site' 'sites': '$site'
}, },
label='Region' label=_('Region')
) )
sitegroup = DynamicModelChoiceField( sitegroup = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
@ -760,7 +761,7 @@ class VLANForm(TenancyForm, NetBoxModelForm):
initial_params={ initial_params={
'sites': '$site' 'sites': '$site'
}, },
label='Site group' label=_('Site group')
) )
site = DynamicModelChoiceField( site = DynamicModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
@ -786,12 +787,12 @@ class VLANForm(TenancyForm, NetBoxModelForm):
'tags', 'tags',
] ]
help_texts = { help_texts = {
'site': "Leave blank if this VLAN spans multiple sites", 'site': _("Leave blank if this VLAN spans multiple sites"),
'group': "VLAN group (optional)", 'group': _("VLAN group (optional)"),
'vid': "Configured VLAN ID", 'vid': _("Configured VLAN ID"),
'name': "Configured VLAN name", 'name': _("Configured VLAN name"),
'status': "Operational status of this VLAN", 'status': _("Operational status of this VLAN"),
'role': "The primary function of this VLAN", 'role': _("The primary function of this VLAN"),
} }
widgets = { widgets = {
'status': StaticSelect(), 'status': StaticSelect(),
@ -804,7 +805,7 @@ class ServiceTemplateForm(NetBoxModelForm):
min_value=SERVICE_PORT_MIN, min_value=SERVICE_PORT_MIN,
max_value=SERVICE_PORT_MAX max_value=SERVICE_PORT_MAX
), ),
help_text="Comma-separated list of one or more port numbers. A range may be specified using a hyphen." help_text=_("Comma-separated list of one or more port numbers. A range may be specified using a hyphen.")
) )
comments = CommentField() comments = CommentField()
@ -836,12 +837,12 @@ class ServiceForm(NetBoxModelForm):
min_value=SERVICE_PORT_MIN, min_value=SERVICE_PORT_MIN,
max_value=SERVICE_PORT_MAX max_value=SERVICE_PORT_MAX
), ),
help_text="Comma-separated list of one or more port numbers. A range may be specified using a hyphen." help_text=_("Comma-separated list of one or more port numbers. A range may be specified using a hyphen.")
) )
ipaddresses = DynamicModelMultipleChoiceField( ipaddresses = DynamicModelMultipleChoiceField(
queryset=IPAddress.objects.all(), queryset=IPAddress.objects.all(),
required=False, required=False,
label='IP Addresses', label=_('IP Addresses'),
query_params={ query_params={
'device_id': '$device', 'device_id': '$device',
'virtual_machine_id': '$virtual_machine', 'virtual_machine_id': '$virtual_machine',
@ -855,8 +856,8 @@ class ServiceForm(NetBoxModelForm):
'device', 'virtual_machine', 'name', 'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags', 'device', 'virtual_machine', 'name', 'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags',
] ]
help_texts = { help_texts = {
'ipaddresses': "IP address assignment is optional. If no IPs are selected, the service is assumed to be " 'ipaddresses': _("IP address assignment is optional. If no IPs are selected, the service is assumed to be "
"reachable via all IPs assigned to the device.", "reachable via all IPs assigned to the device."),
} }
widgets = { widgets = {
'protocol': StaticSelect(), 'protocol': StaticSelect(),
@ -937,12 +938,12 @@ class L2VPNTerminationForm(NetBoxModelForm):
queryset=L2VPN.objects.all(), queryset=L2VPN.objects.all(),
required=True, required=True,
query_params={}, query_params={},
label='L2VPN', label=_('L2VPN'),
fetch_trigger='open' fetch_trigger='open'
) )
device_vlan = DynamicModelChoiceField( device_vlan = DynamicModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label="Available on Device", label=_("Available on Device"),
required=False, required=False,
query_params={} query_params={}
) )
@ -952,7 +953,7 @@ class L2VPNTerminationForm(NetBoxModelForm):
query_params={ query_params={
'available_on_device': '$device_vlan' 'available_on_device': '$device_vlan'
}, },
label='VLAN' label=_('VLAN')
) )
device = DynamicModelChoiceField( device = DynamicModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
@ -977,7 +978,7 @@ class L2VPNTerminationForm(NetBoxModelForm):
query_params={ query_params={
'virtual_machine_id': '$virtual_machine' 'virtual_machine_id': '$virtual_machine'
}, },
label='Interface' label=_('Interface')
) )
class Meta: class Meta:

View File

@ -6,6 +6,7 @@ from django.db import models
from django.db.models import F from django.db.models import F
from django.urls import reverse from django.urls import reverse
from django.utils.functional import cached_property from django.utils.functional import cached_property
from django.utils.translation import gettext as _
from dcim.fields import ASNField from dcim.fields import ASNField
from dcim.models import Device from dcim.models import Device
@ -64,7 +65,7 @@ class RIR(OrganizationalModel):
is_private = models.BooleanField( is_private = models.BooleanField(
default=False, default=False,
verbose_name='Private', verbose_name='Private',
help_text='IP space managed by this RIR is considered private' help_text=_('IP space managed by this RIR is considered private')
) )
class Meta: class Meta:
@ -84,7 +85,7 @@ class ASN(PrimaryModel):
asn = ASNField( asn = ASNField(
unique=True, unique=True,
verbose_name='ASN', verbose_name='ASN',
help_text='32-bit autonomous system number' help_text=_('32-bit autonomous system number')
) )
rir = models.ForeignKey( rir = models.ForeignKey(
to='ipam.RIR', to='ipam.RIR',
@ -263,7 +264,7 @@ class Prefix(GetAvailablePrefixesMixin, PrimaryModel):
assigned to a VLAN where appropriate. assigned to a VLAN where appropriate.
""" """
prefix = IPNetworkField( prefix = IPNetworkField(
help_text='IPv4 or IPv6 network with mask' help_text=_('IPv4 or IPv6 network with mask')
) )
site = models.ForeignKey( site = models.ForeignKey(
to='dcim.Site', to='dcim.Site',
@ -300,7 +301,7 @@ class Prefix(GetAvailablePrefixesMixin, PrimaryModel):
choices=PrefixStatusChoices, choices=PrefixStatusChoices,
default=PrefixStatusChoices.STATUS_ACTIVE, default=PrefixStatusChoices.STATUS_ACTIVE,
verbose_name='Status', verbose_name='Status',
help_text='Operational status of this prefix' help_text=_('Operational status of this prefix')
) )
role = models.ForeignKey( role = models.ForeignKey(
to='ipam.Role', to='ipam.Role',
@ -308,16 +309,16 @@ class Prefix(GetAvailablePrefixesMixin, PrimaryModel):
related_name='prefixes', related_name='prefixes',
blank=True, blank=True,
null=True, null=True,
help_text='The primary function of this prefix' help_text=_('The primary function of this prefix')
) )
is_pool = models.BooleanField( is_pool = models.BooleanField(
verbose_name='Is a pool', verbose_name='Is a pool',
default=False, default=False,
help_text='All IP addresses within this prefix are considered usable' help_text=_('All IP addresses within this prefix are considered usable')
) )
mark_utilized = models.BooleanField( mark_utilized = models.BooleanField(
default=False, default=False,
help_text="Treat as 100% utilized" help_text=_("Treat as 100% utilized")
) )
# Cached depth & child counts # Cached depth & child counts
@ -538,10 +539,10 @@ class IPRange(PrimaryModel):
A range of IP addresses, defined by start and end addresses. A range of IP addresses, defined by start and end addresses.
""" """
start_address = IPAddressField( start_address = IPAddressField(
help_text='IPv4 or IPv6 address (with mask)' help_text=_('IPv4 or IPv6 address (with mask)')
) )
end_address = IPAddressField( end_address = IPAddressField(
help_text='IPv4 or IPv6 address (with mask)' help_text=_('IPv4 or IPv6 address (with mask)')
) )
size = models.PositiveIntegerField( size = models.PositiveIntegerField(
editable=False editable=False
@ -565,7 +566,7 @@ class IPRange(PrimaryModel):
max_length=50, max_length=50,
choices=IPRangeStatusChoices, choices=IPRangeStatusChoices,
default=IPRangeStatusChoices.STATUS_ACTIVE, default=IPRangeStatusChoices.STATUS_ACTIVE,
help_text='Operational status of this range' help_text=_('Operational status of this range')
) )
role = models.ForeignKey( role = models.ForeignKey(
to='ipam.Role', to='ipam.Role',
@ -573,7 +574,7 @@ class IPRange(PrimaryModel):
related_name='ip_ranges', related_name='ip_ranges',
blank=True, blank=True,
null=True, null=True,
help_text='The primary function of this range' help_text=_('The primary function of this range')
) )
clone_fields = ( clone_fields = (
@ -736,7 +737,7 @@ class IPAddress(PrimaryModel):
which has a NAT outside IP, that Interface's Device can use either the inside or outside IP as its primary IP. which has a NAT outside IP, that Interface's Device can use either the inside or outside IP as its primary IP.
""" """
address = IPAddressField( address = IPAddressField(
help_text='IPv4 or IPv6 address (with mask)' help_text=_('IPv4 or IPv6 address (with mask)')
) )
vrf = models.ForeignKey( vrf = models.ForeignKey(
to='ipam.VRF', to='ipam.VRF',
@ -757,13 +758,13 @@ class IPAddress(PrimaryModel):
max_length=50, max_length=50,
choices=IPAddressStatusChoices, choices=IPAddressStatusChoices,
default=IPAddressStatusChoices.STATUS_ACTIVE, default=IPAddressStatusChoices.STATUS_ACTIVE,
help_text='The operational status of this IP' help_text=_('The operational status of this IP')
) )
role = models.CharField( role = models.CharField(
max_length=50, max_length=50,
choices=IPAddressRoleChoices, choices=IPAddressRoleChoices,
blank=True, blank=True,
help_text='The functional role of this IP' help_text=_('The functional role of this IP')
) )
assigned_object_type = models.ForeignKey( assigned_object_type = models.ForeignKey(
to=ContentType, to=ContentType,
@ -788,14 +789,14 @@ class IPAddress(PrimaryModel):
blank=True, blank=True,
null=True, null=True,
verbose_name='NAT (Inside)', verbose_name='NAT (Inside)',
help_text='The IP for which this address is the "outside" IP' help_text=_('The IP for which this address is the "outside" IP')
) )
dns_name = models.CharField( dns_name = models.CharField(
max_length=255, max_length=255,
blank=True, blank=True,
validators=[DNSValidator], validators=[DNSValidator],
verbose_name='DNS Name', verbose_name='DNS Name',
help_text='Hostname or FQDN (not case-sensitive)' help_text=_('Hostname or FQDN (not case-sensitive)')
) )
objects = IPAddressManager() objects = IPAddressManager()

View File

@ -4,6 +4,7 @@ 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.urls import reverse from django.urls import reverse
from django.utils.translation import gettext as _
from dcim.models import Interface from dcim.models import Interface
from ipam.choices import * from ipam.choices import *
@ -50,7 +51,7 @@ class VLANGroup(OrganizationalModel):
MinValueValidator(VLAN_VID_MIN), MinValueValidator(VLAN_VID_MIN),
MaxValueValidator(VLAN_VID_MAX) MaxValueValidator(VLAN_VID_MAX)
), ),
help_text='Lowest permissible ID of a child VLAN' help_text=_('Lowest permissible ID of a child VLAN')
) )
max_vid = models.PositiveSmallIntegerField( max_vid = models.PositiveSmallIntegerField(
verbose_name='Maximum VLAN ID', verbose_name='Maximum VLAN ID',
@ -59,7 +60,7 @@ class VLANGroup(OrganizationalModel):
MinValueValidator(VLAN_VID_MIN), MinValueValidator(VLAN_VID_MIN),
MaxValueValidator(VLAN_VID_MAX) MaxValueValidator(VLAN_VID_MAX)
), ),
help_text='Highest permissible ID of a child VLAN' help_text=_('Highest permissible ID of a child VLAN')
) )
class Meta: class Meta:

View File

@ -1,5 +1,6 @@
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 ipam.constants import * from ipam.constants import *
from netbox.models import PrimaryModel from netbox.models import PrimaryModel
@ -26,7 +27,7 @@ class VRF(PrimaryModel):
blank=True, blank=True,
null=True, null=True,
verbose_name='Route distinguisher', verbose_name='Route distinguisher',
help_text='Unique route distinguisher (as defined in RFC 4364)' help_text=_('Unique route distinguisher (as defined in RFC 4364)')
) )
tenant = models.ForeignKey( tenant = models.ForeignKey(
to='tenancy.Tenant', to='tenancy.Tenant',
@ -38,7 +39,7 @@ class VRF(PrimaryModel):
enforce_unique = models.BooleanField( enforce_unique = models.BooleanField(
default=True, default=True,
verbose_name='Enforce unique space', verbose_name='Enforce unique space',
help_text='Prevent duplicate prefixes/IP addresses within this VRF' help_text=_('Prevent duplicate prefixes/IP addresses within this VRF')
) )
import_targets = models.ManyToManyField( import_targets = models.ManyToManyField(
to='ipam.RouteTarget', to='ipam.RouteTarget',
@ -76,7 +77,7 @@ class RouteTarget(PrimaryModel):
name = models.CharField( name = models.CharField(
max_length=VRF_RD_MAX_LENGTH, # Same format options as VRF RD (RFC 4360 section 4) max_length=VRF_RD_MAX_LENGTH, # Same format options as VRF RD (RFC 4360 section 4)
unique=True, unique=True,
help_text='Route target value (formatted in accordance with RFC 4360)' help_text=_('Route target value (formatted in accordance with RFC 4360)')
) )
tenant = models.ForeignKey( tenant = models.ForeignKey(
to='tenancy.Tenant', to='tenancy.Tenant',

View File

@ -1,5 +1,6 @@
from django import forms from django import forms
from django.contrib.postgres.forms import SimpleArrayField from django.contrib.postgres.forms import SimpleArrayField
from django.utils.translation import gettext_lazy as _
class ConfigParam: class ConfigParam:
@ -18,9 +19,9 @@ PARAMS = (
# Banners # Banners
ConfigParam( ConfigParam(
name='BANNER_LOGIN', name='BANNER_LOGIN',
label='Login banner', label=_('Login banner'),
default='', default='',
description="Additional content to display on the login page", description=_("Additional content to display on the login page"),
field_kwargs={ field_kwargs={
'widget': forms.Textarea( 'widget': forms.Textarea(
attrs={'class': 'vLargeTextField'} attrs={'class': 'vLargeTextField'}
@ -29,9 +30,9 @@ PARAMS = (
), ),
ConfigParam( ConfigParam(
name='BANNER_TOP', name='BANNER_TOP',
label='Top banner', label=_('Top banner'),
default='', default='',
description="Additional content to display at the top of every page", description=_("Additional content to display at the top of every page"),
field_kwargs={ field_kwargs={
'widget': forms.Textarea( 'widget': forms.Textarea(
attrs={'class': 'vLargeTextField'} attrs={'class': 'vLargeTextField'}
@ -40,9 +41,9 @@ PARAMS = (
), ),
ConfigParam( ConfigParam(
name='BANNER_BOTTOM', name='BANNER_BOTTOM',
label='Bottom banner', label=_('Bottom banner'),
default='', default='',
description="Additional content to display at the bottom of every page", description=_("Additional content to display at the bottom of every page"),
field_kwargs={ field_kwargs={
'widget': forms.Textarea( 'widget': forms.Textarea(
attrs={'class': 'vLargeTextField'} attrs={'class': 'vLargeTextField'}
@ -53,69 +54,69 @@ PARAMS = (
# IPAM # IPAM
ConfigParam( ConfigParam(
name='ENFORCE_GLOBAL_UNIQUE', name='ENFORCE_GLOBAL_UNIQUE',
label='Globally unique IP space', label=_('Globally unique IP space'),
default=False, default=False,
description="Enforce unique IP addressing within the global table", description=_("Enforce unique IP addressing within the global table"),
field=forms.BooleanField field=forms.BooleanField
), ),
ConfigParam( ConfigParam(
name='PREFER_IPV4', name='PREFER_IPV4',
label='Prefer IPv4', label=_('Prefer IPv4'),
default=False, default=False,
description="Prefer IPv4 addresses over IPv6", description=_("Prefer IPv4 addresses over IPv6"),
field=forms.BooleanField field=forms.BooleanField
), ),
# Racks # Racks
ConfigParam( ConfigParam(
name='RACK_ELEVATION_DEFAULT_UNIT_HEIGHT', name='RACK_ELEVATION_DEFAULT_UNIT_HEIGHT',
label='Rack unit height', label=_('Rack unit height'),
default=22, default=22,
description="Default unit height for rendered rack elevations", description=_("Default unit height for rendered rack elevations"),
field=forms.IntegerField field=forms.IntegerField
), ),
ConfigParam( ConfigParam(
name='RACK_ELEVATION_DEFAULT_UNIT_WIDTH', name='RACK_ELEVATION_DEFAULT_UNIT_WIDTH',
label='Rack unit width', label=_('Rack unit width'),
default=220, default=220,
description="Default unit width for rendered rack elevations", description=_("Default unit width for rendered rack elevations"),
field=forms.IntegerField field=forms.IntegerField
), ),
# Power # Power
ConfigParam( ConfigParam(
name='POWERFEED_DEFAULT_VOLTAGE', name='POWERFEED_DEFAULT_VOLTAGE',
label='Powerfeed voltage', label=_('Powerfeed voltage'),
default=120, default=120,
description="Default voltage for powerfeeds", description=_("Default voltage for powerfeeds"),
field=forms.IntegerField field=forms.IntegerField
), ),
ConfigParam( ConfigParam(
name='POWERFEED_DEFAULT_AMPERAGE', name='POWERFEED_DEFAULT_AMPERAGE',
label='Powerfeed amperage', label=_('Powerfeed amperage'),
default=15, default=15,
description="Default amperage for powerfeeds", description=_("Default amperage for powerfeeds"),
field=forms.IntegerField field=forms.IntegerField
), ),
ConfigParam( ConfigParam(
name='POWERFEED_DEFAULT_MAX_UTILIZATION', name='POWERFEED_DEFAULT_MAX_UTILIZATION',
label='Powerfeed max utilization', label=_('Powerfeed max utilization'),
default=80, default=80,
description="Default max utilization for powerfeeds", description=_("Default max utilization for powerfeeds"),
field=forms.IntegerField field=forms.IntegerField
), ),
# Security # Security
ConfigParam( ConfigParam(
name='ALLOWED_URL_SCHEMES', name='ALLOWED_URL_SCHEMES',
label='Allowed URL schemes', label=_('Allowed URL schemes'),
default=( default=(
'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc', 'file', 'ftp', 'ftps', 'http', 'https', 'irc', 'mailto', 'sftp', 'ssh', 'tel', 'telnet', 'tftp', 'vnc',
'xmpp', 'xmpp',
), ),
description="Permitted schemes for URLs in user-provided content", description=_("Permitted schemes for URLs in user-provided content"),
field=SimpleArrayField, field=SimpleArrayField,
field_kwargs={'base_field': forms.CharField()} field_kwargs={'base_field': forms.CharField()}
), ),
@ -123,13 +124,13 @@ PARAMS = (
# Pagination # Pagination
ConfigParam( ConfigParam(
name='PAGINATE_COUNT', name='PAGINATE_COUNT',
label='Default page size', label=_('Default page size'),
default=50, default=50,
field=forms.IntegerField field=forms.IntegerField
), ),
ConfigParam( ConfigParam(
name='MAX_PAGE_SIZE', name='MAX_PAGE_SIZE',
label='Maximum page size', label=_('Maximum page size'),
default=1000, default=1000,
field=forms.IntegerField field=forms.IntegerField
), ),
@ -137,9 +138,9 @@ PARAMS = (
# Validation # Validation
ConfigParam( ConfigParam(
name='CUSTOM_VALIDATORS', name='CUSTOM_VALIDATORS',
label='Custom validators', label=_('Custom validators'),
default={}, default={},
description="Custom validation rules (JSON)", description=_("Custom validation rules (JSON)"),
field=forms.JSONField, field=forms.JSONField,
field_kwargs={ field_kwargs={
'widget': forms.Textarea( 'widget': forms.Textarea(
@ -151,28 +152,28 @@ PARAMS = (
# NAPALM # NAPALM
ConfigParam( ConfigParam(
name='NAPALM_USERNAME', name='NAPALM_USERNAME',
label='NAPALM username', label=_('NAPALM username'),
default='', default='',
description="Username to use when connecting to devices via NAPALM" description=_("Username to use when connecting to devices via NAPALM")
), ),
ConfigParam( ConfigParam(
name='NAPALM_PASSWORD', name='NAPALM_PASSWORD',
label='NAPALM password', label=_('NAPALM password'),
default='', default='',
description="Password to use when connecting to devices via NAPALM" description=_("Password to use when connecting to devices via NAPALM")
), ),
ConfigParam( ConfigParam(
name='NAPALM_TIMEOUT', name='NAPALM_TIMEOUT',
label='NAPALM timeout', label=_('NAPALM timeout'),
default=30, default=30,
description="NAPALM connection timeout (in seconds)", description=_("NAPALM connection timeout (in seconds)"),
field=forms.IntegerField field=forms.IntegerField
), ),
ConfigParam( ConfigParam(
name='NAPALM_ARGS', name='NAPALM_ARGS',
label='NAPALM arguments', label=_('NAPALM arguments'),
default={}, default={},
description="Additional arguments to pass when invoking a NAPALM driver (as JSON data)", description=_("Additional arguments to pass when invoking a NAPALM driver (as JSON data)"),
field=forms.JSONField, field=forms.JSONField,
field_kwargs={ field_kwargs={
'widget': forms.Textarea( 'widget': forms.Textarea(
@ -184,46 +185,46 @@ PARAMS = (
# User preferences # User preferences
ConfigParam( ConfigParam(
name='DEFAULT_USER_PREFERENCES', name='DEFAULT_USER_PREFERENCES',
label='Default preferences', label=_('Default preferences'),
default={}, default={},
description="Default preferences for new users", description=_("Default preferences for new users"),
field=forms.JSONField field=forms.JSONField
), ),
# Miscellaneous # Miscellaneous
ConfigParam( ConfigParam(
name='MAINTENANCE_MODE', name='MAINTENANCE_MODE',
label='Maintenance mode', label=_('Maintenance mode'),
default=False, default=False,
description="Enable maintenance mode", description=_("Enable maintenance mode"),
field=forms.BooleanField field=forms.BooleanField
), ),
ConfigParam( ConfigParam(
name='GRAPHQL_ENABLED', name='GRAPHQL_ENABLED',
label='GraphQL enabled', label=_('GraphQL enabled'),
default=True, default=True,
description="Enable the GraphQL API", description=_("Enable the GraphQL API"),
field=forms.BooleanField field=forms.BooleanField
), ),
ConfigParam( ConfigParam(
name='CHANGELOG_RETENTION', name='CHANGELOG_RETENTION',
label='Changelog retention', label=_('Changelog retention'),
default=90, default=90,
description="Days to retain changelog history (set to zero for unlimited)", description=_("Days to retain changelog history (set to zero for unlimited)"),
field=forms.IntegerField field=forms.IntegerField
), ),
ConfigParam( ConfigParam(
name='JOBRESULT_RETENTION', name='JOBRESULT_RETENTION',
label='Job result retention', label=_('Job result retention'),
default=90, default=90,
description="Days to retain job result history (set to zero for unlimited)", description=_("Days to retain job result history (set to zero for unlimited)"),
field=forms.IntegerField field=forms.IntegerField
), ),
ConfigParam( ConfigParam(
name='MAPS_URL', name='MAPS_URL',
label='Maps URL', label=_('Maps URL'),
default='https://maps.google.com/?q=', default='https://maps.google.com/?q=',
description="Base URL for mapping geographic locations" description=_("Base URL for mapping geographic locations")
), ),
) )

View File

@ -5,6 +5,7 @@ from django.db import models
from django_filters.exceptions import FieldLookupError from django_filters.exceptions import FieldLookupError
from django_filters.utils import get_model_field, resolve_field from django_filters.utils import get_model_field, resolve_field
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.utils.translation import gettext as _
from extras.choices import CustomFieldFilterLogicChoices from extras.choices import CustomFieldFilterLogicChoices
from extras.filters import TagFilter from extras.filters import TagFilter
@ -235,7 +236,7 @@ class NetBoxModelFilterSet(ChangeLoggedModelFilterSet):
""" """
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
tag = TagFilter() tag = TagFilter()

View File

@ -17,7 +17,7 @@ LOOKUP_CHOICES = (
class SearchForm(BootstrapMixin, forms.Form): class SearchForm(BootstrapMixin, forms.Form):
q = forms.CharField( q = forms.CharField(
label='Search', label=_('Search'),
widget=forms.TextInput( widget=forms.TextInput(
attrs={ attrs={
'hx-get': '', 'hx-get': '',
@ -29,7 +29,7 @@ class SearchForm(BootstrapMixin, forms.Form):
obj_types = forms.MultipleChoiceField( obj_types = forms.MultipleChoiceField(
choices=[], choices=[],
required=False, required=False,
label='Object type(s)', label=_('Object type(s)'),
widget=StaticSelectMultiple() widget=StaticSelectMultiple()
) )
lookup = forms.ChoiceField( lookup = forms.ChoiceField(

View File

@ -2,6 +2,7 @@ from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _
from extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices, CustomFieldVisibilityChoices from extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices, CustomFieldVisibilityChoices
from extras.forms.mixins import CustomFieldsMixin, SavedFiltersMixin from extras.forms.mixins import CustomFieldsMixin, SavedFiltersMixin
@ -132,7 +133,7 @@ class NetBoxModelFilterSetForm(BootstrapMixin, CustomFieldsMixin, SavedFiltersMi
""" """
q = forms.CharField( q = forms.CharField(
required=False, required=False,
label='Search' label=_('Search')
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@ -1,119 +1,120 @@
from django.utils.translation import gettext as _
from netbox.registry import registry from netbox.registry import registry
from . import * from . import *
# #
# Nav menus # Nav menus
# #
ORGANIZATION_MENU = Menu( ORGANIZATION_MENU = Menu(
label='Organization', label=_('Organization'),
icon_class='mdi mdi-domain', icon_class='mdi mdi-domain',
groups=( groups=(
MenuGroup( MenuGroup(
label='Sites', label=_('Sites'),
items=( items=(
get_model_item('dcim', 'site', 'Sites'), get_model_item('dcim', 'site', _('Sites')),
get_model_item('dcim', 'region', 'Regions'), get_model_item('dcim', 'region', _('Regions')),
get_model_item('dcim', 'sitegroup', 'Site Groups'), get_model_item('dcim', 'sitegroup', _('Site Groups')),
get_model_item('dcim', 'location', 'Locations'), get_model_item('dcim', 'location', _('Locations')),
), ),
), ),
MenuGroup( MenuGroup(
label='Racks', label=_('Racks'),
items=( items=(
get_model_item('dcim', 'rack', 'Racks'), get_model_item('dcim', 'rack', _('Racks')),
get_model_item('dcim', 'rackrole', 'Rack Roles'), get_model_item('dcim', 'rackrole', _('Rack Roles')),
get_model_item('dcim', 'rackreservation', 'Reservations'), get_model_item('dcim', 'rackreservation', _('Reservations')),
MenuItem( MenuItem(
link='dcim:rack_elevation_list', link='dcim:rack_elevation_list',
link_text='Elevations', link_text=_('Elevations'),
permissions=['dcim.view_rack'] permissions=['dcim.view_rack']
), ),
), ),
), ),
MenuGroup( MenuGroup(
label='Tenancy', label=_('Tenancy'),
items=( items=(
get_model_item('tenancy', 'tenant', 'Tenants'), get_model_item('tenancy', 'tenant', _('Tenants')),
get_model_item('tenancy', 'tenantgroup', 'Tenant Groups'), get_model_item('tenancy', 'tenantgroup', _('Tenant Groups')),
), ),
), ),
MenuGroup( MenuGroup(
label='Contacts', label=_('Contacts'),
items=( items=(
get_model_item('tenancy', 'contact', 'Contacts'), get_model_item('tenancy', 'contact', _('Contacts')),
get_model_item('tenancy', 'contactgroup', 'Contact Groups'), get_model_item('tenancy', 'contactgroup', _('Contact Groups')),
get_model_item('tenancy', 'contactrole', 'Contact Roles'), get_model_item('tenancy', 'contactrole', _('Contact Roles')),
), ),
), ),
), ),
) )
DEVICES_MENU = Menu( DEVICES_MENU = Menu(
label='Devices', label=_('Devices'),
icon_class='mdi mdi-server', icon_class='mdi mdi-server',
groups=( groups=(
MenuGroup( MenuGroup(
label='Devices', label=_('Devices'),
items=( items=(
get_model_item('dcim', 'device', 'Devices'), get_model_item('dcim', 'device', _('Devices')),
get_model_item('dcim', 'module', 'Modules'), get_model_item('dcim', 'module', _('Modules')),
get_model_item('dcim', 'devicerole', 'Device Roles'), get_model_item('dcim', 'devicerole', _('Device Roles')),
get_model_item('dcim', 'platform', 'Platforms'), get_model_item('dcim', 'platform', _('Platforms')),
get_model_item('dcim', 'virtualchassis', 'Virtual Chassis'), get_model_item('dcim', 'virtualchassis', _('Virtual Chassis')),
get_model_item('dcim', 'virtualdevicecontext', 'Virtual Device Contexts'), get_model_item('dcim', 'virtualdevicecontext', _('Virtual Device Contexts')),
), ),
), ),
MenuGroup( MenuGroup(
label='Device Types', label=_('Device Types'),
items=( items=(
get_model_item('dcim', 'devicetype', 'Device Types'), get_model_item('dcim', 'devicetype', _('Device Types')),
get_model_item('dcim', 'moduletype', 'Module Types'), get_model_item('dcim', 'moduletype', _('Module Types')),
get_model_item('dcim', 'manufacturer', 'Manufacturers'), get_model_item('dcim', 'manufacturer', _('Manufacturers')),
), ),
), ),
MenuGroup( MenuGroup(
label='Device Components', label=_('Device Components'),
items=( items=(
get_model_item('dcim', 'interface', 'Interfaces', actions=['import']), get_model_item('dcim', 'interface', _('Interfaces'), actions=['import']),
get_model_item('dcim', 'frontport', 'Front Ports', actions=['import']), get_model_item('dcim', 'frontport', _('Front Ports'), actions=['import']),
get_model_item('dcim', 'rearport', 'Rear Ports', actions=['import']), get_model_item('dcim', 'rearport', _('Rear Ports'), actions=['import']),
get_model_item('dcim', 'consoleport', 'Console Ports', actions=['import']), get_model_item('dcim', 'consoleport', _('Console Ports'), actions=['import']),
get_model_item('dcim', 'consoleserverport', 'Console Server Ports', actions=['import']), get_model_item('dcim', 'consoleserverport', _('Console Server Ports'), actions=['import']),
get_model_item('dcim', 'powerport', 'Power Ports', actions=['import']), get_model_item('dcim', 'powerport', _('Power Ports'), actions=['import']),
get_model_item('dcim', 'poweroutlet', 'Power Outlets', actions=['import']), get_model_item('dcim', 'poweroutlet', _('Power Outlets'), actions=['import']),
get_model_item('dcim', 'modulebay', 'Module Bays', actions=['import']), get_model_item('dcim', 'modulebay', _('Module Bays'), actions=['import']),
get_model_item('dcim', 'devicebay', 'Device Bays', actions=['import']), get_model_item('dcim', 'devicebay', _('Device Bays'), actions=['import']),
get_model_item('dcim', 'inventoryitem', 'Inventory Items', actions=['import']), get_model_item('dcim', 'inventoryitem', _('Inventory Items'), actions=['import']),
get_model_item('dcim', 'inventoryitemrole', 'Inventory Item Roles'), get_model_item('dcim', 'inventoryitemrole', _('Inventory Item Roles')),
), ),
), ),
), ),
) )
CONNECTIONS_MENU = Menu( CONNECTIONS_MENU = Menu(
label='Connections', label=_('Connections'),
icon_class='mdi mdi-connection', icon_class='mdi mdi-connection',
groups=( groups=(
MenuGroup( MenuGroup(
label='Connections', label=_('Connections'),
items=( items=(
get_model_item('dcim', 'cable', 'Cables', actions=['import']), get_model_item('dcim', 'cable', _('Cables'), actions=['import']),
get_model_item('wireless', 'wirelesslink', 'Wireless Links', actions=['import']), get_model_item('wireless', 'wirelesslink', _('Wireless Links'), actions=['import']),
MenuItem( MenuItem(
link='dcim:interface_connections_list', link='dcim:interface_connections_list',
link_text='Interface Connections', link_text=_('Interface Connections'),
permissions=['dcim.view_interface'] permissions=['dcim.view_interface']
), ),
MenuItem( MenuItem(
link='dcim:console_connections_list', link='dcim:console_connections_list',
link_text='Console Connections', link_text=_('Console Connections'),
permissions=['dcim.view_consoleport'] permissions=['dcim.view_consoleport']
), ),
MenuItem( MenuItem(
link='dcim:power_connections_list', link='dcim:power_connections_list',
link_text='Power Connections', link_text=_('Power Connections'),
permissions=['dcim.view_powerport'] permissions=['dcim.view_powerport']
), ),
), ),
@ -122,192 +123,192 @@ CONNECTIONS_MENU = Menu(
) )
WIRELESS_MENU = Menu( WIRELESS_MENU = Menu(
label='Wireless', label=_('Wireless'),
icon_class='mdi mdi-wifi', icon_class='mdi mdi-wifi',
groups=( groups=(
MenuGroup( MenuGroup(
label='Wireless', label=_('Wireless'),
items=( items=(
get_model_item('wireless', 'wirelesslan', 'Wireless LANs'), get_model_item('wireless', 'wirelesslan', _('Wireless LANs')),
get_model_item('wireless', 'wirelesslangroup', 'Wireless LAN Groups'), get_model_item('wireless', 'wirelesslangroup', _('Wireless LAN Groups')),
), ),
), ),
), ),
) )
IPAM_MENU = Menu( IPAM_MENU = Menu(
label='IPAM', label=_('IPAM'),
icon_class='mdi mdi-counter', icon_class='mdi mdi-counter',
groups=( groups=(
MenuGroup( MenuGroup(
label='IP Addresses', label=_('IP Addresses'),
items=( items=(
get_model_item('ipam', 'ipaddress', 'IP Addresses'), get_model_item('ipam', 'ipaddress', _('IP Addresses')),
get_model_item('ipam', 'iprange', 'IP Ranges'), get_model_item('ipam', 'iprange', _('IP Ranges')),
), ),
), ),
MenuGroup( MenuGroup(
label='Prefixes', label=_('Prefixes'),
items=( items=(
get_model_item('ipam', 'prefix', 'Prefixes'), get_model_item('ipam', 'prefix', _('Prefixes')),
get_model_item('ipam', 'role', 'Prefix & VLAN Roles'), get_model_item('ipam', 'role', _('Prefix & VLAN Roles')),
), ),
), ),
MenuGroup( MenuGroup(
label='ASNs', label=_('ASNs'),
items=( items=(
get_model_item('ipam', 'asn', 'ASNs'), get_model_item('ipam', 'asn', _('ASNs')),
), ),
), ),
MenuGroup( MenuGroup(
label='Aggregates', label=_('Aggregates'),
items=( items=(
get_model_item('ipam', 'aggregate', 'Aggregates'), get_model_item('ipam', 'aggregate', _('Aggregates')),
get_model_item('ipam', 'rir', 'RIRs'), get_model_item('ipam', 'rir', _('RIRs')),
), ),
), ),
MenuGroup( MenuGroup(
label='VRFs', label=_('VRFs'),
items=( items=(
get_model_item('ipam', 'vrf', 'VRFs'), get_model_item('ipam', 'vrf', _('VRFs')),
get_model_item('ipam', 'routetarget', 'Route Targets'), get_model_item('ipam', 'routetarget', _('Route Targets')),
), ),
), ),
MenuGroup( MenuGroup(
label='VLANs', label=_('VLANs'),
items=( items=(
get_model_item('ipam', 'vlan', 'VLANs'), get_model_item('ipam', 'vlan', _('VLANs')),
get_model_item('ipam', 'vlangroup', 'VLAN Groups'), get_model_item('ipam', 'vlangroup', _('VLAN Groups')),
), ),
), ),
MenuGroup( MenuGroup(
label='Other', label=_('Other'),
items=( items=(
get_model_item('ipam', 'fhrpgroup', 'FHRP Groups'), get_model_item('ipam', 'fhrpgroup', _('FHRP Groups')),
get_model_item('ipam', 'servicetemplate', 'Service Templates'), get_model_item('ipam', 'servicetemplate', _('Service Templates')),
get_model_item('ipam', 'service', 'Services'), get_model_item('ipam', 'service', _('Services')),
), ),
), ),
), ),
) )
OVERLAY_MENU = Menu( OVERLAY_MENU = Menu(
label='Overlay', label=_('Overlay'),
icon_class='mdi mdi-graph-outline', icon_class='mdi mdi-graph-outline',
groups=( groups=(
MenuGroup( MenuGroup(
label='L2VPNs', label='L2VPNs',
items=( items=(
get_model_item('ipam', 'l2vpn', 'L2VPNs'), get_model_item('ipam', 'l2vpn', _('L2VPNs')),
get_model_item('ipam', 'l2vpntermination', 'Terminations'), get_model_item('ipam', 'l2vpntermination', _('Terminations')),
), ),
), ),
), ),
) )
VIRTUALIZATION_MENU = Menu( VIRTUALIZATION_MENU = Menu(
label='Virtualization', label=_('Virtualization'),
icon_class='mdi mdi-monitor', icon_class='mdi mdi-monitor',
groups=( groups=(
MenuGroup( MenuGroup(
label='Virtual Machines', label=_('Virtual Machines'),
items=( items=(
get_model_item('virtualization', 'virtualmachine', 'Virtual Machines'), get_model_item('virtualization', 'virtualmachine', _('Virtual Machines')),
get_model_item('virtualization', 'vminterface', 'Interfaces', actions=['import']), get_model_item('virtualization', 'vminterface', _('Interfaces'), actions=['import']),
), ),
), ),
MenuGroup( MenuGroup(
label='Clusters', label=_('Clusters'),
items=( items=(
get_model_item('virtualization', 'cluster', 'Clusters'), get_model_item('virtualization', 'cluster', _('Clusters')),
get_model_item('virtualization', 'clustertype', 'Cluster Types'), get_model_item('virtualization', 'clustertype', _('Cluster Types')),
get_model_item('virtualization', 'clustergroup', 'Cluster Groups'), get_model_item('virtualization', 'clustergroup', _('Cluster Groups')),
), ),
), ),
), ),
) )
CIRCUITS_MENU = Menu( CIRCUITS_MENU = Menu(
label='Circuits', label=_('Circuits'),
icon_class='mdi mdi-transit-connection-variant', icon_class='mdi mdi-transit-connection-variant',
groups=( groups=(
MenuGroup( MenuGroup(
label='Circuits', label=_('Circuits'),
items=( items=(
get_model_item('circuits', 'circuit', 'Circuits'), get_model_item('circuits', 'circuit', _('Circuits')),
get_model_item('circuits', 'circuittype', 'Circuit Types'), get_model_item('circuits', 'circuittype', _('Circuit Types')),
), ),
), ),
MenuGroup( MenuGroup(
label='Providers', label=_('Providers'),
items=( items=(
get_model_item('circuits', 'provider', 'Providers'), get_model_item('circuits', 'provider', _('Providers')),
get_model_item('circuits', 'providernetwork', 'Provider Networks'), get_model_item('circuits', 'providernetwork', _('Provider Networks')),
), ),
), ),
), ),
) )
POWER_MENU = Menu( POWER_MENU = Menu(
label='Power', label=_('Power'),
icon_class='mdi mdi-flash', icon_class='mdi mdi-flash',
groups=( groups=(
MenuGroup( MenuGroup(
label='Power', label=_('Power'),
items=( items=(
get_model_item('dcim', 'powerfeed', 'Power Feeds'), get_model_item('dcim', 'powerfeed', _('Power Feeds')),
get_model_item('dcim', 'powerpanel', 'Power Panels'), get_model_item('dcim', 'powerpanel', _('Power Panels')),
), ),
), ),
), ),
) )
OTHER_MENU = Menu( OTHER_MENU = Menu(
label='Other', label=_('Other'),
icon_class='mdi mdi-notification-clear-all', icon_class='mdi mdi-notification-clear-all',
groups=( groups=(
MenuGroup( MenuGroup(
label='Logging', label=_('Logging'),
items=( items=(
get_model_item('extras', 'journalentry', 'Journal Entries', actions=[]), get_model_item('extras', 'journalentry', _('Journal Entries'), actions=[]),
get_model_item('extras', 'objectchange', 'Change Log', actions=[]), get_model_item('extras', 'objectchange', _('Change Log'), actions=[]),
), ),
), ),
MenuGroup( MenuGroup(
label='Customization', label=_('Customization'),
items=( items=(
get_model_item('extras', 'customfield', 'Custom Fields'), get_model_item('extras', 'customfield', _('Custom Fields')),
get_model_item('extras', 'customlink', 'Custom Links'), get_model_item('extras', 'customlink', _('Custom Links')),
get_model_item('extras', 'exporttemplate', 'Export Templates'), get_model_item('extras', 'exporttemplate', _('Export Templates')),
get_model_item('extras', 'savedfilter', 'Saved Filters'), get_model_item('extras', 'savedfilter', _('Saved Filters')),
), ),
), ),
MenuGroup( MenuGroup(
label='Integrations', label=_('Integrations'),
items=( items=(
get_model_item('extras', 'webhook', 'Webhooks'), get_model_item('extras', 'webhook', _('Webhooks')),
MenuItem( MenuItem(
link='extras:report_list', link='extras:report_list',
link_text='Reports', link_text=_('Reports'),
permissions=['extras.view_report'] permissions=['extras.view_report']
), ),
MenuItem( MenuItem(
link='extras:script_list', link='extras:script_list',
link_text='Scripts', link_text=_('Scripts'),
permissions=['extras.view_script'] permissions=['extras.view_script']
), ),
MenuItem( MenuItem(
link='extras:jobresult_list', link='extras:jobresult_list',
link_text='Job Results', link_text=_('Job Results'),
permissions=['extras.view_jobresult'], permissions=['extras.view_jobresult'],
), ),
), ),
), ),
MenuGroup( MenuGroup(
label='Other', label=_('Other'),
items=( items=(
get_model_item('extras', 'tag', 'Tags'), get_model_item('extras', 'tag', 'Tags'),
get_model_item('extras', 'configcontext', 'Config Contexts', actions=['add']), get_model_item('extras', 'configcontext', _('Config Contexts'), actions=['add']),
), ),
), ),
), ),
@ -342,7 +343,7 @@ if registry['plugins']['menu_items']:
for label, items in registry['plugins']['menu_items'].items() for label, items in registry['plugins']['menu_items'].items()
] ]
plugins_menu = Menu( plugins_menu = Menu(
label="Plugins", label=_("Plugins"),
icon_class="mdi mdi-puzzle", icon_class="mdi mdi-puzzle",
groups=groups groups=groups
) )

View File

@ -1,3 +1,4 @@
from django.utils.translation import gettext as _
from netbox.registry import registry from netbox.registry import registry
from users.preferences import UserPreference from users.preferences import UserPreference
from utilities.paginator import EnhancedPaginator from utilities.paginator import EnhancedPaginator
@ -13,7 +14,7 @@ PREFERENCES = {
# User interface # User interface
'ui.colormode': UserPreference( 'ui.colormode': UserPreference(
label='Color mode', label=_('Color mode'),
choices=( choices=(
('light', 'Light'), ('light', 'Light'),
('dark', 'Dark'), ('dark', 'Dark'),
@ -21,25 +22,25 @@ PREFERENCES = {
default='light', default='light',
), ),
'pagination.per_page': UserPreference( 'pagination.per_page': UserPreference(
label='Page length', label=_('Page length'),
choices=get_page_lengths(), choices=get_page_lengths(),
description='The number of objects to display per page', description=_('The number of objects to display per page'),
coerce=lambda x: int(x) coerce=lambda x: int(x)
), ),
'pagination.placement': UserPreference( 'pagination.placement': UserPreference(
label='Paginator placement', label=_('Paginator placement'),
choices=( choices=(
('bottom', 'Bottom'), ('bottom', 'Bottom'),
('top', 'Top'), ('top', 'Top'),
('both', 'Both'), ('both', 'Both'),
), ),
description='Where the paginator controls will be displayed relative to a table', description=_('Where the paginator controls will be displayed relative to a table'),
default='bottom' default='bottom'
), ),
# Miscellaneous # Miscellaneous
'data_format': UserPreference( 'data_format': UserPreference(
label='Data format', label=_('Data format'),
choices=( choices=(
('json', 'JSON'), ('json', 'JSON'),
('yaml', 'YAML'), ('yaml', 'YAML'),

View File

@ -1,5 +1,6 @@
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _
from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet
from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter
@ -25,13 +26,13 @@ __all__ = (
class ContactGroupFilterSet(OrganizationalModelFilterSet): class ContactGroupFilterSet(OrganizationalModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=ContactGroup.objects.all(), queryset=ContactGroup.objects.all(),
label='Contact group (ID)', label=_('Contact group (ID)'),
) )
parent = django_filters.ModelMultipleChoiceFilter( parent = django_filters.ModelMultipleChoiceFilter(
field_name='parent__slug', field_name='parent__slug',
queryset=ContactGroup.objects.all(), queryset=ContactGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Contact group (slug)', label=_('Contact group (slug)'),
) )
class Meta: class Meta:
@ -51,14 +52,14 @@ class ContactFilterSet(NetBoxModelFilterSet):
queryset=ContactGroup.objects.all(), queryset=ContactGroup.objects.all(),
field_name='group', field_name='group',
lookup_expr='in', lookup_expr='in',
label='Contact group (ID)', label=_('Contact group (ID)'),
) )
group = TreeNodeMultipleChoiceFilter( group = TreeNodeMultipleChoiceFilter(
queryset=ContactGroup.objects.all(), queryset=ContactGroup.objects.all(),
field_name='group', field_name='group',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Contact group (slug)', label=_('Contact group (slug)'),
) )
class Meta: class Meta:
@ -83,17 +84,17 @@ class ContactAssignmentFilterSet(ChangeLoggedModelFilterSet):
content_type = ContentTypeFilter() content_type = ContentTypeFilter()
contact_id = django_filters.ModelMultipleChoiceFilter( contact_id = django_filters.ModelMultipleChoiceFilter(
queryset=Contact.objects.all(), queryset=Contact.objects.all(),
label='Contact (ID)', label=_('Contact (ID)'),
) )
role_id = django_filters.ModelMultipleChoiceFilter( role_id = django_filters.ModelMultipleChoiceFilter(
queryset=ContactRole.objects.all(), queryset=ContactRole.objects.all(),
label='Contact role (ID)', label=_('Contact role (ID)'),
) )
role = django_filters.ModelMultipleChoiceFilter( role = django_filters.ModelMultipleChoiceFilter(
field_name='role__slug', field_name='role__slug',
queryset=ContactRole.objects.all(), queryset=ContactRole.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Contact role (slug)', label=_('Contact role (slug)'),
) )
class Meta: class Meta:
@ -105,18 +106,18 @@ class ContactModelFilterSet(django_filters.FilterSet):
contact = django_filters.ModelMultipleChoiceFilter( contact = django_filters.ModelMultipleChoiceFilter(
field_name='contacts__contact', field_name='contacts__contact',
queryset=Contact.objects.all(), queryset=Contact.objects.all(),
label='Contact', label=_('Contact'),
) )
contact_role = django_filters.ModelMultipleChoiceFilter( contact_role = django_filters.ModelMultipleChoiceFilter(
field_name='contacts__role', field_name='contacts__role',
queryset=ContactRole.objects.all(), queryset=ContactRole.objects.all(),
label='Contact Role' label=_('Contact Role')
) )
contact_group = TreeNodeMultipleChoiceFilter( contact_group = TreeNodeMultipleChoiceFilter(
queryset=ContactGroup.objects.all(), queryset=ContactGroup.objects.all(),
field_name='contacts__contact__group', field_name='contacts__contact__group',
lookup_expr='in', lookup_expr='in',
label='Contact group', label=_('Contact group'),
) )
@ -127,13 +128,13 @@ class ContactModelFilterSet(django_filters.FilterSet):
class TenantGroupFilterSet(OrganizationalModelFilterSet): class TenantGroupFilterSet(OrganizationalModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
label='Tenant group (ID)', label=_('Tenant group (ID)'),
) )
parent = django_filters.ModelMultipleChoiceFilter( parent = django_filters.ModelMultipleChoiceFilter(
field_name='parent__slug', field_name='parent__slug',
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Tenant group (slug)', label=_('Tenant group (slug)'),
) )
class Meta: class Meta:
@ -146,14 +147,14 @@ class TenantFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
field_name='group', field_name='group',
lookup_expr='in', lookup_expr='in',
label='Tenant group (ID)', label=_('Tenant group (ID)'),
) )
group = TreeNodeMultipleChoiceFilter( group = TreeNodeMultipleChoiceFilter(
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
field_name='group', field_name='group',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Tenant group (slug)', label=_('Tenant group (slug)'),
) )
class Meta: class Meta:
@ -179,22 +180,22 @@ class TenancyFilterSet(django_filters.FilterSet):
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
field_name='tenant__group', field_name='tenant__group',
lookup_expr='in', lookup_expr='in',
label='Tenant Group (ID)', label=_('Tenant Group (ID)'),
) )
tenant_group = TreeNodeMultipleChoiceFilter( tenant_group = TreeNodeMultipleChoiceFilter(
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
field_name='tenant__group', field_name='tenant__group',
to_field_name='slug', to_field_name='slug',
lookup_expr='in', lookup_expr='in',
label='Tenant Group (slug)', label=_('Tenant Group (slug)'),
) )
tenant_id = django_filters.ModelMultipleChoiceFilter( tenant_id = django_filters.ModelMultipleChoiceFilter(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
label='Tenant (ID)', label=_('Tenant (ID)'),
) )
tenant = django_filters.ModelMultipleChoiceFilter( tenant = django_filters.ModelMultipleChoiceFilter(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
field_name='tenant__slug', field_name='tenant__slug',
to_field_name='slug', to_field_name='slug',
label='Tenant (slug)', label=_('Tenant (slug)'),
) )

View File

@ -1,3 +1,4 @@
from django.utils.translation import gettext as _
from netbox.forms import NetBoxModelCSVForm from netbox.forms import NetBoxModelCSVForm
from tenancy.models import * from tenancy.models import *
from utilities.forms import CSVModelChoiceField, SlugField from utilities.forms import CSVModelChoiceField, SlugField
@ -20,7 +21,7 @@ class TenantGroupCSVForm(NetBoxModelCSVForm):
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent group' help_text=_('Parent group')
) )
slug = SlugField() slug = SlugField()
@ -35,7 +36,7 @@ class TenantCSVForm(NetBoxModelCSVForm):
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned group' help_text=_('Assigned group')
) )
class Meta: class Meta:
@ -52,7 +53,7 @@ class ContactGroupCSVForm(NetBoxModelCSVForm):
queryset=ContactGroup.objects.all(), queryset=ContactGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent group' help_text=_('Parent group')
) )
slug = SlugField() slug = SlugField()
@ -74,7 +75,7 @@ class ContactCSVForm(NetBoxModelCSVForm):
queryset=ContactGroup.objects.all(), queryset=ContactGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned group' help_text=_('Assigned group')
) )
class Meta: class Meta:

View File

@ -3,6 +3,7 @@ from django.contrib.auth.models import Group, User
from django.contrib.admin.widgets import FilteredSelectMultiple from django.contrib.admin.widgets import FilteredSelectMultiple
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import FieldError, ValidationError from django.core.exceptions import FieldError, ValidationError
from django.utils.translation import gettext as _
from users.constants import CONSTRAINT_TOKEN_USER, OBJECTPERMISSION_OBJECT_TYPES from users.constants import CONSTRAINT_TOKEN_USER, OBJECTPERMISSION_OBJECT_TYPES
from users.models import ObjectPermission, Token from users.models import ObjectPermission, Token
@ -46,7 +47,7 @@ class GroupAdminForm(forms.ModelForm):
class TokenAdminForm(forms.ModelForm): class TokenAdminForm(forms.ModelForm):
key = forms.CharField( key = forms.CharField(
required=False, required=False,
help_text="If no key is provided, one will be generated automatically." help_text=_("If no key is provided, one will be generated automatically.")
) )
class Meta: class Meta:
@ -70,10 +71,10 @@ class ObjectPermissionForm(forms.ModelForm):
model = ObjectPermission model = ObjectPermission
exclude = [] exclude = []
help_texts = { help_texts = {
'actions': 'Actions granted in addition to those listed above', 'actions': _('Actions granted in addition to those listed above'),
'constraints': 'JSON expression of a queryset filter that will return only permitted objects. Leave null ' 'constraints': _('JSON expression of a queryset filter that will return only permitted objects. Leave null '
'to match all objects of this type. A list of multiple objects will result in a logical OR ' 'to match all objects of this type. A list of multiple objects will result in a logical OR '
'operation.' 'operation.')
} }
labels = { labels = {
'actions': 'Additional actions' 'actions': 'Additional actions'

View File

@ -1,6 +1,7 @@
import django_filters import django_filters
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _
from netbox.filtersets import BaseFilterSet from netbox.filtersets import BaseFilterSet
from users.models import ObjectPermission, Token from users.models import ObjectPermission, Token
@ -15,7 +16,7 @@ __all__ = (
class GroupFilterSet(BaseFilterSet): class GroupFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
class Meta: class Meta:
@ -31,18 +32,18 @@ class GroupFilterSet(BaseFilterSet):
class UserFilterSet(BaseFilterSet): class UserFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
group_id = django_filters.ModelMultipleChoiceFilter( group_id = django_filters.ModelMultipleChoiceFilter(
field_name='groups', field_name='groups',
queryset=Group.objects.all(), queryset=Group.objects.all(),
label='Group', label=_('Group'),
) )
group = django_filters.ModelMultipleChoiceFilter( group = django_filters.ModelMultipleChoiceFilter(
field_name='groups__name', field_name='groups__name',
queryset=Group.objects.all(), queryset=Group.objects.all(),
to_field_name='name', to_field_name='name',
label='Group (name)', label=_('Group (name)'),
) )
class Meta: class Meta:
@ -63,18 +64,18 @@ class UserFilterSet(BaseFilterSet):
class TokenFilterSet(BaseFilterSet): class TokenFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
user_id = django_filters.ModelMultipleChoiceFilter( user_id = django_filters.ModelMultipleChoiceFilter(
field_name='user', field_name='user',
queryset=User.objects.all(), queryset=User.objects.all(),
label='User', label=_('User'),
) )
user = django_filters.ModelMultipleChoiceFilter( user = django_filters.ModelMultipleChoiceFilter(
field_name='user__username', field_name='user__username',
queryset=User.objects.all(), queryset=User.objects.all(),
to_field_name='username', to_field_name='username',
label='User (name)', label=_('User (name)'),
) )
created = django_filters.DateTimeFilter() created = django_filters.DateTimeFilter()
created__gte = django_filters.DateTimeFilter( created__gte = django_filters.DateTimeFilter(
@ -111,29 +112,29 @@ class TokenFilterSet(BaseFilterSet):
class ObjectPermissionFilterSet(BaseFilterSet): class ObjectPermissionFilterSet(BaseFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label=_('Search'),
) )
user_id = django_filters.ModelMultipleChoiceFilter( user_id = django_filters.ModelMultipleChoiceFilter(
field_name='users', field_name='users',
queryset=User.objects.all(), queryset=User.objects.all(),
label='User', label=_('User'),
) )
user = django_filters.ModelMultipleChoiceFilter( user = django_filters.ModelMultipleChoiceFilter(
field_name='users__username', field_name='users__username',
queryset=User.objects.all(), queryset=User.objects.all(),
to_field_name='username', to_field_name='username',
label='User (name)', label=_('User (name)'),
) )
group_id = django_filters.ModelMultipleChoiceFilter( group_id = django_filters.ModelMultipleChoiceFilter(
field_name='groups', field_name='groups',
queryset=Group.objects.all(), queryset=Group.objects.all(),
label='Group', label=_('Group'),
) )
group = django_filters.ModelMultipleChoiceFilter( group = django_filters.ModelMultipleChoiceFilter(
field_name='groups__name', field_name='groups__name',
queryset=Group.objects.all(), queryset=Group.objects.all(),
to_field_name='name', to_field_name='name',
label='Group (name)', label=_('Group (name)'),
) )
class Meta: class Meta:

View File

@ -3,6 +3,7 @@ from django.conf import settings
from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm from django.contrib.auth.forms import AuthenticationForm, PasswordChangeForm as DjangoPasswordChangeForm
from django.contrib.postgres.forms import SimpleArrayField from django.contrib.postgres.forms import SimpleArrayField
from django.utils.html import mark_safe from django.utils.html import mark_safe
from django.utils.translation import gettext as _
from ipam.formfields import IPNetworkFormField from ipam.formfields import IPNetworkFormField
from netbox.preferences import PREFERENCES from netbox.preferences import PREFERENCES
@ -100,14 +101,14 @@ class UserConfigForm(BootstrapMixin, forms.ModelForm, metaclass=UserConfigFormMe
class TokenForm(BootstrapMixin, forms.ModelForm): class TokenForm(BootstrapMixin, forms.ModelForm):
key = forms.CharField( key = forms.CharField(
required=False, required=False,
help_text="If no key is provided, one will be generated automatically." help_text=_("If no key is provided, one will be generated automatically.")
) )
allowed_ips = SimpleArrayField( allowed_ips = SimpleArrayField(
base_field=IPNetworkFormField(), base_field=IPNetworkFormField(),
required=False, required=False,
label='Allowed IPs', label=_('Allowed IPs'),
help_text='Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. ' help_text=_('Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. '
'Example: <code>10.1.1.0/24,192.168.10.16/32,2001:db8:1::/64</code>', 'Example: <code>10.1.1.0/24,192.168.10.16/32,2001:db8:1::/64</code>'),
) )
class Meta: class Meta:

View File

@ -10,6 +10,7 @@ from django.db import models
from django.db.models.signals import post_save from django.db.models.signals import post_save
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 netaddr import IPNetwork from netaddr import IPNetwork
from ipam.fields import IPNetworkField from ipam.fields import IPNetworkField
@ -216,7 +217,7 @@ class Token(models.Model):
) )
write_enabled = models.BooleanField( write_enabled = models.BooleanField(
default=True, default=True,
help_text='Permit create/update/delete operations using this key' help_text=_('Permit create/update/delete operations using this key')
) )
description = models.CharField( description = models.CharField(
max_length=200, max_length=200,
@ -227,8 +228,8 @@ class Token(models.Model):
blank=True, blank=True,
null=True, null=True,
verbose_name='Allowed IPs', verbose_name='Allowed IPs',
help_text='Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. ' help_text=_('Allowed IPv4/IPv6 networks from where the token can be used. Leave blank for no restrictions. '
'Ex: "10.1.1.0/24, 192.168.10.16/32, 2001:DB8:1::/64"', 'Ex: "10.1.1.0/24, 192.168.10.16/32, 2001:DB8:1::/64"'),
) )
def __str__(self): def __str__(self):
@ -304,12 +305,12 @@ class ObjectPermission(models.Model):
) )
actions = ArrayField( actions = ArrayField(
base_field=models.CharField(max_length=30), base_field=models.CharField(max_length=30),
help_text="The list of actions granted by this permission" help_text=_("The list of actions granted by this permission")
) )
constraints = models.JSONField( constraints = models.JSONField(
blank=True, blank=True,
null=True, null=True,
help_text="Queryset filter matching the applicable objects of the selected type(s)" help_text=_("Queryset filter matching the applicable objects of the selected type(s)")
) )
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -5,6 +5,7 @@ from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _
from utilities.choices import unpack_grouped_choices from utilities.choices import unpack_grouped_choices
from utilities.forms.utils import parse_csv, validate_csv from utilities.forms.utils import parse_csv, validate_csv
@ -50,9 +51,9 @@ class CSVDataField(forms.CharField):
if not self.initial: if not self.initial:
self.initial = ','.join(self.required_fields) + '\n' self.initial = ','.join(self.required_fields) + '\n'
if not self.help_text: if not self.help_text:
self.help_text = 'Enter the list of column headers followed by one line per record to be imported, using ' \ self.help_text = _('Enter the list of column headers followed by one line per record to be imported, using '
'commas to separate values. Multi-line data and values containing commas may be wrapped ' \ 'commas to separate values. Multi-line data and values containing commas may be wrapped '
'in double quotes.' 'in double quotes.')
def to_python(self, value): def to_python(self, value):
reader = csv.reader(StringIO(value.strip())) reader = csv.reader(StringIO(value.strip()))

View File

@ -1,6 +1,7 @@
import re import re
from django import forms from django import forms
from django.utils.translation import gettext as _
from utilities.forms.constants import * from utilities.forms.constants import *
from utilities.forms.utils import expand_alphanumeric_pattern, expand_ipaddress_pattern from utilities.forms.utils import expand_alphanumeric_pattern, expand_ipaddress_pattern
@ -42,8 +43,8 @@ class ExpandableIPAddressField(forms.CharField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if not self.help_text: if not self.help_text:
self.help_text = 'Specify a numeric range to create multiple IPs.<br />'\ self.help_text = _('Specify a numeric range to create multiple IPs.<br />'
'Example: <code>192.0.2.[1,5,100-254]/24</code>' 'Example: <code>192.0.2.[1,5,100-254]/24</code>')
def to_python(self, value): def to_python(self, value):
# Hackish address family detection but it's all we have to work with # Hackish address family detection but it's all we have to work with

View File

@ -4,6 +4,7 @@ from django import forms
from django.db.models import Count from django.db.models import Count
from django.forms.fields import JSONField as _JSONField, InvalidJSONInput from django.forms.fields import JSONField as _JSONField, InvalidJSONInput
from django.templatetags.static import static from django.templatetags.static import static
from django.utils.translation import gettext as _
from netaddr import AddrFormatError, EUI from netaddr import AddrFormatError, EUI
from utilities.forms import widgets from utilities.forms import widgets
@ -45,7 +46,7 @@ class SlugField(forms.SlugField):
slug_source: Name of the form field from which the slug value will be derived slug_source: Name of the form field from which the slug value will be derived
""" """
widget = widgets.SlugWidget widget = widgets.SlugWidget
help_text = "URL-friendly unique shorthand" help_text = _("URL-friendly unique shorthand")
def __init__(self, *, slug_source='name', help_text=help_text, **kwargs): def __init__(self, *, slug_source='name', help_text=help_text, **kwargs):
super().__init__(help_text=help_text, **kwargs) super().__init__(help_text=help_text, **kwargs)
@ -97,7 +98,7 @@ class JSONField(_JSONField):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
if not self.help_text: if not self.help_text:
self.help_text = 'Enter context data in <a href="https://json.org/">JSON</a> format.' self.help_text = _('Enter context data in <a href="https://json.org/">JSON</a> format.')
self.widget.attrs['placeholder'] = '' self.widget.attrs['placeholder'] = ''
self.widget.attrs['class'] = 'font-monospace' self.widget.attrs['class'] = 'font-monospace'

View File

@ -5,8 +5,9 @@ from io import StringIO
import yaml import yaml
from django import forms from django import forms
from utilities.forms.utils import parse_csv from django.utils.translation import gettext as _
from utilities.forms.utils import parse_csv
from .choices import ImportFormatChoices from .choices import ImportFormatChoices
from .widgets import APISelect, APISelectMultiple, ClearableFileInput, StaticSelect from .widgets import APISelect, APISelectMultiple, ClearableFileInput, StaticSelect
@ -103,7 +104,7 @@ class BulkRenameForm(BootstrapMixin, forms.Form):
use_regex = forms.BooleanField( use_regex = forms.BooleanField(
required=False, required=False,
initial=True, initial=True,
label='Use regular expressions' label=_('Use regular expressions')
) )
def clean(self): def clean(self):
@ -145,7 +146,7 @@ class ImportForm(BootstrapMixin, forms.Form):
data = forms.CharField( data = forms.CharField(
required=False, required=False,
widget=forms.Textarea(attrs={'class': 'font-monospace'}), widget=forms.Textarea(attrs={'class': 'font-monospace'}),
help_text="Enter object data in CSV, JSON or YAML format." help_text=_("Enter object data in CSV, JSON or YAML format.")
) )
data_file = forms.FileField( data_file = forms.FileField(
label="Data file", label="Data file",
@ -219,7 +220,7 @@ class FilterForm(BootstrapMixin, forms.Form):
""" """
q = forms.CharField( q = forms.CharField(
required=False, required=False,
label='Search' label=_('Search')
) )
@ -233,7 +234,7 @@ class TableConfigForm(BootstrapMixin, forms.Form):
widget=forms.SelectMultiple( widget=forms.SelectMultiple(
attrs={'size': 10, 'class': 'form-select'} attrs={'size': 10, 'class': 'form-select'}
), ),
label='Available Columns' label=_('Available Columns')
) )
columns = forms.MultipleChoiceField( columns = forms.MultipleChoiceField(
choices=[], choices=[],
@ -241,7 +242,7 @@ class TableConfigForm(BootstrapMixin, forms.Form):
widget=forms.SelectMultiple( widget=forms.SelectMultiple(
attrs={'size': 10, 'class': 'form-select'} attrs={'size': 10, 'class': 'form-select'}
), ),
label='Selected Columns' label=_('Selected Columns')
) )
def __init__(self, table, *args, **kwargs): def __init__(self, table, *args, **kwargs):

View File

@ -1,5 +1,6 @@
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _
from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup from dcim.models import Device, DeviceRole, Platform, Region, Site, SiteGroup
from extras.filtersets import LocalConfigContextFilterSet from extras.filtersets import LocalConfigContextFilterSet
@ -38,57 +39,57 @@ class ClusterFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
lookup_expr='in', lookup_expr='in',
label='Region (ID)', label=_('Region (ID)'),
) )
region = TreeNodeMultipleChoiceFilter( region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Region (slug)', label=_('Region (slug)'),
) )
site_group_id = TreeNodeMultipleChoiceFilter( site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='site__group', field_name='site__group',
lookup_expr='in', lookup_expr='in',
label='Site group (ID)', label=_('Site group (ID)'),
) )
site_group = TreeNodeMultipleChoiceFilter( site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='site__group', field_name='site__group',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Site group (slug)', label=_('Site group (slug)'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label=_('Site (ID)'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='site__slug', field_name='site__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
group_id = django_filters.ModelMultipleChoiceFilter( group_id = django_filters.ModelMultipleChoiceFilter(
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
label='Parent group (ID)', label=_('Parent group (ID)'),
) )
group = django_filters.ModelMultipleChoiceFilter( group = django_filters.ModelMultipleChoiceFilter(
field_name='group__slug', field_name='group__slug',
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Parent group (slug)', label=_('Parent group (slug)'),
) )
type_id = django_filters.ModelMultipleChoiceFilter( type_id = django_filters.ModelMultipleChoiceFilter(
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
label='Cluster type (ID)', label=_('Cluster type (ID)'),
) )
type = django_filters.ModelMultipleChoiceFilter( type = django_filters.ModelMultipleChoiceFilter(
field_name='type__slug', field_name='type__slug',
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Cluster type (slug)', label=_('Cluster type (slug)'),
) )
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=ClusterStatusChoices, choices=ClusterStatusChoices,
@ -121,111 +122,111 @@ class VirtualMachineFilterSet(
cluster_group_id = django_filters.ModelMultipleChoiceFilter( cluster_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='cluster__group', field_name='cluster__group',
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
label='Cluster group (ID)', label=_('Cluster group (ID)'),
) )
cluster_group = django_filters.ModelMultipleChoiceFilter( cluster_group = django_filters.ModelMultipleChoiceFilter(
field_name='cluster__group__slug', field_name='cluster__group__slug',
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Cluster group (slug)', label=_('Cluster group (slug)'),
) )
cluster_type_id = django_filters.ModelMultipleChoiceFilter( cluster_type_id = django_filters.ModelMultipleChoiceFilter(
field_name='cluster__type', field_name='cluster__type',
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
label='Cluster type (ID)', label=_('Cluster type (ID)'),
) )
cluster_type = django_filters.ModelMultipleChoiceFilter( cluster_type = django_filters.ModelMultipleChoiceFilter(
field_name='cluster__type__slug', field_name='cluster__type__slug',
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Cluster type (slug)', label=_('Cluster type (slug)'),
) )
cluster_id = django_filters.ModelMultipleChoiceFilter( cluster_id = django_filters.ModelMultipleChoiceFilter(
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
label='Cluster (ID)', label=_('Cluster (ID)'),
) )
cluster = django_filters.ModelMultipleChoiceFilter( cluster = django_filters.ModelMultipleChoiceFilter(
field_name='cluster__name', field_name='cluster__name',
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
to_field_name='name', to_field_name='name',
label='Cluster', label=_('Cluster'),
) )
device_id = django_filters.ModelMultipleChoiceFilter( device_id = django_filters.ModelMultipleChoiceFilter(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label='Device (ID)', label=_('Device (ID)'),
) )
device = django_filters.ModelMultipleChoiceFilter( device = django_filters.ModelMultipleChoiceFilter(
field_name='device__name', field_name='device__name',
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
label='Device', label=_('Device'),
) )
region_id = TreeNodeMultipleChoiceFilter( region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
lookup_expr='in', lookup_expr='in',
label='Region (ID)', label=_('Region (ID)'),
) )
region = TreeNodeMultipleChoiceFilter( region = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Region (slug)', label=_('Region (slug)'),
) )
site_group_id = TreeNodeMultipleChoiceFilter( site_group_id = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='site__group', field_name='site__group',
lookup_expr='in', lookup_expr='in',
label='Site group (ID)', label=_('Site group (ID)'),
) )
site_group = TreeNodeMultipleChoiceFilter( site_group = TreeNodeMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
field_name='site__group', field_name='site__group',
lookup_expr='in', lookup_expr='in',
to_field_name='slug', to_field_name='slug',
label='Site group (slug)', label=_('Site group (slug)'),
) )
site_id = django_filters.ModelMultipleChoiceFilter( site_id = django_filters.ModelMultipleChoiceFilter(
queryset=Site.objects.all(), queryset=Site.objects.all(),
label='Site (ID)', label=_('Site (ID)'),
) )
site = django_filters.ModelMultipleChoiceFilter( site = django_filters.ModelMultipleChoiceFilter(
field_name='site__slug', field_name='site__slug',
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Site (slug)', label=_('Site (slug)'),
) )
name = MultiValueCharFilter( name = MultiValueCharFilter(
lookup_expr='iexact' lookup_expr='iexact'
) )
role_id = django_filters.ModelMultipleChoiceFilter( role_id = django_filters.ModelMultipleChoiceFilter(
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
label='Role (ID)', label=_('Role (ID)'),
) )
role = django_filters.ModelMultipleChoiceFilter( role = django_filters.ModelMultipleChoiceFilter(
field_name='role__slug', field_name='role__slug',
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Role (slug)', label=_('Role (slug)'),
) )
platform_id = django_filters.ModelMultipleChoiceFilter( platform_id = django_filters.ModelMultipleChoiceFilter(
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
label='Platform (ID)', label=_('Platform (ID)'),
) )
platform = django_filters.ModelMultipleChoiceFilter( platform = django_filters.ModelMultipleChoiceFilter(
field_name='platform__slug', field_name='platform__slug',
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
to_field_name='slug', to_field_name='slug',
label='Platform (slug)', label=_('Platform (slug)'),
) )
mac_address = MultiValueMACAddressFilter( mac_address = MultiValueMACAddressFilter(
field_name='interfaces__mac_address', field_name='interfaces__mac_address',
label='MAC address', label=_('MAC address'),
) )
has_primary_ip = django_filters.BooleanFilter( has_primary_ip = django_filters.BooleanFilter(
method='_has_primary_ip', method='_has_primary_ip',
label='Has a primary IP', label=_('Has a primary IP'),
) )
class Meta: class Meta:
@ -251,48 +252,48 @@ class VMInterfaceFilterSet(NetBoxModelFilterSet):
cluster_id = django_filters.ModelMultipleChoiceFilter( cluster_id = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine__cluster', field_name='virtual_machine__cluster',
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
label='Cluster (ID)', label=_('Cluster (ID)'),
) )
cluster = django_filters.ModelMultipleChoiceFilter( cluster = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine__cluster__name', field_name='virtual_machine__cluster__name',
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
to_field_name='name', to_field_name='name',
label='Cluster', label=_('Cluster'),
) )
virtual_machine_id = django_filters.ModelMultipleChoiceFilter( virtual_machine_id = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine', field_name='virtual_machine',
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
label='Virtual machine (ID)', label=_('Virtual machine (ID)'),
) )
virtual_machine = django_filters.ModelMultipleChoiceFilter( virtual_machine = django_filters.ModelMultipleChoiceFilter(
field_name='virtual_machine__name', field_name='virtual_machine__name',
queryset=VirtualMachine.objects.all(), queryset=VirtualMachine.objects.all(),
to_field_name='name', to_field_name='name',
label='Virtual machine', label=_('Virtual machine'),
) )
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
field_name='parent', field_name='parent',
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
label='Parent interface (ID)', label=_('Parent interface (ID)'),
) )
bridge_id = django_filters.ModelMultipleChoiceFilter( bridge_id = django_filters.ModelMultipleChoiceFilter(
field_name='bridge', field_name='bridge',
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
label='Bridged interface (ID)', label=_('Bridged interface (ID)'),
) )
mac_address = MultiValueMACAddressFilter( mac_address = MultiValueMACAddressFilter(
label='MAC address', label=_('MAC address'),
) )
vrf_id = django_filters.ModelMultipleChoiceFilter( vrf_id = django_filters.ModelMultipleChoiceFilter(
field_name='vrf', field_name='vrf',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
label='VRF', label=_('VRF'),
) )
vrf = django_filters.ModelMultipleChoiceFilter( vrf = django_filters.ModelMultipleChoiceFilter(
field_name='vrf__rd', field_name='vrf__rd',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
to_field_name='rd', to_field_name='rd',
label='VRF (RD)', label=_('VRF (RD)'),
) )
class Meta: class Meta:

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from utilities.forms import BootstrapMixin, ExpandableNameField, form_from_model from utilities.forms import BootstrapMixin, ExpandableNameField, form_from_model
from virtualization.models import VMInterface, VirtualMachine from virtualization.models import VMInterface, VirtualMachine
@ -14,7 +15,7 @@ class VirtualMachineBulkAddComponentForm(BootstrapMixin, forms.Form):
widget=forms.MultipleHiddenInput() widget=forms.MultipleHiddenInput()
) )
name = ExpandableNameField( name = ExpandableNameField(
label='Name' label=_('Name')
) )
def clean_tags(self): def clean_tags(self):

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from dcim.choices import InterfaceModeChoices from dcim.choices import InterfaceModeChoices
from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN from dcim.constants import INTERFACE_MTU_MAX, INTERFACE_MTU_MIN
@ -90,7 +91,7 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm):
) )
comments = CommentField( comments = CommentField(
widget=SmallTextarea, widget=SmallTextarea,
label='Comments' label=_('Comments')
) )
model = Cluster model = Cluster
@ -147,15 +148,15 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm):
) )
vcpus = forms.IntegerField( vcpus = forms.IntegerField(
required=False, required=False,
label='vCPUs' label=_('vCPUs')
) )
memory = forms.IntegerField( memory = forms.IntegerField(
required=False, required=False,
label='Memory (MB)' label=_('Memory (MB)')
) )
disk = forms.IntegerField( disk = forms.IntegerField(
required=False, required=False,
label='Disk (GB)' label=_('Disk (GB)')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -163,7 +164,7 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm):
) )
comments = CommentField( comments = CommentField(
widget=SmallTextarea, widget=SmallTextarea,
label='Comments' label=_('Comments')
) )
model = VirtualMachine model = VirtualMachine
@ -199,7 +200,7 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
min_value=INTERFACE_MTU_MIN, min_value=INTERFACE_MTU_MIN,
max_value=INTERFACE_MTU_MAX, max_value=INTERFACE_MTU_MAX,
label='MTU' label=_('MTU')
) )
description = forms.CharField( description = forms.CharField(
max_length=100, max_length=100,
@ -213,7 +214,7 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm):
vlan_group = DynamicModelChoiceField( vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
label='VLAN group' label=_('VLAN group')
) )
untagged_vlan = DynamicModelChoiceField( untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
@ -221,7 +222,7 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm):
query_params={ query_params={
'group_id': '$vlan_group', 'group_id': '$vlan_group',
}, },
label='Untagged VLAN' label=_('Untagged VLAN')
) )
tagged_vlans = DynamicModelMultipleChoiceField( tagged_vlans = DynamicModelMultipleChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
@ -229,12 +230,12 @@ class VMInterfaceBulkEditForm(NetBoxModelBulkEditForm):
query_params={ query_params={
'group_id': '$vlan_group', 'group_id': '$vlan_group',
}, },
label='Tagged VLANs' label=_('Tagged VLANs')
) )
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
model = VMInterface model = VMInterface

View File

@ -1,5 +1,6 @@
from dcim.choices import InterfaceModeChoices from dcim.choices import InterfaceModeChoices
from dcim.models import Device, DeviceRole, Platform, Site from dcim.models import Device, DeviceRole, Platform, Site
from django.utils.translation import gettext as _
from ipam.models import VRF from ipam.models import VRF
from netbox.forms import NetBoxModelCSVForm from netbox.forms import NetBoxModelCSVForm
from tenancy.models import Tenant from tenancy.models import Tenant
@ -36,29 +37,29 @@ class ClusterCSVForm(NetBoxModelCSVForm):
type = CSVModelChoiceField( type = CSVModelChoiceField(
queryset=ClusterType.objects.all(), queryset=ClusterType.objects.all(),
to_field_name='name', to_field_name='name',
help_text='Type of cluster' help_text=_('Type of cluster')
) )
group = CSVModelChoiceField( group = CSVModelChoiceField(
queryset=ClusterGroup.objects.all(), queryset=ClusterGroup.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned cluster group' help_text=_('Assigned cluster group')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=ClusterStatusChoices, choices=ClusterStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
site = CSVModelChoiceField( site = CSVModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned site' help_text=_('Assigned site')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
class Meta: class Meta:
@ -69,25 +70,25 @@ class ClusterCSVForm(NetBoxModelCSVForm):
class VirtualMachineCSVForm(NetBoxModelCSVForm): class VirtualMachineCSVForm(NetBoxModelCSVForm):
status = CSVChoiceField( status = CSVChoiceField(
choices=VirtualMachineStatusChoices, choices=VirtualMachineStatusChoices,
help_text='Operational status' help_text=_('Operational status')
) )
site = CSVModelChoiceField( site = CSVModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned site' help_text=_('Assigned site')
) )
cluster = CSVModelChoiceField( cluster = CSVModelChoiceField(
queryset=Cluster.objects.all(), queryset=Cluster.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned cluster' help_text=_('Assigned cluster')
) )
device = CSVModelChoiceField( device = CSVModelChoiceField(
queryset=Device.objects.all(), queryset=Device.objects.all(),
to_field_name='name', to_field_name='name',
required=False, required=False,
help_text='Assigned device within cluster' help_text=_('Assigned device within cluster')
) )
role = CSVModelChoiceField( role = CSVModelChoiceField(
queryset=DeviceRole.objects.filter( queryset=DeviceRole.objects.filter(
@ -95,19 +96,19 @@ class VirtualMachineCSVForm(NetBoxModelCSVForm):
), ),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Functional role' help_text=_('Functional role')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
platform = CSVModelChoiceField( platform = CSVModelChoiceField(
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned platform' help_text=_('Assigned platform')
) )
class Meta: class Meta:
@ -127,24 +128,24 @@ class VMInterfaceCSVForm(NetBoxModelCSVForm):
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent interface' help_text=_('Parent interface')
) )
bridge = CSVModelChoiceField( bridge = CSVModelChoiceField(
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Bridged interface' help_text=_('Bridged interface')
) )
mode = CSVChoiceField( mode = CSVChoiceField(
choices=InterfaceModeChoices, choices=InterfaceModeChoices,
required=False, required=False,
help_text='IEEE 802.1Q operational mode (for L2 interfaces)' help_text=_('IEEE 802.1Q operational mode (for L2 interfaces)')
) )
vrf = CSVModelChoiceField( vrf = CSVModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
to_field_name='rd', to_field_name='rd',
help_text='Assigned VRF' help_text=_('Assigned VRF')
) )
class Meta: class Meta:

View File

@ -160,11 +160,11 @@ class VirtualMachineFilterForm(
) )
mac_address = forms.CharField( mac_address = forms.CharField(
required=False, required=False,
label='MAC address' label=_('MAC address')
) )
has_primary_ip = forms.NullBooleanField( has_primary_ip = forms.NullBooleanField(
required=False, required=False,
label='Has a primary IP', label=_('Has a primary IP'),
widget=StaticSelect( widget=StaticSelect(
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
) )

View File

@ -1,6 +1,7 @@
from django import forms from django import forms
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _
from dcim.forms.common import InterfaceCommonForm from dcim.forms.common import InterfaceCommonForm
from dcim.forms.model_forms import INTERFACE_MODE_HELP_TEXT from dcim.forms.model_forms import INTERFACE_MODE_HELP_TEXT
@ -204,7 +205,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
'cluster_id': '$cluster', 'cluster_id': '$cluster',
'site_id': '$site', 'site_id': '$site',
}, },
help_text="Optionally pin this VM to a specific host device within the cluster" help_text=_("Optionally pin this VM to a specific host device within the cluster")
) )
role = DynamicModelChoiceField( role = DynamicModelChoiceField(
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
@ -240,8 +241,8 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm):
'local_context_data', 'local_context_data',
] ]
help_texts = { help_texts = {
'local_context_data': "Local config context data overwrites all sources contexts in the final rendered " 'local_context_data': _("Local config context data overwrites all sources contexts in the final rendered "
"config context", "config context"),
} }
widgets = { widgets = {
"status": StaticSelect(), "status": StaticSelect(),
@ -297,7 +298,7 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
required=False, required=False,
label='Parent interface', label=_('Parent interface'),
query_params={ query_params={
'virtual_machine_id': '$virtual_machine', 'virtual_machine_id': '$virtual_machine',
} }
@ -305,7 +306,7 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
bridge = DynamicModelChoiceField( bridge = DynamicModelChoiceField(
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
required=False, required=False,
label='Bridged interface', label=_('Bridged interface'),
query_params={ query_params={
'virtual_machine_id': '$virtual_machine', 'virtual_machine_id': '$virtual_machine',
} }
@ -313,12 +314,12 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
vlan_group = DynamicModelChoiceField( vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
label='VLAN group' label=_('VLAN group')
) )
untagged_vlan = DynamicModelChoiceField( untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
label='Untagged VLAN', label=_('Untagged VLAN'),
query_params={ query_params={
'group_id': '$vlan_group', 'group_id': '$vlan_group',
'available_on_virtualmachine': '$virtual_machine', 'available_on_virtualmachine': '$virtual_machine',
@ -327,7 +328,7 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
tagged_vlans = DynamicModelMultipleChoiceField( tagged_vlans = DynamicModelMultipleChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
label='Tagged VLANs', label=_('Tagged VLANs'),
query_params={ query_params={
'group_id': '$vlan_group', 'group_id': '$vlan_group',
'available_on_virtualmachine': '$virtual_machine', 'available_on_virtualmachine': '$virtual_machine',
@ -336,7 +337,7 @@ class VMInterfaceForm(InterfaceCommonForm, NetBoxModelForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
label='VRF' label=_('VRF')
) )
fieldsets = ( fieldsets = (

View File

@ -1,4 +1,5 @@
from django import forms from django import forms
from django.utils.translation import gettext as _
from dcim.choices import LinkStatusChoices from dcim.choices import LinkStatusChoices
from ipam.models import VLAN from ipam.models import VLAN
@ -45,12 +46,12 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm):
vlan = DynamicModelChoiceField( vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
label='VLAN' label=_('VLAN')
) )
ssid = forms.CharField( ssid = forms.CharField(
max_length=SSID_MAX_LENGTH, max_length=SSID_MAX_LENGTH,
required=False, required=False,
label='SSID' label=_('SSID')
) )
tenant = DynamicModelChoiceField( tenant = DynamicModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@ -66,7 +67,7 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm):
) )
auth_psk = forms.CharField( auth_psk = forms.CharField(
required=False, required=False,
label='Pre-shared key' label=_('Pre-shared key')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,
@ -91,7 +92,7 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm):
ssid = forms.CharField( ssid = forms.CharField(
max_length=SSID_MAX_LENGTH, max_length=SSID_MAX_LENGTH,
required=False, required=False,
label='SSID' label=_('SSID')
) )
status = forms.ChoiceField( status = forms.ChoiceField(
choices=add_blank_choice(LinkStatusChoices), choices=add_blank_choice(LinkStatusChoices),
@ -111,7 +112,7 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm):
) )
auth_psk = forms.CharField( auth_psk = forms.CharField(
required=False, required=False,
label='Pre-shared key' label=_('Pre-shared key')
) )
description = forms.CharField( description = forms.CharField(
max_length=200, max_length=200,

View File

@ -1,3 +1,4 @@
from django.utils.translation import gettext as _
from dcim.choices import LinkStatusChoices from dcim.choices import LinkStatusChoices
from dcim.models import Interface from dcim.models import Interface
from ipam.models import VLAN from ipam.models import VLAN
@ -19,7 +20,7 @@ class WirelessLANGroupCSVForm(NetBoxModelCSVForm):
queryset=WirelessLANGroup.objects.all(), queryset=WirelessLANGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Parent group' help_text=_('Parent group')
) )
slug = SlugField() slug = SlugField()
@ -33,7 +34,7 @@ class WirelessLANCSVForm(NetBoxModelCSVForm):
queryset=WirelessLANGroup.objects.all(), queryset=WirelessLANGroup.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned group' help_text=_('Assigned group')
) )
status = CSVChoiceField( status = CSVChoiceField(
choices=WirelessLANStatusChoices, choices=WirelessLANStatusChoices,
@ -43,23 +44,23 @@ class WirelessLANCSVForm(NetBoxModelCSVForm):
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Bridged VLAN' help_text=_('Bridged VLAN')
) )
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
auth_type = CSVChoiceField( auth_type = CSVChoiceField(
choices=WirelessAuthTypeChoices, choices=WirelessAuthTypeChoices,
required=False, required=False,
help_text='Authentication type' help_text=_('Authentication type')
) )
auth_cipher = CSVChoiceField( auth_cipher = CSVChoiceField(
choices=WirelessAuthCipherChoices, choices=WirelessAuthCipherChoices,
required=False, required=False,
help_text='Authentication cipher' help_text=_('Authentication cipher')
) )
class Meta: class Meta:
@ -73,7 +74,7 @@ class WirelessLANCSVForm(NetBoxModelCSVForm):
class WirelessLinkCSVForm(NetBoxModelCSVForm): class WirelessLinkCSVForm(NetBoxModelCSVForm):
status = CSVChoiceField( status = CSVChoiceField(
choices=LinkStatusChoices, choices=LinkStatusChoices,
help_text='Connection status' help_text=_('Connection status')
) )
interface_a = CSVModelChoiceField( interface_a = CSVModelChoiceField(
queryset=Interface.objects.all() queryset=Interface.objects.all()
@ -85,17 +86,17 @@ class WirelessLinkCSVForm(NetBoxModelCSVForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False, required=False,
to_field_name='name', to_field_name='name',
help_text='Assigned tenant' help_text=_('Assigned tenant')
) )
auth_type = CSVChoiceField( auth_type = CSVChoiceField(
choices=WirelessAuthTypeChoices, choices=WirelessAuthTypeChoices,
required=False, required=False,
help_text='Authentication type' help_text=_('Authentication type')
) )
auth_cipher = CSVChoiceField( auth_cipher = CSVChoiceField(
choices=WirelessAuthCipherChoices, choices=WirelessAuthCipherChoices,
required=False, required=False,
help_text='Authentication cipher' help_text=_('Authentication cipher')
) )
class Meta: class Meta:

View File

@ -35,7 +35,7 @@ class WirelessLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
) )
ssid = forms.CharField( ssid = forms.CharField(
required=False, required=False,
label='SSID' label=_('SSID')
) )
group_id = DynamicModelMultipleChoiceField( group_id = DynamicModelMultipleChoiceField(
queryset=WirelessLANGroup.objects.all(), queryset=WirelessLANGroup.objects.all(),
@ -74,7 +74,7 @@ class WirelessLinkFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
) )
ssid = forms.CharField( ssid = forms.CharField(
required=False, required=False,
label='SSID' label=_('SSID')
) )
status = forms.ChoiceField( status = forms.ChoiceField(
required=False, required=False,

View File

@ -1,3 +1,4 @@
from django.utils.translation import gettext as _
from dcim.models import Device, Interface, Location, Region, Site, SiteGroup from dcim.models import Device, Interface, Location, Region, Site, SiteGroup
from ipam.models import VLAN, VLANGroup from ipam.models import VLAN, VLANGroup
from netbox.forms import NetBoxModelForm from netbox.forms import NetBoxModelForm
@ -63,7 +64,7 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm):
vlan_group = DynamicModelChoiceField( vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
label='VLAN group', label=_('VLAN group'),
null_option='None', null_option='None',
query_params={ query_params={
'site': '$site' 'site': '$site'
@ -75,7 +76,7 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm):
vlan = DynamicModelChoiceField( vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,
label='VLAN', label=_('VLAN'),
query_params={ query_params={
'site_id': '$site', 'site_id': '$site',
'group_id': '$vlan_group', 'group_id': '$vlan_group',
@ -107,7 +108,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
site_a = DynamicModelChoiceField( site_a = DynamicModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
required=False, required=False,
label='Site', label=_('Site'),
initial_params={ initial_params={
'devices': '$device_a', 'devices': '$device_a',
} }
@ -118,7 +119,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
'site_id': '$site_a', 'site_id': '$site_a',
}, },
required=False, required=False,
label='Location', label=_('Location'),
initial_params={ initial_params={
'devices': '$device_a', 'devices': '$device_a',
} }
@ -130,7 +131,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
'location_id': '$location_a', 'location_id': '$location_a',
}, },
required=False, required=False,
label='Device', label=_('Device'),
initial_params={ initial_params={
'interfaces': '$interface_a' 'interfaces': '$interface_a'
} }
@ -142,12 +143,12 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
'device_id': '$device_a', 'device_id': '$device_a',
}, },
disabled_indicator='_occupied', disabled_indicator='_occupied',
label='Interface' label=_('Interface')
) )
site_b = DynamicModelChoiceField( site_b = DynamicModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
required=False, required=False,
label='Site', label=_('Site'),
initial_params={ initial_params={
'devices': '$device_b', 'devices': '$device_b',
} }
@ -158,7 +159,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
'site_id': '$site_b', 'site_id': '$site_b',
}, },
required=False, required=False,
label='Location', label=_('Location'),
initial_params={ initial_params={
'devices': '$device_b', 'devices': '$device_b',
} }
@ -170,7 +171,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
'location_id': '$location_b', 'location_id': '$location_b',
}, },
required=False, required=False,
label='Device', label=_('Device'),
initial_params={ initial_params={
'interfaces': '$interface_b' 'interfaces': '$interface_b'
} }
@ -182,7 +183,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
'device_id': '$device_b', 'device_id': '$device_b',
}, },
disabled_indicator='_occupied', disabled_indicator='_occupied',
label='Interface' label=_('Interface')
) )
comments = CommentField() comments = CommentField()