netbox-plugin-dns 1.2.1__tar.gz → 1.2.3__tar.gz

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 (155) hide show
  1. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/PKG-INFO +13 -2
  2. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/README.md +12 -1
  3. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/__init__.py +2 -1
  4. netbox_plugin_dns-1.2.3/netbox_dns/choices/record.py +80 -0
  5. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/record.py +9 -4
  6. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/record_template.py +9 -4
  7. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/zone.py +8 -1
  8. netbox_plugin_dns-1.2.3/netbox_dns/models/__init__.py +8 -0
  9. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/models/nameserver.py +1 -0
  10. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/models/record.py +1 -0
  11. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/models/view.py +1 -0
  12. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/models/zone.py +1 -0
  13. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/nameserver.html +2 -0
  14. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/record.html +20 -20
  15. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/view.html +2 -0
  16. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone.html +12 -5
  17. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zonetemplate.html +2 -4
  18. netbox_plugin_dns-1.2.3/netbox_dns/templatetags/__init__.py +0 -0
  19. netbox_plugin_dns-1.2.3/netbox_dns/templatetags/netbox_dns.py +10 -0
  20. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/utilities/conversions.py +25 -0
  21. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/validators/dns_name.py +10 -1
  22. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/nameserver.py +1 -0
  23. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/record.py +1 -0
  24. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/record_template.py +1 -0
  25. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/registrar.py +1 -0
  26. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/registration_contact.py +1 -0
  27. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/view.py +1 -0
  28. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/zone.py +1 -0
  29. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/zone_template.py +1 -0
  30. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_plugin_dns.egg-info/PKG-INFO +13 -2
  31. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_plugin_dns.egg-info/SOURCES.txt +2 -0
  32. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/pyproject.toml +1 -1
  33. netbox_plugin_dns-1.2.1/netbox_dns/choices/record.py +0 -51
  34. netbox_plugin_dns-1.2.1/netbox_dns/models/__init__.py +0 -13
  35. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/LICENSE +0 -0
  36. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/nested_serializers.py +0 -0
  37. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers.py +0 -0
  38. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/__init__.py +0 -0
  39. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/nameserver.py +0 -0
  40. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/prefix.py +0 -0
  41. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/record.py +0 -0
  42. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/record_template.py +0 -0
  43. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/registrar.py +0 -0
  44. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/registration_contact.py +0 -0
  45. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/view.py +0 -0
  46. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/zone.py +0 -0
  47. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/serializers_/zone_template.py +0 -0
  48. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/urls.py +0 -0
  49. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/api/views.py +0 -0
  50. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/apps.py +0 -0
  51. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/choices/__init__.py +0 -0
  52. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/choices/zone.py +0 -0
  53. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/fields/__init__.py +0 -0
  54. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/fields/address.py +0 -0
  55. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/fields/ipam.py +0 -0
  56. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/fields/network.py +0 -0
  57. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/fields/rfc2317.py +0 -0
  58. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/__init__.py +0 -0
  59. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/nameserver.py +0 -0
  60. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/record.py +0 -0
  61. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/record_template.py +0 -0
  62. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/registrar.py +0 -0
  63. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/registration_contact.py +0 -0
  64. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/view.py +0 -0
  65. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/zone.py +0 -0
  66. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/filtersets/zone_template.py +0 -0
  67. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/__init__.py +0 -0
  68. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/nameserver.py +0 -0
  69. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/registrar.py +0 -0
  70. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/registration_contact.py +0 -0
  71. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/view.py +0 -0
  72. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/forms/zone_template.py +0 -0
  73. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/graphql/__init__.py +0 -0
  74. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/graphql/filters.py +0 -0
  75. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/graphql/schema.py +0 -0
  76. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/graphql/types.py +0 -0
  77. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/locale/de/LC_MESSAGES/django.mo +0 -0
  78. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/locale/en/LC_MESSAGES/django.mo +0 -0
  79. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/management/commands/cleanup_database.py +0 -0
  80. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/management/commands/cleanup_rrset_ttl.py +0 -0
  81. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/management/commands/rebuild_dnssync.py +0 -0
  82. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/management/commands/setup_dnssync.py +0 -0
  83. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/management/commands/update_soa.py +0 -0
  84. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0001_squashed_netbox_dns_0_15.py +0 -0
  85. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0001_squashed_netbox_dns_0_22.py +0 -0
  86. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0002_contact_description_registrar_description.py +0 -0
  87. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0003_default_view.py +0 -0
  88. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0004_create_and_assign_default_view.py +0 -0
  89. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0005_alter_zone_view_not_null.py +0 -0
  90. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0006_templating.py +0 -0
  91. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0007_alter_ordering_options.py +0 -0
  92. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0008_view_prefixes.py +0 -0
  93. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0009_rename_contact_registrationcontact.py +0 -0
  94. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0010_view_ip_address_filter.py +0 -0
  95. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0011_rename_related_fields.py +0 -0
  96. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0012_natural_ordering.py +0 -0
  97. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0020_netbox_3_4.py +0 -0
  98. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0021_record_ip_address.py +0 -0
  99. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0022_search.py +0 -0
  100. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0023_alter_record_value.py +0 -0
  101. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0024_tenancy.py +0 -0
  102. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0025_ipam_coupling_cf.py +0 -0
  103. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0026_domain_registration.py +0 -0
  104. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0027_alter_registrar_iana_id.py +0 -0
  105. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0028_rfc2317_fields.py +0 -0
  106. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/0029_record_fqdn.py +0 -0
  107. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/migrations/__init__.py +0 -0
  108. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/mixins/__init__.py +0 -0
  109. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/mixins/object_modification.py +0 -0
  110. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/models/record_template.py +0 -0
  111. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/models/registrar.py +0 -0
  112. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/models/registration_contact.py +0 -0
  113. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/models/zone_template.py +0 -0
  114. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/navigation.py +0 -0
  115. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/signals/__init__.py +0 -0
  116. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/signals/ipam_dnssync.py +0 -0
  117. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/__init__.py +0 -0
  118. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/ipam_dnssync.py +0 -0
  119. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/nameserver.py +0 -0
  120. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/record.py +0 -0
  121. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/record_template.py +0 -0
  122. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/registrar.py +0 -0
  123. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/registration_contact.py +0 -0
  124. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/view.py +0 -0
  125. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/zone.py +0 -0
  126. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/tables/zone_template.py +0 -0
  127. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/template_content.py +0 -0
  128. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/record/managed.html +0 -0
  129. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/record/related.html +0 -0
  130. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/recordtemplate.html +6 -6
  131. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/registrar.html +0 -0
  132. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/registrationcontact.html +0 -0
  133. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/view/button.html +0 -0
  134. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/view/prefix.html +0 -0
  135. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/view/related.html +0 -0
  136. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone/base.html +0 -0
  137. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone/child.html +0 -0
  138. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone/child_zone.html +0 -0
  139. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone/delegation_record.html +0 -0
  140. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone/managed_record.html +0 -0
  141. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone/record.html +0 -0
  142. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone/registration.html +0 -0
  143. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/templates/netbox_dns/zone/rfc2317_child_zone.html +0 -0
  144. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/urls.py +0 -0
  145. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/utilities/__init__.py +0 -0
  146. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/utilities/dns.py +0 -0
  147. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/utilities/ipam_dnssync.py +0 -0
  148. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/validators/__init__.py +0 -0
  149. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/validators/dns_value.py +0 -0
  150. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/validators/rfc2317.py +0 -0
  151. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_dns/views/__init__.py +0 -0
  152. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_plugin_dns.egg-info/dependency_links.txt +0 -0
  153. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_plugin_dns.egg-info/requires.txt +0 -0
  154. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/netbox_plugin_dns.egg-info/top_level.txt +0 -0
  155. {netbox_plugin_dns-1.2.1 → netbox_plugin_dns-1.2.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: netbox-plugin-dns
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: NetBox DNS is a NetBox plugin for managing DNS data.
5
5
  Author-email: Peter Eckel <pete@netbox-dns.org>
6
6
  Project-URL: Homepage, https://github.com/peteeckel/netbox-plugin-dns
@@ -66,9 +66,20 @@ For integration with a large number of DNS server implementations integration to
66
66
 
67
67
  ## Requirements
68
68
 
69
- * NetBox 4.0.0 or higher
69
+ * NetBox 4.2.0 or higher
70
70
  * Python 3.10 or higher
71
71
 
72
+ ## Compatibility with NetBox Versions
73
+
74
+ NetBox Version | NetBox DNS Version | Comment
75
+ -------------- | ------------------ | -------
76
+ 3.5 | 0.22 |
77
+ 3.6 | 0.22 |
78
+ 3.7 | 0.22 |
79
+ 4.0 - 4.1 | 1.0 | Supports legacy IPAM Coupling
80
+ 4.0 - 4.1 | 1.1 | Supports IPAM DNSsync
81
+ 4.2 | 1.2 |
82
+
72
83
  ## Installation & Configuration
73
84
 
74
85
  ### Installation
@@ -50,9 +50,20 @@ For integration with a large number of DNS server implementations integration to
50
50
 
51
51
  ## Requirements
52
52
 
53
- * NetBox 4.0.0 or higher
53
+ * NetBox 4.2.0 or higher
54
54
  * Python 3.10 or higher
55
55
 
56
+ ## Compatibility with NetBox Versions
57
+
58
+ NetBox Version | NetBox DNS Version | Comment
59
+ -------------- | ------------------ | -------
60
+ 3.5 | 0.22 |
61
+ 3.6 | 0.22 |
62
+ 3.7 | 0.22 |
63
+ 4.0 - 4.1 | 1.0 | Supports legacy IPAM Coupling
64
+ 4.0 - 4.1 | 1.1 | Supports IPAM DNSsync
65
+ 4.2 | 1.2 |
66
+
56
67
  ## Installation & Configuration
57
68
 
58
69
  ### Installation
@@ -7,7 +7,7 @@ from ipam.choices import IPAddressStatusChoices
7
7
 
8
8
  from netbox_dns.choices import RecordTypeChoices, RecordStatusChoices, ZoneStatusChoices
9
9
 
10
- __version__ = "1.2.1"
10
+ __version__ = "1.2.3"
11
11
 
12
12
 
13
13
  def _check_list(setting):
@@ -36,6 +36,7 @@ class DNSConfig(PluginConfig):
36
36
  ZoneStatusChoices.STATUS_ACTIVE,
37
37
  ZoneStatusChoices.STATUS_DYNAMIC,
38
38
  ],
