netbox-plugin-dns 1.1.2__py3-none-any.whl → 1.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of netbox-plugin-dns might be problematic. Click here for more details.

Files changed (84) hide show
  1. netbox_dns/__init__.py +14 -6
  2. netbox_dns/api/nested_serializers.py +3 -2
  3. netbox_dns/api/serializers_/nameserver.py +2 -1
  4. netbox_dns/api/serializers_/record.py +5 -4
  5. netbox_dns/api/serializers_/record_template.py +2 -1
  6. netbox_dns/api/serializers_/view.py +2 -1
  7. netbox_dns/api/serializers_/zone.py +12 -11
  8. netbox_dns/api/serializers_/zone_template.py +8 -7
  9. netbox_dns/api/views.py +9 -4
  10. netbox_dns/choices/record.py +4 -2
  11. netbox_dns/choices/zone.py +8 -4
  12. netbox_dns/fields/address.py +5 -22
  13. netbox_dns/fields/network.py +2 -1
  14. netbox_dns/fields/rfc2317.py +7 -3
  15. netbox_dns/filtersets/nameserver.py +3 -2
  16. netbox_dns/filtersets/record.py +14 -9
  17. netbox_dns/filtersets/record_template.py +3 -2
  18. netbox_dns/filtersets/view.py +3 -2
  19. netbox_dns/filtersets/zone.py +24 -22
  20. netbox_dns/filtersets/zone_template.py +15 -14
  21. netbox_dns/forms/nameserver.py +41 -17
  22. netbox_dns/forms/record.py +61 -32
  23. netbox_dns/forms/record_template.py +49 -28
  24. netbox_dns/forms/registrar.py +21 -17
  25. netbox_dns/forms/registration_contact.py +37 -25
  26. netbox_dns/forms/view.py +49 -27
  27. netbox_dns/forms/zone.py +173 -120
  28. netbox_dns/forms/zone_template.py +53 -43
  29. netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
  30. netbox_dns/locale/en/LC_MESSAGES/django.mo +0 -0
  31. netbox_dns/management/commands/rebuild_dnssync.py +14 -1
  32. netbox_dns/models/nameserver.py +6 -2
  33. netbox_dns/models/record.py +74 -40
  34. netbox_dns/models/record_template.py +17 -9
  35. netbox_dns/models/registrar.py +11 -7
  36. netbox_dns/models/registration_contact.py +23 -11
  37. netbox_dns/models/view.py +15 -6
  38. netbox_dns/models/zone.py +83 -50
  39. netbox_dns/models/zone_template.py +12 -10
  40. netbox_dns/navigation.py +30 -28
  41. netbox_dns/signals/ipam_dnssync.py +21 -14
  42. netbox_dns/tables/ipam_dnssync.py +2 -1
  43. netbox_dns/tables/nameserver.py +2 -0
  44. netbox_dns/tables/record.py +21 -11
  45. netbox_dns/tables/record_template.py +12 -5
  46. netbox_dns/tables/registrar.py +2 -0
  47. netbox_dns/tables/registration_contact.py +2 -0
  48. netbox_dns/tables/view.py +3 -1
  49. netbox_dns/tables/zone.py +15 -2
  50. netbox_dns/tables/zone_template.py +7 -0
  51. netbox_dns/templates/netbox_dns/nameserver.html +6 -5
  52. netbox_dns/templates/netbox_dns/record/managed.html +2 -1
  53. netbox_dns/templates/netbox_dns/record/related.html +26 -14
  54. netbox_dns/templates/netbox_dns/record.html +39 -20
  55. netbox_dns/templates/netbox_dns/recordtemplate.html +27 -15
  56. netbox_dns/templates/netbox_dns/registrar.html +11 -10
  57. netbox_dns/templates/netbox_dns/registrationcontact.html +16 -15
  58. netbox_dns/templates/netbox_dns/view/button.html +2 -1
  59. netbox_dns/templates/netbox_dns/view/prefix.html +7 -4
  60. netbox_dns/templates/netbox_dns/view/related.html +26 -10
  61. netbox_dns/templates/netbox_dns/view.html +11 -14
  62. netbox_dns/templates/netbox_dns/zone/base.html +2 -1
  63. netbox_dns/templates/netbox_dns/zone/child.html +3 -2
  64. netbox_dns/templates/netbox_dns/zone/record.html +3 -2
  65. netbox_dns/templates/netbox_dns/zone/registration.html +8 -7
  66. netbox_dns/templates/netbox_dns/zone.html +28 -30
  67. netbox_dns/templates/netbox_dns/zonetemplate.html +27 -17
  68. netbox_dns/utilities/ipam_dnssync.py +15 -4
  69. netbox_dns/validators/dns_name.py +11 -4
  70. netbox_dns/validators/dns_value.py +55 -9
  71. netbox_dns/validators/rfc2317.py +6 -3
  72. netbox_dns/views/nameserver.py +4 -2
  73. netbox_dns/views/record_template.py +4 -3
  74. netbox_dns/views/registrar.py +3 -1
  75. netbox_dns/views/registration_contact.py +2 -1
  76. netbox_dns/views/view.py +2 -1
  77. netbox_dns/views/zone.py +6 -4
  78. netbox_dns/views/zone_template.py +8 -7
  79. {netbox_plugin_dns-1.1.2.dist-info → netbox_plugin_dns-1.1.4.dist-info}/METADATA +2 -2
  80. netbox_plugin_dns-1.1.4.dist-info/RECORD +150 -0
  81. netbox_plugin_dns-1.1.2.dist-info/RECORD +0 -148
  82. {netbox_plugin_dns-1.1.2.dist-info → netbox_plugin_dns-1.1.4.dist-info}/LICENSE +0 -0
  83. {netbox_plugin_dns-1.1.2.dist-info → netbox_plugin_dns-1.1.4.dist-info}/WHEEL +0 -0
  84. {netbox_plugin_dns-1.1.2.dist-info → netbox_plugin_dns-1.1.4.dist-info}/top_level.txt +0 -0
