2
0

model_forms.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. from django.contrib.contenttypes.models import ContentType
  2. from django.utils.translation import gettext_lazy as _
  3. from circuits.choices import (
  4. CircuitCommitRateChoices,
  5. CircuitPriorityChoices,
  6. CircuitStatusChoices,
  7. CircuitTerminationPortSpeedChoices,
  8. CircuitTerminationSideChoices,
  9. VirtualCircuitTerminationRoleChoices,
  10. )
  11. from circuits.constants import *
  12. from circuits.models import *
  13. from dcim.models import Interface
  14. from ipam.models import ASN
  15. from netbox.choices import DistanceUnitChoices
  16. from netbox.forms import NetBoxModelForm, OrganizationalModelForm, PrimaryModelForm
  17. from tenancy.forms import TenancyForm
  18. from utilities.forms import GenericObjectFormMixin, add_blank_choice
  19. from utilities.forms.fields import (
  20. ChoiceField,
  21. DynamicModelChoiceField,
  22. DynamicModelMultipleChoiceField,
  23. GenericObjectChoiceField,
  24. SlugField,
  25. TypedChoiceField,
  26. )
  27. from utilities.forms.mixins import DistanceValidationMixin
  28. from utilities.forms.rendering import FieldSet, InlineFields, M2MAddRemoveFields
  29. from utilities.forms.widgets import DatePicker, NumberWithOptions
  30. __all__ = (
  31. 'CircuitForm',
  32. 'CircuitGroupAssignmentForm',
  33. 'CircuitGroupForm',
  34. 'CircuitTerminationForm',
  35. 'CircuitTypeForm',
  36. 'ProviderAccountForm',
  37. 'ProviderForm',
  38. 'ProviderNetworkForm',
  39. 'VirtualCircuitForm',
  40. 'VirtualCircuitTerminationForm',
  41. 'VirtualCircuitTypeForm',
  42. )
  43. class ProviderForm(PrimaryModelForm):
  44. slug = SlugField()
  45. asns = DynamicModelMultipleChoiceField(
  46. queryset=ASN.objects.all(),
  47. label=_('ASNs'),
  48. required=False
  49. )
  50. add_asns = DynamicModelMultipleChoiceField(
  51. queryset=ASN.objects.all(),
  52. label=_('Add ASNs'),
  53. required=False
  54. )
  55. remove_asns = DynamicModelMultipleChoiceField(
  56. queryset=ASN.objects.all(),
  57. label=_('Remove ASNs'),
  58. required=False
  59. )
  60. fieldsets = (
  61. FieldSet('name', 'slug', M2MAddRemoveFields('asns'), 'description', 'tags'),
  62. )
  63. class Meta:
  64. model = Provider
  65. fields = [
  66. 'name', 'slug', 'description', 'owner', 'comments', 'tags',
  67. ]
  68. def __init__(self, *args, **kwargs):
  69. super().__init__(*args, **kwargs)
  70. if self.instance.pk and (count := self.instance.asns.count()) >= M2MAddRemoveFields.THRESHOLD:
  71. # Add/remove mode for large M2M sets
  72. self.fields.pop('asns')
  73. self.fields['add_asns'].widget.add_query_param('provider_id__n', self.instance.pk)
  74. self.fields['remove_asns'].widget.add_query_param('provider_id', self.instance.pk)
  75. self.fields['remove_asns'].help_text = _("{count} ASNs currently assigned").format(count=count)
  76. else:
  77. # Simple mode for new objects or small M2M sets
  78. self.fields.pop('add_asns')
  79. self.fields.pop('remove_asns')
  80. if self.instance.pk:
  81. self.initial['asns'] = list(self.instance.asns.values_list('pk', flat=True))
  82. class ProviderAccountForm(PrimaryModelForm):
  83. provider = DynamicModelChoiceField(
  84. label=_('Provider'),
  85. queryset=Provider.objects.all(),
  86. selector=True,
  87. quick_add=True
  88. )
  89. fieldsets = (
  90. FieldSet('provider', 'account', 'name', 'description', 'tags'),
  91. )
  92. class Meta:
  93. model = ProviderAccount
  94. fields = [
  95. 'provider', 'account', 'name', 'description', 'owner', 'comments', 'tags',
  96. ]
  97. class ProviderNetworkForm(PrimaryModelForm):
  98. provider = DynamicModelChoiceField(
  99. label=_('Provider'),
  100. queryset=Provider.objects.all(),
  101. selector=True,
  102. quick_add=True
  103. )
  104. fieldsets = (
  105. FieldSet('provider', 'name', 'service_id', 'description', 'tags'),
  106. )
  107. class Meta:
  108. model = ProviderNetwork
  109. fields = [
  110. 'provider', 'name', 'service_id', 'description', 'owner', 'comments', 'tags',
  111. ]
  112. class CircuitTypeForm(OrganizationalModelForm):
  113. fieldsets = (
  114. FieldSet('name', 'slug', 'color', 'description', 'tags'),
  115. )
  116. class Meta:
  117. model = CircuitType
  118. fields = [
  119. 'name', 'slug', 'color', 'description', 'owner', 'comments', 'tags',
  120. ]
  121. class CircuitForm(DistanceValidationMixin, TenancyForm, PrimaryModelForm):
  122. status = ChoiceField(
  123. label=_('Status'),
  124. choices=CircuitStatusChoices,
  125. initial=CircuitStatusChoices.STATUS_ACTIVE,
  126. )
  127. distance_unit = TypedChoiceField(
  128. label=_('Distance unit'),
  129. choices=add_blank_choice(DistanceUnitChoices),
  130. required=False,
  131. )
  132. provider = DynamicModelChoiceField(
  133. label=_('Provider'),
  134. queryset=Provider.objects.all(),
  135. selector=True,
  136. quick_add=True
  137. )
  138. provider_account = DynamicModelChoiceField(
  139. label=_('Provider account'),
  140. queryset=ProviderAccount.objects.all(),
  141. required=False,
  142. query_params={
  143. 'provider_id': '$provider',
  144. }
  145. )
  146. type = DynamicModelChoiceField(
  147. queryset=CircuitType.objects.all(),
  148. quick_add=True
  149. )
  150. fieldsets = (
  151. FieldSet(
  152. 'provider',
  153. 'provider_account',
  154. 'cid',
  155. 'type',
  156. 'status',
  157. InlineFields('distance', 'distance_unit', label=_('Distance')),
  158. 'description',
  159. 'tags',
  160. name=_('Circuit')
  161. ),
  162. FieldSet('install_date', 'termination_date', 'commit_rate', name=_('Service Parameters')),
  163. FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
  164. )
  165. class Meta:
  166. model = Circuit
  167. fields = [
  168. 'cid', 'type', 'provider', 'provider_account', 'status', 'install_date', 'termination_date', 'commit_rate',
  169. 'distance', 'distance_unit', 'description', 'tenant_group', 'tenant', 'owner', 'comments', 'tags',
  170. ]
  171. widgets = {
  172. 'install_date': DatePicker(),
  173. 'termination_date': DatePicker(),
  174. 'commit_rate': NumberWithOptions(
  175. options=CircuitCommitRateChoices
  176. ),
  177. }
  178. class CircuitTerminationForm(GenericObjectFormMixin, NetBoxModelForm):
  179. term_side = ChoiceField(
  180. label=_('Termination side'),
  181. choices=CircuitTerminationSideChoices,
  182. )
  183. circuit = DynamicModelChoiceField(
  184. label=_('Circuit'),
  185. queryset=Circuit.objects.all(),
  186. selector=True
  187. )
  188. termination = GenericObjectChoiceField(
  189. label=_('Termination'),
  190. content_type_queryset=ContentType.objects.filter(model__in=CIRCUIT_TERMINATION_TERMINATION_TYPES),
  191. required=True,
  192. selector=True,
  193. hx_target_id='circuit-termination',
  194. )
  195. fieldsets = (
  196. FieldSet(
  197. 'circuit', 'term_side', 'description', 'tags', 'termination', 'mark_connected',
  198. name=_('Circuit Termination'), html_id='circuit-termination',
  199. ),
  200. FieldSet('port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', name=_('Termination Details')),
  201. )
  202. class Meta:
  203. model = CircuitTermination
  204. fields = [
  205. 'circuit', 'term_side', 'mark_connected', 'port_speed', 'upstream_speed',
  206. 'xconnect_id', 'pp_info', 'description', 'tags',
  207. ]
  208. widgets = {
  209. 'port_speed': NumberWithOptions(
  210. options=CircuitTerminationPortSpeedChoices
  211. ),
  212. 'upstream_speed': NumberWithOptions(
  213. options=CircuitTerminationPortSpeedChoices
  214. ),
  215. }
  216. class CircuitGroupForm(TenancyForm, OrganizationalModelForm):
  217. fieldsets = (
  218. FieldSet('name', 'slug', 'description', 'tags', name=_('Circuit Group')),
  219. FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
  220. )
  221. class Meta:
  222. model = CircuitGroup
  223. fields = [
  224. 'name', 'slug', 'description', 'tenant_group', 'tenant', 'owner', 'comments', 'tags',
  225. ]
  226. class CircuitGroupAssignmentForm(GenericObjectFormMixin, NetBoxModelForm):
  227. priority = TypedChoiceField(
  228. label=_('Priority'),
  229. choices=add_blank_choice(CircuitPriorityChoices),
  230. required=False,
  231. )
  232. group = DynamicModelChoiceField(
  233. label=_('Group'),
  234. queryset=CircuitGroup.objects.all(),
  235. )
  236. member = GenericObjectChoiceField(
  237. label=_('Member'),
  238. content_type_queryset=ContentType.objects.filter(CIRCUIT_GROUP_ASSIGNMENT_MEMBER_MODELS),
  239. required=False,
  240. selector=True,
  241. hx_target_id='circuit-group-assignment',
  242. )
  243. fieldsets = (
  244. FieldSet(
  245. 'group', 'member', 'priority', 'tags',
  246. name=_('Group Assignment'), html_id='circuit-group-assignment',
  247. ),
  248. )
  249. class Meta:
  250. model = CircuitGroupAssignment
  251. fields = [
  252. 'group', 'priority', 'tags',
  253. ]
  254. class VirtualCircuitTypeForm(OrganizationalModelForm):
  255. fieldsets = (
  256. FieldSet('name', 'slug', 'color', 'description', 'tags'),
  257. )
  258. class Meta:
  259. model = VirtualCircuitType
  260. fields = [
  261. 'name', 'slug', 'color', 'description', 'owner', 'comments', 'tags',
  262. ]
  263. class VirtualCircuitForm(TenancyForm, PrimaryModelForm):
  264. status = ChoiceField(
  265. label=_('Status'),
  266. choices=CircuitStatusChoices,
  267. initial=CircuitStatusChoices.STATUS_ACTIVE,
  268. )
  269. provider_network = DynamicModelChoiceField(
  270. label=_('Provider network'),
  271. queryset=ProviderNetwork.objects.all(),
  272. selector=True
  273. )
  274. provider_account = DynamicModelChoiceField(
  275. label=_('Provider account'),
  276. queryset=ProviderAccount.objects.all(),
  277. required=False
  278. )
  279. type = DynamicModelChoiceField(
  280. queryset=VirtualCircuitType.objects.all(),
  281. quick_add=True
  282. )
  283. fieldsets = (
  284. FieldSet(
  285. 'provider_network', 'provider_account', 'cid', 'type', 'status', 'description', 'tags',
  286. name=_('Virtual circuit'),
  287. ),
  288. FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
  289. )
  290. class Meta:
  291. model = VirtualCircuit
  292. fields = [
  293. 'cid', 'provider_network', 'provider_account', 'type', 'status', 'description', 'tenant_group', 'tenant',
  294. 'owner', 'comments', 'tags',
  295. ]
  296. class VirtualCircuitTerminationForm(NetBoxModelForm):
  297. virtual_circuit = DynamicModelChoiceField(
  298. label=_('Virtual circuit'),
  299. queryset=VirtualCircuit.objects.all(),
  300. selector=True
  301. )
  302. role = ChoiceField(
  303. choices=VirtualCircuitTerminationRoleChoices,
  304. label=_('Role')
  305. )
  306. interface = DynamicModelChoiceField(
  307. label=_('Interface'),
  308. queryset=Interface.objects.all(),
  309. selector=True,
  310. query_params={
  311. 'kind': 'virtual',
  312. 'virtual_circuit_termination_id': 'null',
  313. },
  314. context={
  315. 'parent': 'device',
  316. }
  317. )
  318. fieldsets = (
  319. FieldSet(
  320. 'virtual_circuit', 'role', 'interface', 'description', 'tags',
  321. ),
  322. )
  323. class Meta:
  324. model = VirtualCircuitTermination
  325. fields = [
  326. 'virtual_circuit', 'role', 'interface', 'description', 'tags',
  327. ]