39
+ "filter_record_types": [],
39
40
  "record_active_status": [
40
41
  RecordStatusChoices.STATUS_ACTIVE,
41
42
  ],
@@ -0,0 +1,80 @@
1
+ from dns import rdatatype, rdataclass
2
+
3
+ from django.utils.translation import gettext_lazy as _
4
+ from django.core.exceptions import ImproperlyConfigured
5
+
6
+ from netbox.plugins.utils import get_plugin_config
7
+ from utilities.choices import ChoiceSet
8
+
9
+
10
+ __all__ = (
11
+ "RecordTypeChoices",
12
+ "RecordSelectableTypeChoices",
13
+ "RecordClassChoices",
14
+ "RecordStatusChoices",
15
+ )
16
+
17
+
18
+ def define_choice_attributes(filter_name=None):
19
+ try:
20
+ if filter_name is not None:
21
+ filter_choices = get_plugin_config("netbox_dns", filter_name, [])
22
+ else:
23
+ filter_choices = []
24
+ except ImproperlyConfigured:
25
+ filter_choices = []
26
+
27
+ def decorator(cls):
28
+ choices = []
29
+ for choice in cls._choices:
30
+ if choice[0] not in filter_choices:
31
+ setattr(cls, choice[0], choice[0])
32
+ choices.append(choice)
33
+ cls._choices = choices
34
+ cls.CHOICES = choices
35
+
36
+ return cls
37
+
38
+ return decorator
39
+
40
+
41
+ @define_choice_attributes()
42
+ class RecordTypeChoices(ChoiceSet):
43
+ CHOICES = [
44
+ (rdtype.name, rdtype.name)
45
+ for rdtype in sorted(rdatatype.RdataType, key=lambda a: a.name)
46
+ if not rdatatype.is_metatype(rdtype)
47
+ ]
48
+ SINGLETONS = [
49
+ rdtype.name for rdtype in rdatatype.RdataType if rdatatype.is_singleton(rdtype)
50
+ ]
51
+
52
+
53
+ @define_choice_attributes(filter_name="filter_record_types")
54
+ class RecordSelectableTypeChoices(ChoiceSet):
55
+ CHOICES = [
56
+ (rdtype.name, rdtype.name)
57
+ for rdtype in sorted(rdatatype.RdataType, key=lambda a: a.name)
58
+ if not rdatatype.is_metatype(rdtype)
59
+ ]
60
+
61
+
62
+ @define_choice_attributes()
63
+ class RecordClassChoices(ChoiceSet):
64
+ CHOICES = [
65
+ (rdclass.name, rdclass.name)
66
+ for rdclass in sorted(rdataclass.RdataClass)
67
+ if not rdataclass.is_metaclass(rdclass)
68
+ ]
69
+
70
+
71
+ class RecordStatusChoices(ChoiceSet):
72
+ key = "Record.status"
73
+
74
+ STATUS_ACTIVE = "active"
75
+ STATUS_INACTIVE = "inactive"
76
+
77
+ CHOICES = [
78
+ (STATUS_ACTIVE, _("Active"), "blue"),
79
+ (STATUS_INACTIVE, _("Inactive"), "red"),
80
+ ]
@@ -21,7 +21,7 @@ from tenancy.models import Tenant, TenantGroup
21
21
  from tenancy.forms import TenancyForm, TenancyFilterForm