netbox_dns/models/zone.py CHANGED
@@ -16,6 +16,8 @@ from django.urls import reverse
16
16
  from django.db.models.signals import m2m_changed
17
17
  from django.dispatch import receiver
18
18
  from django.conf import settings
19
+ from django.utils.translation import gettext_lazy as _
20
+ from django.utils.translation import pgettext_lazy as _p
19
21
 
20
22
  from netbox.models import NetBoxModel
21
23
  from netbox.models.features import ContactsMixin
@@ -51,6 +53,9 @@ __all__ = (
51
53
  "ZoneIndex",
52
54
  )
53
55
 
56
+ ZONE_ACTIVE_STATUS_LIST = get_plugin_config("netbox_dns", "zone_active_status")
57
+ RECORD_ACTIVE_STATUS_LIST = get_plugin_config("netbox_dns", "record_active_status")
58
+
54
59
 
55
60
  class ZoneManager(models.Manager.from_queryset(RestrictedQuerySet)):
56
61
  """
@@ -63,15 +68,13 @@ class ZoneManager(models.Manager.from_queryset(RestrictedQuerySet)):
63
68
  .get_queryset()
64
69
  .annotate(
65
70
  active=ExpressionWrapper(
66
- Q(status__in=Zone.ACTIVE_STATUS_LIST), output_field=BooleanField()
71
+ Q(status__in=ZONE_ACTIVE_STATUS_LIST), output_field=BooleanField()
67
72
  )
68
73
  )
69
74
  )
70
75
 
71
76
 
72
77
  class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
73
- ACTIVE_STATUS_LIST = (ZoneStatusChoices.STATUS_ACTIVE,)
74
-
75
78
  def __init__(self, *args, **kwargs):
76
79
  kwargs.pop("template", None)
77
80
 
@@ -81,95 +84,101 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
81
84
  self._ip_addresses_checked = False
82
85
 
83
86
  view = models.ForeignKey(
87
+ verbose_name=_p("DNS", "View"),
84
88
  to="View",
85
89
  on_delete=models.PROTECT,
86
90
  null=False,
87
91
  )
88
92
  name = models.CharField(
93
+ verbose_name=_("Name"),
89
94
  max_length=255,
90
95
  )
91
96
  status = models.CharField(
97
+ verbose_name=_("Status"),
92
98
  max_length=50,
93
99
  choices=ZoneStatusChoices,
94
100
  default=ZoneStatusChoices.STATUS_ACTIVE,
95
101
  blank=True,
96
102
  )
97
103
  nameservers = models.ManyToManyField(
104
+ verbose_name=_("Nameserver"),
98
105
  to="NameServer",
99
106
  related_name="zones",
100
107
  blank=True,
101
108
  )
102
109
  default_ttl = models.PositiveIntegerField(
110
+ verbose_name=_("Default TTL"),
103
111
  blank=True,
104
- verbose_name="Default TTL",
105
112
  validators=[MinValueValidator(1)],
106
113
  )
107
114
  soa_ttl = models.PositiveIntegerField(
115
+ verbose_name=_("SOA TTL"),
108
116
  blank=False,
109
117
  null=False,
110
- verbose_name="SOA TTL",
111
118
  validators=[MinValueValidator(1)],
112
119
  )
113
120
  soa_mname = models.ForeignKey(
121
+ verbose_name=_("SOA MName"),
114
122
  to="NameServer",
115
123
  related_name="zones_soa",
116
- verbose_name="SOA MName",
117
124
  on_delete=models.PROTECT,
118
125
  blank=False,
119
126
  null=False,
120
127
  )
121
128
  soa_rname = models.CharField(
129
+ verbose_name=_("SOA RName"),
122
130
  max_length=255,
123
131
  blank=False,
124
132
  null=False,
125
- verbose_name="SOA RName",
126
133
  )
127
134
  soa_serial = models.BigIntegerField(
135
+ verbose_name=_("SOA Serial"),
128
136
  blank=True,
129
137
  null=True,
130
- verbose_name="SOA Serial",
131
138
  validators=[MinValueValidator(1), MaxValueValidator(4294967295)],
132
139
  )
133
140
  soa_refresh = models.PositiveIntegerField(
141
+ verbose_name=_("SOA Refresh"),
134
142
  blank=False,
135
143
  null=False,
136
- verbose_name="SOA Refresh",
137
144
  validators=[MinValueValidator(1)],
138
145
  )
139
146
  soa_retry = models.PositiveIntegerField(
147
+ verbose_name=_("SOA Retry"),
140
148
  blank=False,
141
149
  null=False,
142
- verbose_name="SOA Retry",
143
150
  validators=[MinValueValidator(1)],
144
151
  )
145
152
  soa_expire = models.PositiveIntegerField(
153
+ verbose_name=_("SOA Expire"),
146
154
  blank=False,
147
155
  null=False,
148
- verbose_name="SOA Expire",
149
156
  validators=[MinValueValidator(1)],
150
157
  )
151
158
  soa_minimum = models.PositiveIntegerField(
159
+ verbose_name=_("SOA Minimum TTL"),
152
160
  blank=False,
153
161
  null=False,
154
- verbose_name="SOA Minimum TTL",
155
162
  validators=[MinValueValidator(1)],
156
163
  )
157
164
  soa_serial_auto = models.BooleanField(
158
- verbose_name="Generate SOA Serial",
159
- help_text="Automatically generate the SOA Serial field",
165
+ verbose_name=_("Generate SOA Serial"),
166
+ help_text=_("Automatically generate the SOA serial number"),
160
167
  default=True,
161
168
  )
162
169
  description = models.CharField(
170
+ verbose_name=_("Description"),
163
171
  max_length=200,
164
172
  blank=True,
165
173
  )
166
174
  arpa_network = NetworkField(
167
- verbose_name="ARPA Network",
168
- help_text="Network related to a reverse lookup zone (.arpa)",
175
+ verbose_name=_("ARPA Network"),
176
+ help_text=_("Network related to a reverse lookup zone (.arpa)"),
169
177
  blank=True,
170
178
  null=True,
171
179
  )
172
180
  tenant = models.ForeignKey(
181
+ verbose_name=_("Tenant"),
173
182
  to="tenancy.Tenant",
174
183
  on_delete=models.PROTECT,
175
184
  related_name="netbox_dns_zones",
@@ -177,72 +186,66 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
177
186
  null=True,
178
187
  )
179
188
  registrar = models.ForeignKey(
189
+ verbose_name=_("Registrar"),
180
190
  to="Registrar",
181
191
  on_delete=models.SET_NULL,
182
- verbose_name="Registrar",
183
- help_text="The external registrar the domain is registered with",
184
192
  blank=True,
185
193
  null=True,
186
194
  )
187
195
  registry_domain_id = models.CharField(
188
- verbose_name="Registry Domain ID",
189
- help_text="The ID of the domain assigned by the registry",
196
+ verbose_name=_("Registry Domain ID"),
190
197
  max_length=50,
191
198
  blank=True,
192
199
  null=True,
193
200
  )
194
201
  registrant = models.ForeignKey(
202
+ verbose_name=_("Registrant"),
195
203
  to="RegistrationContact",
196
204
  on_delete=models.SET_NULL,
197
- verbose_name="Registrant",
198
- help_text="The owner of the domain",
199
205
  blank=True,
200
206
  null=True,
201
207
  )
202
208
  admin_c = models.ForeignKey(
209
+ verbose_name="Administrative Contact",
203
210
  to="RegistrationContact",
204
211
  on_delete=models.SET_NULL,
205
- verbose_name="Admin Contact",
206
212
  related_name="admin_c_zones",
207
- help_text="The administrative contact for the domain",
208
213
  blank=True,
209
214
  null=True,
210
215
  )
211
216
  tech_c = models.ForeignKey(
217
+ verbose_name=_("Technical Contact"),
212
218
  to="RegistrationContact",
213
219
  on_delete=models.SET_NULL,
214
- verbose_name="Technical Contact",
215
220
  related_name="tech_c_zones",
216
- help_text="The technical contact for the domain",
217
221
  blank=True,
218
222
  null=True,
219
223
  )
220
224
  billing_c = models.ForeignKey(
225
+ verbose_name=_("Billing Contact"),
221
226
  to="RegistrationContact",
222
227
  on_delete=models.SET_NULL,
223
- verbose_name="Billing Contact",
224
228
  related_name="billing_c_zones",
225
- help_text="The billing contact for the domain",
226
229
  blank=True,
227
230
  null=True,
228
231
  )
229
232
  rfc2317_prefix = RFC2317NetworkField(
230
- verbose_name="RCF2317 Prefix",
231
- help_text="RFC2317 IPv4 prefix prefix with a length of at least 25 bits",
233
+ verbose_name=_("RFC2317 Prefix"),
234
+ help_text=_("RFC2317 IPv4 prefix with a length of at least 25 bits"),
232
235
  blank=True,
233
236
  null=True,
234
237
  )
235
238
  rfc2317_parent_managed = models.BooleanField(
236
- verbose_name="RFC2317 Parent Managed",
237
- help_text="The parent zone for the RFC2317 zone is managed by NetBox DNS",
239
+ verbose_name=_("RFC2317 Parent Managed"),
240
+ help_text=_("The parent zone for the RFC2317 zone is managed by NetBox DNS"),
238
241
  default=False,
239
242
  )
240
243
  rfc2317_parent_zone = models.ForeignKey(
244
+ verbose_name=_("RFC2317 Parent Zone"),
241
245
  to="self",
242
246
  on_delete=models.SET_NULL,
243
- verbose_name="RFC2317 Parent Zone",
244
247
  related_name="rfc2317_child_zones",
245
- help_text="Parent zone for RFC2317 reverse zones",
248
+ help_text=_("Parent zone for RFC2317 reverse zones"),
246
249
  blank=True,
247
250
  null=True,
248
251
  )
@@ -266,8 +269,8 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
266
269
  )
267
270
 
268
271
  class Meta:
269
- verbose_name = "Zone"
270
- verbose_name_plural = "Zones"
272
+ verbose_name = _("Zone")
273
+ verbose_name_plural = _("Zones")
271
274
 
272
275
  ordering = (
273
276
  "view",
@@ -297,11 +300,21 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
297
300
 
298
301
  @staticmethod
299
302
  def get_defaults():
303
+ default_fields = (
304
+ "zone_default_ttl",
305
+ "zone_soa_ttl",
306
+ "zone_soa_serial",
307
+ "zone_soa_refresh",
308
+ "zone_soa_retry",
309
+ "zone_soa_expire",
310
+ "zone_soa_minimum",
311
+ "zone_soa_rname",
312
+ )
313
+
300
314
  return {
301
315
  field[5:]: value
302
316
  for field, value in settings.PLUGINS_CONFIG.get("netbox_dns").items()
303
- if field.startswith("zone_")
304
- and field not in ("zone_soa_mname", "zone_nameservers")
317
+ if field in default_fields
305
318
  }
306
319
 
307
320
  @property
@@ -335,7 +348,7 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
335
348
 
336
349
  @property
337
350
  def is_active(self):
338
- return self.status in Zone.ACTIVE_STATUS_LIST
351
+ return self.status in ZONE_ACTIVE_STATUS_LIST
339
352
 
340
353
  @property
341
354
  def is_reverse_zone(self):
@@ -453,7 +466,9 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
453
466
  ns_errors = []
454
467
 
455
468
  if not nameservers:
456
- ns_errors.append(f"No nameservers are configured for zone {self}")
469
+ ns_errors.append(
470
+ _("No nameservers are configured for zone {zone}").format(zone=self)
471
+ )
457
472
 
458
473
  for _nameserver in nameservers:
459
474
  name = dns_name.from_text(_nameserver.name, origin=None)
@@ -470,14 +485,16 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
470
485
  relative_name = name.relativize(parent).to_text()
471
486
  address_records = Record.objects.filter(
472
487
  Q(zone=ns_zone),
473
- Q(status__in=Record.ACTIVE_STATUS_LIST),
488
+ Q(status__in=RECORD_ACTIVE_STATUS_LIST),
474
489
  Q(Q(name=f"{_nameserver.name}.") | Q(name=relative_name)),
475
490
  Q(Q(type=RecordTypeChoices.A) | Q(type=RecordTypeChoices.AAAA)),
476
491
  )
477
492
 
478
493
  if not address_records:
479
494
  ns_warnings.append(
480
- f"Nameserver {_nameserver.name} does not have an active address record in zone {ns_zone}"
495
+ _(
496
+ "Nameserver {nameserver} does not have an active address record in zone {zone}"
497
+ ).format(nameserver=_nameserver.name, zone=ns_zone)
481
498
  )
482
499
 
483
500
  return ns_warnings, ns_errors
@@ -491,7 +508,11 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
491
508
 
492
509
  if (new_serial - old_serial) % SOA_SERIAL_WRAP > MAX_SOA_SERIAL_INCREMENT:
493
510
  raise ValidationError(
494
- {"soa_serial": f"soa_serial must not decrease for zone {self.name}."}
511
+ {
512
+ "soa_serial": _(
513
+ "soa_serial must not decrease for zone {zone}."
514
+ ).format(zone=self.name)
515
+ }
495
516
  )
496
517
 
497
518
  def get_auto_serial(self):
@@ -602,7 +623,9 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
602
623
  self.soa_mname = NameServer.objects.get(name=default_soa_mname)
603
624
  except NameServer.DoesNotExist:
604
625
  raise ValidationError(
605
- f"Default soa_mname instance {default_soa_mname} does not exist"
626
+ _("Default soa_mname instance {nameserver} does not exist").format(
627
+ nameserver=default_soa_mname
628
+ )
606
629
  )
607
630
 
608
631
  super().clean_fields(exclude=exclude)
@@ -630,7 +653,7 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
630
653
  ) from None
631
654
 
632
655
  if self.soa_rname in (None, ""):
633
- raise ValidationError("soa_rname not set and no default value defined")
656
+ raise ValidationError(_("soa_rname not set and no default value defined"))
634
657
  try:
635
658
  dns_name.from_text(self.soa_rname, origin=dns_name.root)
636
659
  validate_rname(self.soa_rname)
@@ -645,7 +668,9 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
645
668
  if self.soa_serial is None:
646
669
  raise ValidationError(
647
670
  {
648
- "soa_serial": f"soa_serial is not defined and soa_serial_auto is disabled for zone {self.name}."
671
+ "soa_serial": _(
672
+ "soa_serial is not defined and soa_serial_auto is disabled for zone {zone}."
673
+ ).format(zone=self.name)
649
674
  }
650
675
  )
651
676
 
@@ -663,7 +688,9 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
663
688
  except ValidationError:
664
689
  raise ValidationError(
665
690
  {
666
- "soa_serial_auto": f"Enabling soa_serial_auto would decrease soa_serial for zone {self.name}."
691
+ "soa_serial_auto": _(
692
+ "Enabling soa_serial_auto would decrease soa_serial for zone {zone}."
693
+ ).format(zone=self.name)
667
694
  }
668
695
  )
669
696
 
@@ -697,7 +724,9 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
697
724
  if self.arpa_network is not None:
698
725
  raise ValidationError(
699
726
  {
700
- "rfc2317_prefix": "A regular reverse zone can not be used as an RFC2317 zone."
727
+ "rfc2317_prefix": _(
728
+ "A regular reverse zone can not be used as an RFC2317 zone."
729
+ )
701
730
  }
702
731
  )
703
732
 
@@ -707,7 +736,9 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
707
736
  if rfc2317_parent_zone is None:
708
737
  raise ValidationError(
709
738
  {
710
- "rfc2317_parent_managed": f"Parent zone not found in view {self.view}."
739
+ "rfc2317_parent_managed": _(
740
+ "Parent zone not found in view {view}."
741
+ ).format(view=self.view)
711
742
  }
712
743
  )
713
744
 
@@ -724,7 +755,9 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
724
755
  if overlapping_zones.exists():
725
756
  raise ValidationError(
726
757
  {
727
- "rfc2317_prefix": f"RFC2317 prefix overlaps with zone {overlapping_zones.first()}."
758
+ "rfc2317_prefix": _(
759
+ "RFC2317 prefix overlaps with zone {zone}."
760
+ ).format(zone=overlapping_zones.first())
728
761
  }
729
762
  )
730
763
 
@@ -1,5 +1,6 @@
1
1
  from django.db import models
2
2
  from django.urls import reverse
3
+ from django.utils.translation import gettext_lazy as _
3
4
 
4
5
  from netbox.models import NetBoxModel
5
6
  from netbox.search import SearchIndex, register_search
@@ -13,25 +14,29 @@ __all__ = (
13
14
 
14
15
  class ZoneTemplate(NetBoxModel):
15
16
  name = models.CharField(
16
- verbose_name="Template name",
17
+ verbose_name=_("Template Name"),
17
18
  unique=True,
18
19
  max_length=200,
19
20
  )
20
21
  description = models.CharField(
22
+ verbose_name=_("Description"),
21
23
  max_length=200,
22
24
  blank=True,
23
25
  )
24
26
  nameservers = models.ManyToManyField(
27
+ verbose_name=_("Nameservers"),
25
28
  to="NameServer",
26
29
  related_name="+",
27
30
  blank=True,
28
31
  )
29
32
  record_templates = models.ManyToManyField(
33
+ verbose_name=_("Record Templates"),
30
34
  to="RecordTemplate",
31
35
  related_name="zone_templates",
32
36
  blank=True,
33
37
  )
34
38
  tenant = models.ForeignKey(
39
+ verbose_name=_("Tenant"),
35
40
  to="tenancy.Tenant",
36
41
  on_delete=models.SET_NULL,
37
42
  related_name="+",
@@ -39,45 +44,42 @@ class ZoneTemplate(NetBoxModel):
39
44
  null=True,
40
45
  )
41
46
  registrar = models.ForeignKey(
47
+ verbose_name=_("Registrar"),
42
48
  to="Registrar",
43
49
  on_delete=models.SET_NULL,
44
50
  related_name="+",
45
- help_text="The external registrar the domain is registered with",
46
51
  blank=True,
47
52
  null=True,
48
53
  )
49
54
  registrant = models.ForeignKey(
55
+ verbose_name=_("Registrant"),
50
56
  to="RegistrationContact",
51
57
  on_delete=models.SET_NULL,
52
58
  related_name="+",
53
- help_text="The owner of the domain",
54
59
  blank=True,
55
60
  null=True,
56
61
  )
57
62
  admin_c = models.ForeignKey(
63
+ verbose_name=_("Administrative Contact"),
58
64
  to="RegistrationContact",
59
65
  on_delete=models.SET_NULL,
60
- verbose_name="Admin contact",
61
66
  related_name="+",
62
- help_text="The administrative contact for the domain",
63
67
  blank=True,
64
68
  null=True,
65
69
  )
66
70
  tech_c = models.ForeignKey(
71
+ verbose_name=_("Technical Contact"),
67
72
  to="RegistrationContact",
68
73
  on_delete=models.SET_NULL,
69
- verbose_name="Tech contact",
70
74
  related_name="+",
71
- help_text="The technical contact for the domain",
72
75
  blank=True,
73
76
  null=True,
74
77
  )
75
78
  billing_c = models.ForeignKey(
79
+ verbose_name=_("Billing Contact"),
76
80
  to="RegistrationContact",
77
81
  on_delete=models.SET_NULL,
78
- verbose_name="Billing contact",
79
82
  related_name="+",
80
- help_text="The billing contact for the domain",
81
83
  blank=True,
82
84
  null=True,
83
85
  )
@@ -104,7 +106,7 @@ class ZoneTemplate(NetBoxModel):
104
106
  )
105
107
 
106
108
  class Meta:
107
- verbose_name = "Zone Template"
109
+ verbose_name = _("Zone Template")
108
110
  verbose_name_plural = "Zone Templates"
109
111
 
110
112
  ordering = ("name",)