model_forms.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. import json
  2. from django import forms
  3. from django.contrib.contenttypes.models import ContentType
  4. from django.utils.translation import gettext as _
  5. from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
  6. from extras.choices import *
  7. from extras.models import *
  8. from extras.utils import FeatureQuery
  9. from netbox.forms import NetBoxModelForm
  10. from tenancy.models import Tenant, TenantGroup
  11. from utilities.forms import (
  12. add_blank_choice, BootstrapMixin, CommentField, ContentTypeChoiceField, ContentTypeMultipleChoiceField,
  13. DynamicModelMultipleChoiceField, JSONField, SlugField, StaticSelect,
  14. )
  15. from virtualization.models import Cluster, ClusterGroup, ClusterType
  16. __all__ = (
  17. 'ConfigContextForm',
  18. 'CustomFieldForm',
  19. 'CustomLinkForm',
  20. 'ExportTemplateForm',
  21. 'ImageAttachmentForm',
  22. 'JournalEntryForm',
  23. 'SavedFilterForm',
  24. 'TagForm',
  25. 'WebhookForm',
  26. )
  27. class CustomFieldForm(BootstrapMixin, forms.ModelForm):
  28. content_types = ContentTypeMultipleChoiceField(
  29. queryset=ContentType.objects.all(),
  30. limit_choices_to=FeatureQuery('custom_fields'),
  31. )
  32. object_type = ContentTypeChoiceField(
  33. queryset=ContentType.objects.all(),
  34. # TODO: Come up with a canonical way to register suitable models
  35. limit_choices_to=FeatureQuery('webhooks'),
  36. required=False,
  37. help_text=_("Type of the related object (for object/multi-object fields only)")
  38. )
  39. fieldsets = (
  40. ('Custom Field', (
  41. 'content_types', 'name', 'label', 'group_name', 'type', 'object_type', 'required', 'description',
  42. )),
  43. ('Behavior', ('search_weight', 'filter_logic', 'ui_visibility', 'weight')),
  44. ('Values', ('default', 'choices')),
  45. ('Validation', ('validation_minimum', 'validation_maximum', 'validation_regex')),
  46. )
  47. class Meta:
  48. model = CustomField
  49. fields = '__all__'
  50. help_texts = {
  51. 'type': _("The type of data stored in this field. For object/multi-object fields, select the related object "
  52. "type below.")
  53. }
  54. widgets = {
  55. 'type': StaticSelect(),
  56. 'filter_logic': StaticSelect(),
  57. 'ui_visibility': StaticSelect(),
  58. }
  59. class CustomLinkForm(BootstrapMixin, forms.ModelForm):
  60. content_types = ContentTypeMultipleChoiceField(
  61. queryset=ContentType.objects.all(),
  62. limit_choices_to=FeatureQuery('custom_links')
  63. )
  64. fieldsets = (
  65. ('Custom Link', ('name', 'content_types', 'weight', 'group_name', 'button_class', 'enabled', 'new_window')),
  66. ('Templates', ('link_text', 'link_url')),
  67. )
  68. class Meta:
  69. model = CustomLink
  70. fields = '__all__'
  71. widgets = {
  72. 'button_class': StaticSelect(),
  73. 'link_text': forms.Textarea(attrs={'class': 'font-monospace'}),
  74. 'link_url': forms.Textarea(attrs={'class': 'font-monospace'}),
  75. }
  76. help_texts = {
  77. 'link_text': _('Jinja2 template code for the link text. Reference the object as <code>{{ object }}</code>. '
  78. 'Links which render as empty text will not be displayed.'),
  79. 'link_url': _('Jinja2 template code for the link URL. Reference the object as <code>{{ object }}</code>.'),
  80. }
  81. class ExportTemplateForm(BootstrapMixin, forms.ModelForm):
  82. content_types = ContentTypeMultipleChoiceField(
  83. queryset=ContentType.objects.all(),
  84. limit_choices_to=FeatureQuery('export_templates')
  85. )
  86. fieldsets = (
  87. ('Export Template', ('name', 'content_types', 'description')),
  88. ('Template', ('template_code',)),
  89. ('Rendering', ('mime_type', 'file_extension', 'as_attachment')),
  90. )
  91. class Meta:
  92. model = ExportTemplate
  93. fields = '__all__'
  94. widgets = {
  95. 'template_code': forms.Textarea(attrs={'class': 'font-monospace'}),
  96. }
  97. class SavedFilterForm(BootstrapMixin, forms.ModelForm):
  98. slug = SlugField()
  99. content_types = ContentTypeMultipleChoiceField(
  100. queryset=ContentType.objects.all()
  101. )
  102. parameters = JSONField()
  103. fieldsets = (
  104. ('Saved Filter', ('name', 'slug', 'content_types', 'description', 'weight', 'enabled', 'shared')),
  105. ('Parameters', ('parameters',)),
  106. )
  107. class Meta:
  108. model = SavedFilter
  109. exclude = ('user',)
  110. def __init__(self, *args, initial=None, **kwargs):
  111. # Convert any parameters delivered via initial data to JSON data
  112. if initial and 'parameters' in initial:
  113. if type(initial['parameters']) is str:
  114. initial['parameters'] = json.loads(initial['parameters'])
  115. super().__init__(*args, initial=initial, **kwargs)
  116. class WebhookForm(BootstrapMixin, forms.ModelForm):
  117. content_types = ContentTypeMultipleChoiceField(
  118. queryset=ContentType.objects.all(),
  119. limit_choices_to=FeatureQuery('webhooks')
  120. )
  121. fieldsets = (
  122. ('Webhook', ('name', 'content_types', 'enabled')),
  123. ('Events', ('type_create', 'type_update', 'type_delete')),
  124. ('HTTP Request', (
  125. 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'secret',
  126. )),
  127. ('Conditions', ('conditions',)),
  128. ('SSL', ('ssl_verification', 'ca_file_path')),
  129. )
  130. class Meta:
  131. model = Webhook
  132. fields = '__all__'
  133. labels = {
  134. 'type_create': 'Creations',
  135. 'type_update': 'Updates',
  136. 'type_delete': 'Deletions',
  137. }
  138. widgets = {
  139. 'http_method': StaticSelect(),
  140. 'additional_headers': forms.Textarea(attrs={'class': 'font-monospace'}),
  141. 'body_template': forms.Textarea(attrs={'class': 'font-monospace'}),
  142. 'conditions': forms.Textarea(attrs={'class': 'font-monospace'}),
  143. }
  144. class TagForm(BootstrapMixin, forms.ModelForm):
  145. slug = SlugField()
  146. fieldsets = (
  147. ('Tag', ('name', 'slug', 'color', 'description')),
  148. )
  149. class Meta:
  150. model = Tag
  151. fields = [
  152. 'name', 'slug', 'color', 'description'
  153. ]
  154. class ConfigContextForm(BootstrapMixin, forms.ModelForm):
  155. regions = DynamicModelMultipleChoiceField(
  156. queryset=Region.objects.all(),
  157. required=False
  158. )
  159. site_groups = DynamicModelMultipleChoiceField(
  160. queryset=SiteGroup.objects.all(),
  161. required=False
  162. )
  163. sites = DynamicModelMultipleChoiceField(
  164. queryset=Site.objects.all(),
  165. required=False
  166. )
  167. locations = DynamicModelMultipleChoiceField(
  168. queryset=Location.objects.all(),
  169. required=False
  170. )
  171. device_types = DynamicModelMultipleChoiceField(
  172. queryset=DeviceType.objects.all(),
  173. required=False
  174. )
  175. roles = DynamicModelMultipleChoiceField(
  176. queryset=DeviceRole.objects.all(),
  177. required=False
  178. )
  179. platforms = DynamicModelMultipleChoiceField(
  180. queryset=Platform.objects.all(),
  181. required=False
  182. )
  183. cluster_types = DynamicModelMultipleChoiceField(
  184. queryset=ClusterType.objects.all(),
  185. required=False
  186. )
  187. cluster_groups = DynamicModelMultipleChoiceField(
  188. queryset=ClusterGroup.objects.all(),
  189. required=False
  190. )
  191. clusters = DynamicModelMultipleChoiceField(
  192. queryset=Cluster.objects.all(),
  193. required=False
  194. )
  195. tenant_groups = DynamicModelMultipleChoiceField(
  196. queryset=TenantGroup.objects.all(),
  197. required=False
  198. )
  199. tenants = DynamicModelMultipleChoiceField(
  200. queryset=Tenant.objects.all(),
  201. required=False
  202. )
  203. tags = DynamicModelMultipleChoiceField(
  204. queryset=Tag.objects.all(),
  205. required=False
  206. )
  207. data = JSONField()
  208. fieldsets = (
  209. ('Config Context', ('name', 'weight', 'description', 'data', 'is_active')),
  210. ('Assignment', (
  211. 'regions', 'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types',
  212. 'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags',
  213. )),
  214. )
  215. class Meta:
  216. model = ConfigContext
  217. fields = (
  218. 'name', 'weight', 'description', 'data', 'is_active', 'regions', 'site_groups', 'sites', 'locations',
  219. 'roles', 'device_types', 'platforms', 'cluster_types', 'cluster_groups', 'clusters', 'tenant_groups',
  220. 'tenants', 'tags',
  221. )
  222. def __init__(self, *args, initial=None, **kwargs):
  223. # Convert data delivered via initial data to JSON data
  224. if initial and 'data' in initial:
  225. if type(initial['data']) is str:
  226. initial['data'] = json.loads(initial['data'])
  227. super().__init__(*args, initial=initial, **kwargs)
  228. class ImageAttachmentForm(BootstrapMixin, forms.ModelForm):
  229. class Meta:
  230. model = ImageAttachment
  231. fields = [
  232. 'name', 'image',
  233. ]
  234. class JournalEntryForm(NetBoxModelForm):
  235. kind = forms.ChoiceField(
  236. choices=add_blank_choice(JournalEntryKindChoices),
  237. required=False,
  238. widget=StaticSelect()
  239. )
  240. comments = CommentField()
  241. class Meta:
  242. model = JournalEntry
  243. fields = ['assigned_object_type', 'assigned_object_id', 'kind', 'tags', 'comments']
  244. widgets = {
  245. 'assigned_object_type': forms.HiddenInput,
  246. 'assigned_object_id': forms.HiddenInput,
  247. }