22
22
 
23
23
  from netbox_dns.models import View, Zone, Record
24
- from netbox_dns.choices import RecordTypeChoices, RecordStatusChoices
24
+ from netbox_dns.choices import RecordSelectableTypeChoices, RecordStatusChoices
25
25
  from netbox_dns.utilities import name_to_unicode
26
26
 
27
27
 
@@ -57,6 +57,11 @@ class RecordForm(TenancyForm, NetBoxModelForm):
57
57
  },
58
58
  label=_("Zone"),
59
59
  )
60
+ type = forms.ChoiceField(
61
+ choices=add_blank_choice(RecordSelectableTypeChoices),
62
+ required=True,
63
+ label=_("Type"),
64
+ )
60
65
 
61
66
  disable_ptr = forms.BooleanField(
62
67
  required=False,
@@ -123,7 +128,7 @@ class RecordFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
123
128
  )
124
129
 
125
130
  type = forms.MultipleChoiceField(
126
- choices=RecordTypeChoices,
131
+ choices=RecordSelectableTypeChoices,
127
132
  required=False,
128
133
  label=_("Type"),
129
134
  )
@@ -210,7 +215,7 @@ class RecordImportForm(NetBoxModelImportForm):
210
215
  help_text=_("This field is required if the zone is not in the default view"),
