object_import.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. from django import forms
  2. from django.db.models import Q
  3. from django.utils.translation import gettext_lazy as _
  4. from dcim.choices import InterfacePoEModeChoices, InterfacePoETypeChoices, InterfaceTypeChoices, PortTypeChoices
  5. from dcim.models import *
  6. from wireless.choices import WirelessRoleChoices
  7. __all__ = (
  8. 'ConsolePortTemplateImportForm',
  9. 'ConsoleServerPortTemplateImportForm',
  10. 'CoolingIntakeTemplateImportForm',
  11. 'CoolingOutflowTemplateImportForm',
  12. 'DeviceBayTemplateImportForm',
  13. 'FrontPortTemplateImportForm',
  14. 'InterfaceTemplateImportForm',
  15. 'InventoryItemTemplateImportForm',
  16. 'ModuleBayTemplateImportForm',
  17. 'PortTemplateMappingImportForm',
  18. 'PowerOutletTemplateImportForm',
  19. 'PowerPortTemplateImportForm',
  20. 'RearPortTemplateImportForm',
  21. )
  22. #
  23. # Component template import forms
  24. #
  25. class ConsolePortTemplateImportForm(forms.ModelForm):
  26. class Meta:
  27. model = ConsolePortTemplate
  28. fields = [
  29. 'device_type', 'module_type', 'name', 'label', 'type', 'description',
  30. ]
  31. class ConsoleServerPortTemplateImportForm(forms.ModelForm):
  32. class Meta:
  33. model = ConsoleServerPortTemplate
  34. fields = [
  35. 'device_type', 'module_type', 'name', 'label', 'type', 'description',
  36. ]
  37. class PowerPortTemplateImportForm(forms.ModelForm):
  38. class Meta:
  39. model = PowerPortTemplate
  40. fields = [
  41. 'device_type', 'module_type', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description',
  42. ]
  43. class PowerOutletTemplateImportForm(forms.ModelForm):
  44. power_port = forms.ModelChoiceField(
  45. label=_('Power port'),
  46. queryset=PowerPortTemplate.objects.all(),
  47. to_field_name='name',
  48. required=False
  49. )
  50. class Meta:
  51. model = PowerOutletTemplate
  52. fields = [
  53. 'device_type', 'module_type', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description',
  54. ]
  55. def clean_device_type(self):
  56. if device_type := self.cleaned_data['device_type']:
  57. power_port = self.fields['power_port']
  58. power_port.queryset = power_port.queryset.filter(device_type=device_type)
  59. return device_type
  60. def clean_module_type(self):
  61. if module_type := self.cleaned_data['module_type']:
  62. power_port = self.fields['power_port']
  63. power_port.queryset = power_port.queryset.filter(module_type=module_type)
  64. return module_type
  65. class CoolingIntakeTemplateImportForm(forms.ModelForm):
  66. class Meta:
  67. model = CoolingIntakeTemplate
  68. fields = [
  69. 'device_type', 'module_type', 'name', 'label', 'type', 'diameter', 'diameter_unit',
  70. 'max_flow', 'max_flow_unit', 'description',
  71. ]
  72. class CoolingOutflowTemplateImportForm(forms.ModelForm):
  73. cooling_intake = forms.ModelChoiceField(
  74. label=_('Cooling intake'),
  75. queryset=CoolingIntakeTemplate.objects.all(),
  76. to_field_name='name',
  77. required=False
  78. )
  79. class Meta:
  80. model = CoolingOutflowTemplate
  81. fields = [
  82. 'device_type', 'module_type', 'name', 'label', 'type', 'diameter', 'diameter_unit',
  83. 'cooling_intake', 'description',
  84. ]
  85. def clean_device_type(self):
  86. if device_type := self.cleaned_data['device_type']:
  87. cooling_intake = self.fields['cooling_intake']
  88. cooling_intake.queryset = cooling_intake.queryset.filter(device_type=device_type)
  89. return device_type
  90. def clean_module_type(self):
  91. if module_type := self.cleaned_data['module_type']:
  92. cooling_intake = self.fields['cooling_intake']
  93. cooling_intake.queryset = cooling_intake.queryset.filter(module_type=module_type)
  94. return module_type
  95. class InterfaceTemplateImportForm(forms.ModelForm):
  96. type = forms.ChoiceField(
  97. label=_('Type'),
  98. choices=InterfaceTypeChoices.CHOICES
  99. )
  100. poe_mode = forms.ChoiceField(
  101. choices=InterfacePoEModeChoices,
  102. required=False,
  103. label=_('PoE mode')
  104. )
  105. poe_type = forms.ChoiceField(
  106. choices=InterfacePoETypeChoices,
  107. required=False,
  108. label=_('PoE type')
  109. )
  110. rf_role = forms.ChoiceField(
  111. choices=WirelessRoleChoices,
  112. required=False,
  113. label=_('Wireless role')
  114. )
  115. class Meta:
  116. model = InterfaceTemplate
  117. fields = [
  118. 'device_type', 'module_type', 'name', 'label', 'type', 'channels', 'channel_id', 'enabled', 'mgmt_only',
  119. 'description', 'poe_mode', 'poe_type', 'rf_role'
  120. ]
  121. class FrontPortTemplateImportForm(forms.ModelForm):
  122. type = forms.ChoiceField(
  123. label=_('Type'),
  124. choices=PortTypeChoices.CHOICES
  125. )
  126. class Meta:
  127. model = FrontPortTemplate
  128. fields = [
  129. 'device_type', 'module_type', 'name', 'type', 'color', 'positions', 'label', 'description',
  130. ]
  131. class RearPortTemplateImportForm(forms.ModelForm):
  132. type = forms.ChoiceField(
  133. label=_('Type'),
  134. choices=PortTypeChoices.CHOICES
  135. )
  136. class Meta:
  137. model = RearPortTemplate
  138. fields = [
  139. 'device_type', 'module_type', 'name', 'type', 'color', 'positions', 'label', 'description',
  140. ]
  141. class PortTemplateMappingImportForm(forms.ModelForm):
  142. front_port = forms.ModelChoiceField(
  143. label=_('Front port'),
  144. queryset=FrontPortTemplate.objects.all(),
  145. to_field_name='name',
  146. )
  147. rear_port = forms.ModelChoiceField(
  148. label=_('Rear port'),
  149. queryset=RearPortTemplate.objects.all(),
  150. to_field_name='name',
  151. )
  152. class Meta:
  153. model = PortTemplateMapping
  154. fields = [
  155. 'device_type', 'module_type', 'front_port', 'front_port_position', 'rear_port', 'rear_port_position',
  156. ]
  157. def clean_device_type(self):
  158. if device_type := self.cleaned_data['device_type']:
  159. front_port = self.fields['front_port']
  160. rear_port = self.fields['rear_port']
  161. front_port.queryset = front_port.queryset.filter(device_type=device_type)
  162. rear_port.queryset = rear_port.queryset.filter(device_type=device_type)
  163. return device_type
  164. def clean_module_type(self):
  165. if module_type := self.cleaned_data['module_type']:
  166. front_port = self.fields['front_port']
  167. rear_port = self.fields['rear_port']
  168. front_port.queryset = front_port.queryset.filter(module_type=module_type)
  169. rear_port.queryset = rear_port.queryset.filter(module_type=module_type)
  170. return module_type
  171. class ModuleBayTemplateImportForm(forms.ModelForm):
  172. module_bay_types = forms.ModelMultipleChoiceField(
  173. label=_('Module bay types'),
  174. queryset=ModuleBayType.objects.all(),
  175. to_field_name='name',
  176. required=False,
  177. )
  178. class Meta:
  179. model = ModuleBayTemplate
  180. # module_bay_types must stay last: clean_device_type/clean_module_type narrow its queryset by
  181. # manufacturer before it is itself cleaned, and Django cleans fields in this order.
  182. fields = [
  183. 'device_type', 'module_type', 'name', 'label', 'position', 'enabled', 'description',
  184. 'module_bay_types',
  185. ]
  186. def clean_enabled(self):
  187. # A dict-bound BooleanField resolves a missing key to False, not the model's own
  188. # default=True -- match ModuleBayImportForm's equivalent CSV-import behavior.
  189. if 'enabled' not in self.data:
  190. return True
  191. return self.cleaned_data['enabled']
  192. def _scope_module_bay_types(self, manufacturer):
  193. module_bay_types = self.fields['module_bay_types']
  194. module_bay_types.queryset = module_bay_types.queryset.filter(
  195. Q(manufacturer__isnull=True) | Q(manufacturer=manufacturer)
  196. )
  197. def clean_device_type(self):
  198. if device_type := self.cleaned_data['device_type']:
  199. self._scope_module_bay_types(device_type.manufacturer)
  200. return device_type
  201. def clean_module_type(self):
  202. if module_type := self.cleaned_data['module_type']:
  203. self._scope_module_bay_types(module_type.manufacturer)
  204. return module_type
  205. def clean_module_bay_types(self):
  206. """
  207. Collapse to one match per name, preferring a manufacturer-specific match over a global
  208. one. ModuleBayType's unique constraint is on (manufacturer, name), not name alone, so a
  209. name can legitimately collide between a global type and one scoped to this template's
  210. own manufacturer (narrowed by clean_device_type/clean_module_type above); the field's
  211. default name-based lookup resolves both matches into cleaned_data rather than picking
  212. one, since it has no way to know which is meant.
  213. """
  214. module_bay_types = self.cleaned_data['module_bay_types']
  215. by_name = {}
  216. for module_bay_type in module_bay_types:
  217. existing = by_name.get(module_bay_type.name)
  218. if existing is None or module_bay_type.manufacturer_id is not None:
  219. by_name[module_bay_type.name] = module_bay_type
  220. return list(by_name.values())
  221. class DeviceBayTemplateImportForm(forms.ModelForm):
  222. class Meta:
  223. model = DeviceBayTemplate
  224. fields = [
  225. 'device_type', 'name', 'label', 'description',
  226. ]
  227. class InventoryItemTemplateImportForm(forms.ModelForm):
  228. parent = forms.ModelChoiceField(
  229. label=_('Parent'),
  230. queryset=InventoryItemTemplate.objects.all(),
  231. required=False
  232. )
  233. role = forms.ModelChoiceField(
  234. label=_('Role'),
  235. queryset=InventoryItemRole.objects.all(),
  236. to_field_name='name',
  237. required=False
  238. )
  239. manufacturer = forms.ModelChoiceField(
  240. label=_('Manufacturer'),
  241. queryset=Manufacturer.objects.all(),
  242. to_field_name='name',
  243. required=False
  244. )
  245. class Meta:
  246. model = InventoryItemTemplate
  247. fields = [
  248. 'device_type', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'description',
  249. ]
  250. def clean_device_type(self):
  251. if device_type := self.cleaned_data['device_type']:
  252. parent = self.fields['parent']
  253. parent.queryset = parent.queryset.filter(device_type=device_type)
  254. return device_type
  255. def clean_module_type(self):
  256. if module_type := self.cleaned_data['module_type']:
  257. parent = self.fields['parent']
  258. parent.queryset = parent.queryset.filter(module_type=module_type)
  259. return module_type