forms.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  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, CustomFieldModelBulkEditForm, CustomFieldModelFilterForm, 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. StaticSelect, StaticSelectMultiple, 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 = (
  56. 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
  57. )
  58. class ProviderBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm):
  59. pk = forms.ModelMultipleChoiceField(
  60. queryset=Provider.objects.all(),
  61. widget=forms.MultipleHiddenInput
  62. )
  63. asn = forms.IntegerField(
  64. required=False,
  65. label='ASN'
  66. )
  67. account = forms.CharField(
  68. max_length=30,
  69. required=False,
  70. label='Account number'
  71. )
  72. portal_url = forms.URLField(
  73. required=False,
  74. label='Portal'
  75. )
  76. noc_contact = forms.CharField(
  77. required=False,
  78. widget=SmallTextarea,
  79. label='NOC contact'
  80. )
  81. admin_contact = forms.CharField(
  82. required=False,
  83. widget=SmallTextarea,
  84. label='Admin contact'
  85. )
  86. comments = CommentField(
  87. widget=SmallTextarea,
  88. label='Comments'
  89. )
  90. class Meta:
  91. nullable_fields = [
  92. 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
  93. ]
  94. class ProviderFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
  95. model = Provider
  96. field_groups = [
  97. ['q', 'tag'],
  98. ['region_id', 'site_group_id', 'site_id'],
  99. ['asn'],
  100. ]
  101. q = forms.CharField(
  102. required=False,
  103. widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
  104. label=_('Search')
  105. )
  106. region_id = DynamicModelMultipleChoiceField(
  107. queryset=Region.objects.all(),
  108. required=False,
  109. label=_('Region'),
  110. fetch_trigger='open'
  111. )
  112. site_group_id = DynamicModelMultipleChoiceField(
  113. queryset=SiteGroup.objects.all(),
  114. required=False,
  115. label=_('Site group'),
  116. fetch_trigger='open'
  117. )
  118. site_id = DynamicModelMultipleChoiceField(
  119. queryset=Site.objects.all(),
  120. required=False,
  121. query_params={
  122. 'region_id': '$region_id',
  123. 'site_group_id': '$site_group_id',
  124. },
  125. label=_('Site'),
  126. fetch_trigger='open'
  127. )
  128. asn = forms.IntegerField(
  129. required=False,
  130. label=_('ASN')
  131. )
  132. tag = TagFilterField(model)
  133. #
  134. # Provider networks
  135. #
  136. class ProviderNetworkForm(BootstrapMixin, CustomFieldModelForm):
  137. provider = DynamicModelChoiceField(
  138. queryset=Provider.objects.all()
  139. )
  140. comments = CommentField()
  141. tags = DynamicModelMultipleChoiceField(
  142. queryset=Tag.objects.all(),
  143. required=False
  144. )
  145. class Meta:
  146. model = ProviderNetwork
  147. fields = [
  148. 'provider', 'name', 'description', 'comments', 'tags',
  149. ]
  150. fieldsets = (
  151. ('Provider Network', ('provider', 'name', 'description', 'tags')),
  152. )
  153. class ProviderNetworkCSVForm(CustomFieldModelCSVForm):
  154. provider = CSVModelChoiceField(
  155. queryset=Provider.objects.all(),
  156. to_field_name='name',
  157. help_text='Assigned provider'
  158. )
  159. class Meta:
  160. model = ProviderNetwork
  161. fields = [
  162. 'provider', 'name', 'description', 'comments',
  163. ]
  164. class ProviderNetworkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm):
  165. pk = forms.ModelMultipleChoiceField(
  166. queryset=ProviderNetwork.objects.all(),
  167. widget=forms.MultipleHiddenInput
  168. )
  169. provider = DynamicModelChoiceField(
  170. queryset=Provider.objects.all(),
  171. required=False
  172. )
  173. description = forms.CharField(
  174. max_length=100,
  175. required=False
  176. )
  177. comments = CommentField(
  178. widget=SmallTextarea,
  179. label='Comments'
  180. )
  181. class Meta:
  182. nullable_fields = [
  183. 'description', 'comments',
  184. ]
  185. class ProviderNetworkFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
  186. model = ProviderNetwork
  187. field_groups = (
  188. ('q', 'tag'),
  189. ('provider_id',),
  190. )
  191. q = forms.CharField(
  192. required=False,
  193. widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
  194. label=_('Search')
  195. )
  196. provider_id = DynamicModelMultipleChoiceField(
  197. queryset=Provider.objects.all(),
  198. required=False,
  199. label=_('Provider'),
  200. fetch_trigger='open'
  201. )
  202. tag = TagFilterField(model)
  203. #
  204. # Circuit types
  205. #
  206. class CircuitTypeForm(BootstrapMixin, CustomFieldModelForm):
  207. slug = SlugField()
  208. class Meta:
  209. model = CircuitType
  210. fields = [
  211. 'name', 'slug', 'description',
  212. ]
  213. class CircuitTypeBulkEditForm(BootstrapMixin, CustomFieldModelBulkEditForm):
  214. pk = forms.ModelMultipleChoiceField(
  215. queryset=CircuitType.objects.all(),
  216. widget=forms.MultipleHiddenInput
  217. )
  218. description = forms.CharField(
  219. max_length=200,
  220. required=False
  221. )
  222. class Meta:
  223. nullable_fields = ['description']
  224. class CircuitTypeCSVForm(CustomFieldModelCSVForm):
  225. slug = SlugField()
  226. class Meta:
  227. model = CircuitType
  228. fields = ('name', 'slug', 'description')
  229. help_texts = {
  230. 'name': 'Name of circuit type',
  231. }
  232. class CircuitTypeFilterForm(BootstrapMixin, CustomFieldModelFilterForm):
  233. model = CircuitType
  234. field_groups = [
  235. ['q'],
  236. ]
  237. q = forms.CharField(
  238. required=False,
  239. widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
  240. label=_('Search')
  241. )
  242. #
  243. # Circuits
  244. #
  245. class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
  246. provider = DynamicModelChoiceField(
  247. queryset=Provider.objects.all()
  248. )
  249. type = DynamicModelChoiceField(
  250. queryset=CircuitType.objects.all()
  251. )
  252. comments = CommentField()
  253. tags = DynamicModelMultipleChoiceField(
  254. queryset=Tag.objects.all(),
  255. required=False
  256. )
  257. class Meta:
  258. model = Circuit
  259. fields = [
  260. 'cid', 'type', 'provider', 'status', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant',
  261. 'comments', 'tags',
  262. ]
  263. fieldsets = (
  264. ('Circuit', ('provider', 'cid', 'type', 'status', 'install_date', 'commit_rate', 'description', 'tags')),
  265. ('Tenancy', ('tenant_group', 'tenant')),
  266. )
  267. help_texts = {
  268. 'cid': "Unique circuit ID",
  269. 'commit_rate': "Committed rate",
  270. }
  271. widgets = {
  272. 'status': StaticSelect(),
  273. 'install_date': DatePicker(),
  274. 'commit_rate': SelectSpeedWidget(),
  275. }
  276. class CircuitCSVForm(CustomFieldModelCSVForm):
  277. provider = CSVModelChoiceField(
  278. queryset=Provider.objects.all(),
  279. to_field_name='name',
  280. help_text='Assigned provider'
  281. )
  282. type = CSVModelChoiceField(
  283. queryset=CircuitType.objects.all(),
  284. to_field_name='name',
  285. help_text='Type of circuit'
  286. )
  287. status = CSVChoiceField(
  288. choices=CircuitStatusChoices,
  289. required=False,
  290. help_text='Operational status'
  291. )
  292. tenant = CSVModelChoiceField(
  293. queryset=Tenant.objects.all(),
  294. required=False,
  295. to_field_name='name',
  296. help_text='Assigned tenant'
  297. )
  298. class Meta:
  299. model = Circuit
  300. fields = [
  301. 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
  302. ]
  303. class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm):
  304. pk = forms.ModelMultipleChoiceField(
  305. queryset=Circuit.objects.all(),
  306. widget=forms.MultipleHiddenInput
  307. )
  308. type = DynamicModelChoiceField(
  309. queryset=CircuitType.objects.all(),
  310. required=False
  311. )
  312. provider = DynamicModelChoiceField(
  313. queryset=Provider.objects.all(),
  314. required=False
  315. )
  316. status = forms.ChoiceField(
  317. choices=add_blank_choice(CircuitStatusChoices),
  318. required=False,
  319. initial='',
  320. widget=StaticSelect()
  321. )
  322. tenant = DynamicModelChoiceField(
  323. queryset=Tenant.objects.all(),
  324. required=False
  325. )
  326. commit_rate = forms.IntegerField(
  327. required=False,
  328. label='Commit rate (Kbps)'
  329. )
  330. description = forms.CharField(
  331. max_length=100,
  332. required=False
  333. )
  334. comments = CommentField(
  335. widget=SmallTextarea,
  336. label='Comments'
  337. )
  338. class Meta:
  339. nullable_fields = [
  340. 'tenant', 'commit_rate', 'description', 'comments',
  341. ]
  342. class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldModelFilterForm):
  343. model = Circuit
  344. field_groups = [
  345. ['q', 'tag'],
  346. ['provider_id', 'provider_network_id'],
  347. ['type_id', 'status', 'commit_rate'],
  348. ['region_id', 'site_group_id', 'site_id'],
  349. ['tenant_group_id', 'tenant_id'],
  350. ]
  351. q = forms.CharField(
  352. required=False,
  353. widget=forms.TextInput(attrs={'placeholder': _('All Fields')}),
  354. label=_('Search')
  355. )
  356. type_id = DynamicModelMultipleChoiceField(
  357. queryset=CircuitType.objects.all(),
  358. required=False,
  359. label=_('Type'),
  360. fetch_trigger='open'
  361. )
  362. provider_id = DynamicModelMultipleChoiceField(
  363. queryset=Provider.objects.all(),
  364. required=False,
  365. label=_('Provider'),
  366. fetch_trigger='open'
  367. )
  368. provider_network_id = DynamicModelMultipleChoiceField(
  369. queryset=ProviderNetwork.objects.all(),
  370. required=False,
  371. query_params={
  372. 'provider_id': '$provider_id'
  373. },
  374. label=_('Provider network'),
  375. fetch_trigger='open'
  376. )
  377. status = forms.MultipleChoiceField(
  378. choices=CircuitStatusChoices,
  379. required=False,
  380. widget=StaticSelectMultiple()
  381. )
  382. region_id = DynamicModelMultipleChoiceField(
  383. queryset=Region.objects.all(),
  384. required=False,
  385. label=_('Region'),
  386. fetch_trigger='open'
  387. )
  388. site_group_id = DynamicModelMultipleChoiceField(
  389. queryset=SiteGroup.objects.all(),
  390. required=False,
  391. label=_('Site group'),
  392. fetch_trigger='open'
  393. )
  394. site_id = DynamicModelMultipleChoiceField(
  395. queryset=Site.objects.all(),
  396. required=False,
  397. query_params={
  398. 'region_id': '$region_id',
  399. 'site_group_id': '$site_group_id',
  400. },
  401. label=_('Site'),
  402. fetch_trigger='open'
  403. )
  404. commit_rate = forms.IntegerField(
  405. required=False,
  406. min_value=0,
  407. label=_('Commit rate (Kbps)')
  408. )
  409. tag = TagFilterField(model)
  410. #
  411. # Circuit terminations
  412. #
  413. class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
  414. region = DynamicModelChoiceField(
  415. queryset=Region.objects.all(),
  416. required=False,
  417. initial_params={
  418. 'sites': '$site'
  419. }
  420. )
  421. site_group = DynamicModelChoiceField(
  422. queryset=SiteGroup.objects.all(),
  423. required=False,
  424. initial_params={
  425. 'sites': '$site'
  426. }
  427. )
  428. site = DynamicModelChoiceField(
  429. queryset=Site.objects.all(),
  430. query_params={
  431. 'region_id': '$region',
  432. 'group_id': '$site_group',
  433. },
  434. required=False
  435. )
  436. provider_network = DynamicModelChoiceField(
  437. queryset=ProviderNetwork.objects.all(),
  438. required=False
  439. )
  440. class Meta:
  441. model = CircuitTermination
  442. fields = [
  443. 'term_side', 'region', 'site_group', 'site', 'provider_network', 'mark_connected', 'port_speed',
  444. 'upstream_speed', 'xconnect_id', 'pp_info', 'description',
  445. ]
  446. help_texts = {
  447. 'port_speed': "Physical circuit speed",
  448. 'xconnect_id': "ID of the local cross-connect",
  449. 'pp_info': "Patch panel ID and port number(s)"
  450. }
  451. widgets = {
  452. 'term_side': forms.HiddenInput(),
  453. 'port_speed': SelectSpeedWidget(),
  454. 'upstream_speed': SelectSpeedWidget(),
  455. }
  456. def __init__(self, *args, **kwargs):
  457. super().__init__(*args, **kwargs)
  458. self.fields['provider_network'].widget.add_query_param('provider_id', self.instance.circuit.provider_id)