211
216
  )
212
217
  type = CSVChoiceField(
213
- choices=RecordTypeChoices,
218
+ choices=RecordSelectableTypeChoices,
214
219
  required=True,
215
220
  label=_("Type"),
216
221
  )
@@ -268,7 +273,7 @@ class RecordBulkEditForm(NetBoxModelBulkEditForm):
268
273
  label=_("Zone"),
269
274
  )
270
275
  type = forms.ChoiceField(
271
- choices=add_blank_choice(RecordTypeChoices),
276
+ choices=add_blank_choice(RecordSelectableTypeChoices),
272
277
  required=False,
273
278
  label=_("Type"),
274
279
  )
@@ -21,7 +21,7 @@ from tenancy.models import Tenant, TenantGroup
21
21
  from tenancy.forms import TenancyForm, TenancyFilterForm
22
22
 
23
23
  from netbox_dns.models import RecordTemplate, ZoneTemplate
24
- from netbox_dns.choices import RecordTypeChoices, RecordStatusChoices
24
+ from netbox_dns.choices import RecordSelectableTypeChoices, RecordStatusChoices
25
25
  from netbox_dns.utilities import name_to_unicode
26
26
 
27
27
 
@@ -41,6 +41,11 @@ class RecordTemplateForm(TenancyForm, NetBoxModelForm):
41
41
  if initial_record_name:
42
42
  self.initial["record_name"] = name_to_unicode(initial_record_name)
43
43
 
44
+ type = forms.ChoiceField(
45
+ choices=add_blank_choice(RecordSelectableTypeChoices),
46
+ required=True,
47
+ label=_("Type"),
48
+ )
44
49
  disable_ptr = forms.BooleanField(
45
50
  required=False,
46
51
  label=_("Disable PTR"),
@@ -103,7 +108,7 @@ class RecordTemplateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
103
108
  )
