forms.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. from django import forms
  2. from taggit.forms import TagField
  3. from dcim.models import Site
  4. from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
  5. from tenancy.forms import TenancyForm
  6. from tenancy.forms import TenancyFilterForm
  7. from tenancy.models import Tenant
  8. from utilities.forms import (
  9. APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField,
  10. FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
  11. )
  12. from .constants import CIRCUIT_STATUS_CHOICES
  13. from .models import Circuit, CircuitTermination, CircuitType, Provider
  14. #
  15. # Providers
  16. #
  17. class ProviderForm(BootstrapMixin, CustomFieldForm):
  18. slug = SlugField()
  19. comments = CommentField()
  20. tags = TagField(
  21. required=False
  22. )
  23. class Meta:
  24. model = Provider
  25. fields = [
  26. 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags',
  27. ]
  28. widgets = {
  29. 'noc_contact': SmallTextarea(
  30. attrs={'rows': 5}
  31. ),
  32. 'admin_contact': SmallTextarea(
  33. attrs={'rows': 5}
  34. ),
  35. }
  36. help_texts = {
  37. 'name': "Full name of the provider",
  38. 'asn': "BGP autonomous system number (if applicable)",
  39. 'portal_url': "URL of the provider's customer support portal",
  40. 'noc_contact': "NOC email address and phone number",
  41. 'admin_contact': "Administrative contact email address and phone number",
  42. }
  43. class ProviderCSVForm(forms.ModelForm):
  44. slug = SlugField()
  45. class Meta:
  46. model = Provider
  47. fields = Provider.csv_headers
  48. help_texts = {
  49. 'name': 'Provider name',
  50. 'asn': '32-bit autonomous system number',
  51. 'portal_url': 'Portal URL',
  52. 'comments': 'Free-form comments',
  53. }
  54. class ProviderBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm):
  55. pk = forms.ModelMultipleChoiceField(
  56. queryset=Provider.objects.all(),
  57. widget=forms.MultipleHiddenInput
  58. )
  59. asn = forms.IntegerField(
  60. required=False,
  61. label='ASN'
  62. )
  63. account = forms.CharField(
  64. max_length=30,
  65. required=False,
  66. label='Account number'
  67. )
  68. portal_url = forms.URLField(
  69. required=False,
  70. label='Portal'
  71. )
  72. noc_contact = forms.CharField(
  73. required=False,
  74. widget=SmallTextarea,
  75. label='NOC contact'
  76. )
  77. admin_contact = forms.CharField(
  78. required=False,
  79. widget=SmallTextarea,
  80. label='Admin contact'
  81. )
  82. comments = CommentField(
  83. widget=SmallTextarea()
  84. )
  85. class Meta:
  86. nullable_fields = [
  87. 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
  88. ]
  89. class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
  90. model = Provider
  91. q = forms.CharField(
  92. required=False,
  93. label='Search'
  94. )
  95. site = FilterChoiceField(
  96. queryset=Site.objects.all(),
  97. to_field_name='slug',
  98. widget=APISelectMultiple(
  99. api_url="/api/dcim/sites/",
  100. value_field="slug",
  101. )
  102. )
  103. asn = forms.IntegerField(
  104. required=False,
  105. label='ASN'
  106. )
  107. #
  108. # Circuit types
  109. #
  110. class CircuitTypeForm(BootstrapMixin, forms.ModelForm):
  111. slug = SlugField()
  112. class Meta:
  113. model = CircuitType
  114. fields = [
  115. 'name', 'slug',
  116. ]
  117. class CircuitTypeCSVForm(forms.ModelForm):
  118. slug = SlugField()
  119. class Meta:
  120. model = CircuitType
  121. fields = CircuitType.csv_headers
  122. help_texts = {
  123. 'name': 'Name of circuit type',
  124. }
  125. #
  126. # Circuits
  127. #
  128. class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldForm):
  129. comments = CommentField()
  130. tags = TagField(
  131. required=False
  132. )
  133. class Meta:
  134. model = Circuit
  135. fields = [
  136. 'cid', 'type', 'provider', 'status', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant',
  137. 'comments', 'tags',
  138. ]
  139. help_texts = {
  140. 'cid': "Unique circuit ID",
  141. 'install_date': "Format: YYYY-MM-DD",
  142. 'commit_rate': "Committed rate",
  143. }
  144. widgets = {
  145. 'provider': APISelect(
  146. api_url="/api/circuits/providers/"
  147. ),
  148. 'type': APISelect(
  149. api_url="/api/circuits/circuit-types/"
  150. ),
  151. 'status': StaticSelect2(),
  152. }
  153. class CircuitCSVForm(forms.ModelForm):
  154. provider = forms.ModelChoiceField(
  155. queryset=Provider.objects.all(),
  156. to_field_name='name',
  157. help_text='Name of parent provider',
  158. error_messages={
  159. 'invalid_choice': 'Provider not found.'
  160. }
  161. )
  162. type = forms.ModelChoiceField(
  163. queryset=CircuitType.objects.all(),
  164. to_field_name='name',
  165. help_text='Type of circuit',
  166. error_messages={
  167. 'invalid_choice': 'Invalid circuit type.'
  168. }
  169. )
  170. status = CSVChoiceField(
  171. choices=CIRCUIT_STATUS_CHOICES,
  172. required=False,
  173. help_text='Operational status'
  174. )
  175. tenant = forms.ModelChoiceField(
  176. queryset=Tenant.objects.all(),
  177. required=False,
  178. to_field_name='name',
  179. help_text='Name of assigned tenant',
  180. error_messages={
  181. 'invalid_choice': 'Tenant not found.'
  182. }
  183. )
  184. class Meta:
  185. model = Circuit
  186. fields = [
  187. 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
  188. ]
  189. class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm):
  190. pk = forms.ModelMultipleChoiceField(
  191. queryset=Circuit.objects.all(),
  192. widget=forms.MultipleHiddenInput
  193. )
  194. type = forms.ModelChoiceField(
  195. queryset=CircuitType.objects.all(),
  196. required=False,
  197. widget=APISelect(
  198. api_url="/api/circuits/circuit-types/"
  199. )
  200. )
  201. provider = forms.ModelChoiceField(
  202. queryset=Provider.objects.all(),
  203. required=False,
  204. widget=APISelect(
  205. api_url="/api/circuits/providers/"
  206. )
  207. )
  208. status = forms.ChoiceField(
  209. choices=add_blank_choice(CIRCUIT_STATUS_CHOICES),
  210. required=False,
  211. initial='',
  212. widget=StaticSelect2()
  213. )
  214. tenant = forms.ModelChoiceField(
  215. queryset=Tenant.objects.all(),
  216. required=False,
  217. widget=APISelect(
  218. api_url="/api/tenancy/tenants/"
  219. )
  220. )
  221. commit_rate = forms.IntegerField(
  222. required=False,
  223. label='Commit rate (Kbps)'
  224. )
  225. description = forms.CharField(
  226. max_length=100,
  227. required=False
  228. )
  229. comments = CommentField(
  230. widget=SmallTextarea
  231. )
  232. class Meta:
  233. nullable_fields = [
  234. 'tenant', 'commit_rate', 'description', 'comments',
  235. ]
  236. class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
  237. model = Circuit
  238. field_order = ['q', 'type', 'provider', 'status', 'site', 'tenant_group', 'tenant', 'commit_rate']
  239. q = forms.CharField(
  240. required=False,
  241. label='Search'
  242. )
  243. type = FilterChoiceField(
  244. queryset=CircuitType.objects.all(),
  245. to_field_name='slug',
  246. widget=APISelectMultiple(
  247. api_url="/api/circuits/circuit-types/",
  248. value_field="slug",
  249. )
  250. )
  251. provider = FilterChoiceField(
  252. queryset=Provider.objects.all(),
  253. to_field_name='slug',
  254. widget=APISelectMultiple(
  255. api_url="/api/circuits/providers/",
  256. value_field="slug",
  257. )
  258. )
  259. status = forms.MultipleChoiceField(
  260. choices=CIRCUIT_STATUS_CHOICES,
  261. required=False,
  262. widget=StaticSelect2Multiple()
  263. )
  264. site = FilterChoiceField(
  265. queryset=Site.objects.all(),
  266. to_field_name='slug',
  267. widget=APISelectMultiple(
  268. api_url="/api/dcim/sites/",
  269. value_field="slug",
  270. )
  271. )
  272. commit_rate = forms.IntegerField(
  273. required=False,
  274. min_value=0,
  275. label='Commit rate (Kbps)'
  276. )
  277. #
  278. # Circuit terminations
  279. #
  280. class CircuitTerminationForm(BootstrapMixin, forms.ModelForm):
  281. class Meta:
  282. model = CircuitTermination
  283. fields = [
  284. 'term_side', 'site', 'port_speed', 'upstream_speed', 'xconnect_id', 'pp_info', 'description',
  285. ]
  286. help_texts = {
  287. 'port_speed': "Physical circuit speed",
  288. 'xconnect_id': "ID of the local cross-connect",
  289. 'pp_info': "Patch panel ID and port number(s)"
  290. }
  291. widgets = {
  292. 'term_side': forms.HiddenInput(),
  293. 'site': APISelect(
  294. api_url="/api/dcim/sites/"
  295. )
  296. }