forms.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. from django import forms
  2. from django.utils.translation import gettext as _
  3. from dcim.models import Region, Site, SiteGroup
  4. from extras.forms import (
  5. AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldFilterForm, CustomFieldModelForm, CustomFieldModelCSVForm,
  6. )
  7. from extras.models import Tag
  8. from tenancy.forms import TenancyFilterForm, TenancyForm
  9. from tenancy.models import Tenant
  10. from utilities.forms import (
  11. add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, CSVModelChoiceField, DatePicker,
  12. DynamicModelChoiceField, DynamicModelMultipleChoiceField, SelectSpeedWidget, SmallTextarea, SlugField,
  13. StaticSelect2, StaticSelect2Multiple, TagFilterField,
  14. )
  15. from .choices import CircuitStatusChoices
  16. from .models import *
  17. #
  18. # Providers
  19. #
  20. class ProviderForm(BootstrapMixin, CustomFieldModelForm):
  21. slug = SlugField()
  22. comments = CommentField()
  23. tags = DynamicModelMultipleChoiceField(
  24. queryset=Tag.objects.all(),
  25. required=False
  26. )
  27. class Meta:
  28. model = Provider
  29. fields = [
  30. 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags',
  31. ]
  32. fieldsets = (
  33. ('Provider', ('name', 'slug', 'asn', 'tags')),
  34. ('Support Info', ('account', 'portal_url', 'noc_contact', 'admin_contact')),
  35. )
  36. widgets = {
  37. 'noc_contact': SmallTextarea(
  38. attrs={'rows': 5}
  39. ),
  40. 'admin_contact': SmallTextarea(
  41. attrs={'rows': 5}
  42. ),
  43. }
  44. help_texts = {
  45. 'name': "Full name of the provider",
  46. 'asn': "BGP autonomous system number (if applicable)",
  47. 'portal_url': "URL of the provider's customer support portal",
  48. 'noc_contact': "NOC email address and phone number",
  49. 'admin_contact': "Administrative contact email address and phone number",
  50. }
  51. class ProviderCSVForm(CustomFieldModelCSVForm):
  52. slug = SlugField()
  53. class Meta:
  54. model = Provider
  55. fields = Provider.csv_headers
  56. class ProviderBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm):
  57. pk = forms.ModelMultipleChoiceField(
  58. queryset=Provider.objects.all(),
  59. widget=forms.MultipleHiddenInput
  60. )
  61. asn = forms.IntegerField(
  62. required=False,
  63. label='ASN'
  64. )
  65. account = forms.CharField(
  66. max_length=30,
  67. required=False,
  68. label='Account number'
  69. )
  70. portal_url = forms.URLField(
  71. required=False,
  72. label='Portal'
  73. )
  74. noc_contact = forms.CharField(
  75. required=False,
  76. widget=SmallTextarea,
  77. label='NOC contact'
  78. )
  79. admin_contact = forms.CharField(
  80. required=False,
  81. widget=SmallTextarea,
  82. label='Admin contact'
  83. )
  84. comments = CommentField(
  85. widget=SmallTextarea,
  86. label='Comments'
  87. )
  88. class Meta:
  89. nullable_fields = [
  90. 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
  91. ]
  92. class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
  93. model = Provider
  94. q = forms.CharField(
  95. required=False,
  96. label=_('Search')
  97. )
  98. region_id = DynamicModelMultipleChoiceField(
  99. queryset=Region.objects.all(),
  100. required=False,
  101. label=_('Region')
  102. )
  103. site_id = DynamicModelMultipleChoiceField(
  104. queryset=Site.objects.all(),
  105. required=False,
  106. query_params={
  107. 'region_id': '$region_id'
  108. },
  109. label=_('Site')
  110. )
  111. asn = forms.IntegerField(
  112. required=False,
  113. label=_('ASN')
  114. )
  115. tag = TagFilterField(model)
  116. #
  117. # Provider networks
  118. #
  119. class ProviderNetworkForm(BootstrapMixin, CustomFieldModelForm):
  120. provider = DynamicModelChoiceField(
  121. queryset=Provider.objects.all()
  122. )
  123. comments = CommentField()
  124. tags = DynamicModelMultipleChoiceField(
  125. queryset=Tag.objects.all(),
  126. required=False
  127. )
  128. class Meta:
  129. model = ProviderNetwork
  130. fields = [
  131. 'provider', 'name', 'description', 'comments', 'tags',
  132. ]
  133. fieldsets = (
  134. ('Provider Network', ('provider', 'name', 'description', 'tags')),
  135. )
  136. class ProviderNetworkCSVForm(CustomFieldModelCSVForm):
  137. provider = CSVModelChoiceField(
  138. queryset=Provider.objects.all(),
  139. to_field_name='name',
  140. help_text='Assigned provider'
  141. )
  142. class Meta:
  143. model = ProviderNetwork
  144. fields = [
  145. 'provider', 'name', 'description', 'comments',
  146. ]
  147. class ProviderNetworkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm):
  148. pk = forms.ModelMultipleChoiceField(
  149. queryset=ProviderNetwork.objects.all(),
  150. widget=forms.MultipleHiddenInput
  151. )
  152. provider = DynamicModelChoiceField(
  153. queryset=Provider.objects.all(),
  154. required=False
  155. )
  156. description = forms.CharField(
  157. max_length=100,
  158. required=False
  159. )
  160. comments = CommentField(
  161. widget=SmallTextarea,
  162. label='Comments'
  163. )
  164. class Meta:
  165. nullable_fields = [
  166. 'description', 'comments',
  167. ]
  168. class ProviderNetworkFilterForm(BootstrapMixin, CustomFieldFilterForm):
  169. model = ProviderNetwork
  170. field_order = ['q', 'provider_id']
  171. q = forms.CharField(
  172. required=False,
  173. label=_('Search')
  174. )
  175. provider_id = DynamicModelMultipleChoiceField(
  176. queryset=Provider.objects.all(),
  177. required=False,
  178. label=_('Provider')
  179. )
  180. tag = TagFilterField(model)
  181. #
  182. # Circuit types
  183. #
  184. class CircuitTypeForm(BootstrapMixin, CustomFieldModelForm):
  185. slug = SlugField()
  186. class Meta:
  187. model = CircuitType
  188. fields = [
  189. 'name', 'slug', 'description',
  190. ]
  191. class CircuitTypeBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
  192. pk = forms.ModelMultipleChoiceField(
  193. queryset=CircuitType.objects.all(),
  194. widget=forms.MultipleHiddenInput
  195. )
  196. description = forms.CharField(
  197. max_length=200,
  198. required=False
  199. )
  200. class Meta:
  201. nullable_fields = ['description']
  202. class CircuitTypeCSVForm(CustomFieldModelCSVForm):
  203. slug = SlugField()
  204. class Meta:
  205. model = CircuitType
  206. fields = CircuitType.csv_headers
  207. help_texts = {
  208. 'name': 'Name of circuit type',
  209. }
  210. #
  211. # Circuits
  212. #
  213. class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
  214. provider = DynamicModelChoiceField(
  215. queryset=Provider.objects.all()
  216. )
  217. type = DynamicModelChoiceField(
  218. queryset=CircuitType.objects.all()
  219. )
  220. comments = CommentField()
  221. tags = DynamicModelMultipleChoiceField(
  222. queryset=Tag.objects.all(),
  223. required=False
  224. )
  225. class Meta:
  226. model = Circuit
  227. fields = [
  228. 'cid', 'type', 'provider', 'status', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant',
  229. 'comments', 'tags',
  230. ]
  231. fieldsets = (
  232. ('Circuit', ('provider', 'cid', 'type', 'status', 'install_date', 'commit_rate', 'description', 'tags')),
  233. ('Tenancy', ('tenant_group', 'tenant')),
  234. )
  235. help_texts = {
  236. 'cid': "Unique circuit ID",
  237. 'commit_rate': "Committed rate",
  238. }
  239. widgets = {
  240. 'status': StaticSelect2(),
  241. 'install_date': DatePicker(),
  242. 'commit_rate': SelectSpeedWidget(),
  243. }
  244. class CircuitCSVForm(CustomFieldModelCSVForm):
  245. provider = CSVModelChoiceField(
  246. queryset=Provider.objects.all(),
  247. to_field_name='name',
  248. help_text='Assigned provider'
  249. )
  250. type = CSVModelChoiceField(
  251. queryset=CircuitType.objects.all(),
  252. to_field_name='name',
  253. help_text='Type of circuit'
  254. )
  255. status = CSVChoiceField(
  256. choices=CircuitStatusChoices,
  257. required=False,
  258. help_text='Operational status'
  259. )
  260. tenant = CSVModelChoiceField(
  261. queryset=Tenant.objects.all(),
  262. required=False,
  263. to_field_name='name',
  264. help_text='Assigned tenant'
  265. )
  266. class Meta:
  267. model = Circuit
  268. fields = [
  269. 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
  270. ]
  271. class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm):
  272. pk = forms.ModelMultipleChoiceField(
  273. queryset=Circuit.objects.all(),
  274. widget=forms.MultipleHiddenInput
  275. )
  276. type = DynamicModelChoiceField(
  277. queryset=CircuitType.objects.all(),
  278. required=False
  279. )
  280. provider = DynamicModelChoiceField(
  281. queryset=Provider.objects.all(),
  282. required=False
  283. )
  284. status = forms.ChoiceField(
  285. choices=add_blank_choice(CircuitStatusChoices),
  286. required=False,
  287. initial='',
  288. widget=StaticSelect2()
  289. )
  290. tenant = DynamicModelChoiceField(
  291. queryset=Tenant.objects.all(),
  292. required=False
  293. )
  294. commit_rate = forms.IntegerField(
  295. required=False,
  296. label='Commit rate (Kbps)'
  297. )
  298. description = forms.CharField(
  299. max_length=100,
  300. required=False
  301. )
  302. comments = CommentField(
  303. widget=SmallTextarea,
  304. label='Comments'
  305. )
  306. class Meta:
  307. nullable_fields = [
  308. 'tenant', 'commit_rate', 'description', 'comments',
  309. ]
  310. class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
  311. model = Circuit
  312. field_order = [
  313. 'q', 'type_id', 'provider_id', 'provider_network_id', 'status', 'region_id', 'site_id', 'tenant_group_id', 'tenant_id',
  314. 'commit_rate',
  315. ]
  316. q = forms.CharField(
  317. required=False,
  318. label=_('Search')
  319. )
  320. type_id = DynamicModelMultipleChoiceField(
  321. queryset=CircuitType.objects.all(),
  322. required=False,
  323. label=_('Type')
  324. )
  325. provider_id = DynamicModelMultipleChoiceField(
  326. queryset=Provider.objects.all(),
  327. required=False,
  328. label=_('Provider')
  329. )
  330. provider_network_id = DynamicModelMultipleChoiceField(
  331. queryset=ProviderNetwork.objects.all(),
  332. required=False,
  333. query_params={
  334. 'provider_id': '$provider_id'
  335. },
  336. label=_('Provider network')
  337. )
  338. status = forms.MultipleChoiceField(
  339. choices=CircuitStatusChoices,
  340. required=False,
  341. widget=StaticSelect2Multiple()
  342. )
  343. region_id = DynamicModelMultipleChoiceField(
  344. queryset=Region.objects.all(),
  345. required=False,
  346. label=_('Region')
  347. )
  348. site_id = DynamicModelMultipleChoiceField(
  349. queryset=Site.objects.all(),
  350. required=False,
  351. query_params={
  352. 'region_id': '$region_id'
  353. },
  354. label=_('Site')
  355. )
  356. commit_rate = forms.IntegerField(
  357. required=False,
  358. min_value=0,
  359. label=_('Commit rate (Kbps)')
  360. )
  361. tag = TagFilterField(model)
  362. #
  363. # Circuit terminations
  364. #
  365. class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
  366. region = DynamicModelChoiceField(
  367. queryset=Region.objects.all(),
  368. required=False,
  369. initial_params={
  370. 'sites': '$site'
  371. }
  372. )
  373. site_group = DynamicModelChoiceField(
  374. queryset=SiteGroup.objects.all(),
  375. required=False,
  376. initial_params={
  377. 'sites': '$site'
  378. }
  379. )
  380. site = DynamicModelChoiceField(
  381. queryset=Site.objects.all(),
  382. query_params={
  383. 'region_id': '$region',
  384. 'group_id': '$site_group',
  385. },
  386. required=False
  387. )
  388. provider_network = DynamicModelChoiceField(
  389. queryset=ProviderNetwork.objects.all(),
  390. required=False
  391. )
  392. class Meta:
  393. model = CircuitTermination
  394. fields = [
  395. 'term_side', 'region', 'site_group', 'site', 'provider_network', 'mark_connected', 'port_speed',
  396. 'upstream_speed', 'xconnect_id', 'pp_info', 'description',
  397. ]
  398. help_texts = {
  399. 'port_speed': "Physical circuit speed",
  400. 'xconnect_id': "ID of the local cross-connect",
  401. 'pp_info': "Patch panel ID and port number(s)"
  402. }
  403. widgets = {
  404. 'term_side': forms.HiddenInput(),
  405. 'port_speed': SelectSpeedWidget(),
  406. 'upstream_speed': SelectSpeedWidget(),
  407. }
  408. def __init__(self, *args, **kwargs):
  409. super().__init__(*args, **kwargs)
  410. self.fields['provider_network'].widget.add_query_param('provider_id', self.instance.circuit.provider_id)