104
109
 
105
110
  type = forms.MultipleChoiceField(
106
- choices=RecordTypeChoices,
111
+ choices=RecordSelectableTypeChoices,
107
112
  required=False,
108
113
  label=_("Type"),
109
114
  )
@@ -142,7 +147,7 @@ class RecordTemplateFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
142
147
 
143
148
  class RecordTemplateImportForm(NetBoxModelImportForm):
144
149
  type = CSVChoiceField(
145
- choices=RecordTypeChoices,
150
+ choices=RecordSelectableTypeChoices,
146
151
  required=True,
147
152
  label=_("Type"),
148
153
  )
@@ -187,7 +192,7 @@ class RecordTemplateBulkEditForm(NetBoxModelBulkEditForm):
187
192
  model = RecordTemplate
188
193
 
189
194
  type = forms.ChoiceField(
190
- choices=add_blank_choice(RecordTypeChoices),
195
+ choices=add_blank_choice(RecordSelectableTypeChoices),
191
196
  required=False,
192
197
  label=_("Type"),
193
198
  )
@@ -35,7 +35,7 @@ from netbox_dns.models import (
35
35
  ZoneTemplate,
36
36
  )
37
37
  from netbox_dns.choices import ZoneStatusChoices
38
- from netbox_dns.utilities import name_to_unicode
38
+ from netbox_dns.utilities import name_to_unicode, network_to_reverse
39
39
  from netbox_dns.fields import RFC2317NetworkFormField
40
40
  from netbox_dns.validators import validate_ipv4, validate_prefix, validate_rfc2317
41
41
 
@@ -307,6 +307,13 @@ class ZoneForm(ZoneTemplateUpdateMixin, TenancyForm, NetBoxModelForm):
307
307
  else self.initial["default_ttl"]
308
308
  )
309
309
 
310
+ def clean_name(self):
311
+ name = self.cleaned_data["name"]
312
+ if reverse_name := network_to_reverse(name):
313
+ return reverse_name
314
+ else:
315
+ return name
316
+
310
317
  class Meta:
311
318
  model = Zone
312
319
 
@@ -0,0 +1,8 @@
1
+ from .zone import *
2
+ from .nameserver import *
3
+ from .record import *
4
+ from .view import *
5
+ from .registration_contact import *
6
+ from .registrar import *
7
+ from .zone_template import *
8
+ from .record_template import *
@@ -50,6 +50,7 @@ class NameServer(ObjectModificationMixin, ContactsMixin, NetBoxModel):
50
50
  clone_fields = (
51
51
  "name",
52
52
  "description",
53
+ "tenant",
53
54
  )
54
55
 
55
56
  class Meta:
@@ -227,6 +227,7 @@ class Record(ObjectModificationMixin, ContactsMixin, NetBoxModel):
227
227
  "ttl",
228
228
  "disable_ptr",
229
229
  "description",
230
+ "tenant",
230
231
  )
231
232
 
232
233
  class Meta:
@@ -64,6 +64,7 @@ class View(ObjectModificationMixin, ContactsMixin, NetBoxModel):
64
64
  clone_fields = (
65
65
  "name",
66
66
  "description",
67
+ "tenant",
67
68
  )
68
69
 
69
70
  @classmethod
@@ -271,6 +271,7 @@ class Zone(ObjectModificationMixin, ContactsMixin, NetBoxModel):
271
271
  "soa_expire",
272
272
  "soa_minimum",
273
273
  "description",
274
+ "tenant",
274
275
  )
275
276
 
276
277
  class Meta:
@@ -23,6 +23,7 @@
23
23
  <td style="word-break:break-all;">{{ object.description }}</td>
24
24
  </tr>
25
25
  {% endif %}
26
+ {% if object.tenant %}
26
27
  <tr>
27
28
  <th scope="row">{% trans "Tenant" %}</th>
28
29
  <td>
@@ -32,6 +33,7 @@
32
33
  {{ object.tenant|linkify|placeholder }}
33
34
  </td>
34
35
  </tr>
36
+ {% endif %}
35
37
  </table>
36
38
  </div>
37
39
  {% include 'inc/panels/custom_fields.html' %}
@@ -63,17 +63,6 @@
63
63
  <td><a href="{% url 'plugins:netbox_dns:zone_records' pk=object.zone.pk %}">{{ object.zone }}</a></td>
64
64
  {% endif %}
65
65
  </tr>
66
- {% if not object.managed or object.tenant %}
67
- <tr>
68
- <th scope="row">{% trans "Tenant" %}</th>
69
- <td>
70
- {% if object.tenant.group %}
71
- {{ object.tenant.group|linkify }} /
72
- {% endif %}
73
- {{ object.tenant|linkify|placeholder }}
74
- </td>
75
- </tr>
76
- {% endif %}
77
66
  <tr>
78
67
  <th scope="row">{% trans "Type" %}</th>
79
68
  <td>{{ object.type }}</td>
@@ -82,16 +71,33 @@
82
71
  <th scope="row">{% trans "Value" %}</th>
83
72
  <td style="word-break:break-all;">{{ object.value }}</td>
84
73
  </tr>
74
+ {% if unicode_value %}
75
+ <tr>
76
+ <th scope="row">{% trans "Unicode Value" %}</th>
77
+ <td style="word-break:break-all;">{{ unicode_value }}</td>
78
+ </tr>
79
+ {% endif %}
85
80
  {% if cname_warning %}
86
81
  <tr class="text-warning">
87
82
  <th scope="row">{% trans "Warning" %}</th>
88
83
  <td>{{ cname_warning }}</td>
89
84
  </tr>
90
85
  {% endif %}
91
- {% if unicode_value %}
86
+ {% if object.description %}
92
87
  <tr>
93
- <th scope="row">{% trans "Unicode Value" %}</th>
94
- <td style="word-break:break-all;">{{ unicode_value }}</td>
88
+ <th scope="row">{% trans "Description" %}</th>
89
+ <td style="word-break:break-all;">{{ object.description }}</td>
90
+ </tr>
91
+ {% endif %}
92
+ {% if object.tenant %}
93
+ <tr>
94
+ <th scope="row">{% trans "Tenant" %}</th>
95
+ <td>
96
+ {% if object.tenant.group %}
97
+ {{ object.tenant.group|linkify }} /
98
+ {% endif %}
99
+ {{ object.tenant|linkify|placeholder }}
100
+ </td>
95
101
  </tr>
96
102
  {% endif %}
97
103
  <tr>
@@ -132,12 +138,6 @@
132
138
  <th scope="row">Status</th>
133
139
  <td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
134
140
  </tr>
135
- {% if object.description %}
136
- <tr>
137
- <th scope="row">{% trans "Description" %}</th>
138
- <td style="word-break:break-all;">{{ object.description }}</td>
139
- </tr>
140
- {% endif %}
141
141
  </table>
142
142
  </div>
143
143
  {% if cname_target_table %}
@@ -21,6 +21,7 @@
21
21
  <td style="word-break:break-all;">{{ object.description }}</td>
22
22
  </tr>
23
23
  {% endif %}
24
+ {% if object.tenant %}
24
25
  <tr>
25
26
  <th scope="row">{% trans "Tenant" %}</th>
26
27
  <td>
@@ -30,6 +31,7 @@
30
31
  {{ object.tenant|linkify|placeholder }}
31
32
  </td>
32
33
  </tr>
34
+ {% endif %}
33
35
  </table>
34
36
  </div>
35
37
  {% include 'inc/panels/custom_fields.html' %}
@@ -1,6 +1,8 @@
1
1
  {% extends 'netbox_dns/zone/base.html' %}
2
2
  {% load helpers %}
3
3
  {% load i18n %}
4
+ {% load netbox_dns %}
5
+ {% load tz %}
4
6
 
5
7
  {% block content %}
6
8
  <div class="row">
@@ -34,6 +36,7 @@
34
36
  <td style="word-break:break-all;">{{ object.description }}</td>
35
37
  </tr>
36
38
  {% endif %}
39
+ {% if object.tenant %}
37
40
  <tr>
38
41
  <th scope="row">{% trans "Tenant" %}</th>
39
42
  <td>
@@ -43,6 +46,7 @@
43
46
  {{ object.tenant|linkify|placeholder }}
44
47
  </td>
45
48
  </tr>
49
+ {% endif %}
46
50
  <tr>
47
51
  <th scope="row">{% trans "Status" %}</th>
48
52
  <td>{% badge object.get_status_display bg_color=object.get_status_color %}</td>
@@ -89,10 +93,6 @@
89
93
  <th scope="row">{% trans "Default TTL" %}</th>
90
94
  <td>{{ object.default_ttl }}</td>
91
95
  </tr>
92
- <tr>
93
- <th scope="row">{% trans "Description" %}</th>
94
- <td>{{ object.description }}</td>
95
- </tr>
96
96
  </table>
97
97
  </div>
98
98
 
@@ -118,7 +118,14 @@
118
118
  {% if object.soa_serial_auto %}
119
119
  <tr>
120
120
  <th scope="row">{% trans "Serial (auto-generated)" %}</th>
121
- <td>{{ object.soa_serial }}</td>
121
+ <td>
122
+ <table style="width: 100%;">
123
+ <tr>
124
+ <td>{{ object.soa_serial }}</td>
125
+ <td align="right" class="text-muted">{{ object.soa_serial|epoch_to_utc|isodatetime }}</td>
126
+ </tr>
127
+ </table>
128
+ </td>
122
129
  </tr>
123
130
  {% else %}
124
131
  <tr>
@@ -21,6 +21,7 @@
21
21
  <td style="word-break:break-all;">{{ object.description }}</td>
22
22
  </tr>
23
23
  {% endif %}
24
+ {% if object.tenant %}
24
25
  <tr>
25
26
  <th scope="row">{% trans "Tenant" %}</th>
26
27
  <td>
@@ -30,6 +31,7 @@
30
31
  {{ object.tenant|linkify|placeholder }}
31
32
  </td>
32
33
  </tr>
34
+ {% endif %}
33
35
  <tr>
34
36
  <th scope="row">{% trans "Nameservers" %}</th>
35
37
  <td>
@@ -40,10 +42,6 @@
40
42
  </table>
41
43
  </td>
42
44
  </tr>
43
- <tr>
44
- <th scope="row">{% trans "Description" %}</th>
45
- <td>{{ object.description }}</td>
46
- </tr>
47
45
  </table>
48
46
  </div>
49
47
 
@@ -0,0 +1,10 @@
1
+ from datetime import datetime, timezone
2
+
3
+ from django import template
4
+
5
+ register = template.Library()
6
+
7
+
8
+ @register.filter(name="epoch_to_utc")
9
+ def epoch_to_utc(epoch):
10
+ return datetime.fromtimestamp(epoch, tz=timezone.utc)
@@ -13,6 +13,7 @@ __all__ = (
13
13
  "name_to_unicode",
14
14
  "value_to_unicode",
15
15
  "normalize_name",
16
+ "network_to_reverse",
16
17
  )
17
18
 
18
19
 
@@ -81,3 +82,27 @@ def normalize_name(name):
81
82
 
82
83
  except DNSException as exc:
83
84
  raise NameFormatError from exc
85
+
86
+
87
+ def network_to_reverse(network):
88
+ try:
89
+ ip_network = IPNetwork(network)
90
+ except AddrFormatError:
91
+ return
92
+
93
+ if ip_network.first == ip_network.last:
94
+ return
95
+
96
+ labels = None
97
+ match ip_network.version:
98
+ case 4:
99
+ if not ip_network.prefixlen % 8:
100
+ labels = 3 + ip_network.prefixlen // 8
101
+ case 6:
102
+ if not ip_network.prefixlen % 4:
103
+ labels = 3 + ip_network.prefixlen // 4
104
+ case _:
105
+ return
106
+
107
+ if labels:
108
+ return ".".join(ip_network[0].reverse_dns.split(".")[-labels:])
@@ -1,4 +1,5 @@
1
1
  import re
2
+ from socket import inet_aton
2
3
 
3
4
  from django.core.exceptions import ValidationError
4
5
  from django.utils.translation import gettext as _
@@ -28,7 +29,7 @@ def _get_label(tolerate_leading_underscores=False, always_tolerant=False):
28
29
 
29
30
  tolerate_underscores = get_plugin_config(
30
31
  "netbox_dns", "tolerate_underscores_in_labels"
31
- ) or get_plugin_config("netbox_dns", "tolerate_underscores_in_hostnames")
32
+ )
32
33
 
33
34
  if tolerate_leading_underscores:
34
35
  if tolerate_underscores:
@@ -95,6 +96,14 @@ def validate_domain_name(
95
96
  ):
96
97
  return
97
98
 
99
+ try:
100
+ inet_aton(name)
101
+ raise ValidationError(
102
+ _("{name} is not a valid DNS domain name").format(name=name)
103
+ )
104
+ except OSError:
105
+ pass
106
+
98
107
  label, zone_label = _get_label(always_tolerant=always_tolerant)
99
108
  if zone_name:
100
109
  regex = rf"^{zone_label}(\.{zone_label})*\.?$"
@@ -83,6 +83,7 @@ class NameServerBulkEditView(generic.BulkEditView):
83
83
  @register_model_view(NameServer, "bulk_delete", path="delete", detail=False)
84
84
  class NameServerBulkDeleteView(generic.BulkDeleteView):
85
85
  queryset = NameServer.objects.all()
86
+ filterset = NameServerFilterSet
86
87
  table = NameServerTable
87
88
 
88
89
 
@@ -198,6 +198,7 @@ class RecordBulkEditView(generic.BulkEditView):
198
198
  @register_model_view(Record, "bulk_delete", path="delete", detail=False)
199
199
  class RecordBulkDeleteView(generic.BulkDeleteView):
200
200
  queryset = Record.objects.filter(managed=False)
201
+ filterset = RecordFilterSet
201
202
  table = RecordTable
202
203
 
203
204
 
@@ -90,4 +90,5 @@ class RecordTemplateBulkEditView(generic.BulkEditView):
90
90
  @register_model_view(RecordTemplate, "bulk_delete", path="delete", detail=False)
91
91
  class RecordTemplateBulkDeleteView(generic.BulkDeleteView):
92
92
  queryset = RecordTemplate.objects.all()
93
+ filterset = RecordTemplateFilterSet
93
94
  table = RecordTemplateTable
@@ -72,6 +72,7 @@ class RegistrarBulkEditView(generic.BulkEditView):
72
72
  @register_model_view(Registrar, "bulk_delete", path="delete", detail=False)
73
73
  class RegistrarBulkDeleteView(generic.BulkDeleteView):
74
74
  queryset = Registrar.objects.all()
75
+ filterset = RegistrarFilterSet
75
76
  table = RegistrarTable
76
77
 
77
78
 
@@ -73,6 +73,7 @@ class RegistrationContactBulkEditView(generic.BulkEditView):
73
73
  @register_model_view(RegistrationContact, "bulk_delete", path="delete", detail=False)
74
74
  class RegistrationContactBulkDeleteView(generic.BulkDeleteView):
75
75
  queryset = RegistrationContact.objects.all()
76
+ filterset = RegistrationContactFilterSet
76
77
  table = RegistrationContactTable
77
78
 
78
79
 
@@ -76,6 +76,7 @@ class ViewBulkEditView(generic.BulkEditView):
76
76
  @register_model_view(View, "bulk_delete", path="delete", detail=False)
77
77
  class ViewBulkDeleteView(generic.BulkDeleteView):
78
78
  queryset = View.objects.all()
79
+ filterset = ViewFilterSet
79
80
  table = ViewTable
80
81
 
81
82
 
@@ -101,6 +101,7 @@ class ZoneBulkEditView(generic.BulkEditView):
101
101
  @register_model_view(Zone, "bulk_delete", path="delete", detail=False)
102
102
  class ZoneBulkDeleteView(generic.BulkDeleteView):
103
103
  queryset = Zone.objects.all()
104
+ filterset = ZoneFilterSet
104
105
  table = ZoneTable
105
106
 
106
107
 
@@ -80,4 +80,5 @@ class ZoneTemplateBulkEditView(generic.BulkEditView):
80
80
  @register_model_view(ZoneTemplate, "bulk_delete", path="delete", detail=False)
81
81
  class ZoneTemplateBulkDeleteView(generic.BulkDeleteView):
82
82
  queryset = ZoneTemplate.objects.all()
83
+ filterset = ZoneTemplateFilterSet
83
84
  table = ZoneTemplateTable