2016-08-23 16:45:26 -04:00
|
|
|
from collections import OrderedDict
|
|
|
|
|
2016-08-12 17:20:01 -04:00
|
|
|
from django import forms
|
2018-06-20 13:52:54 -04:00
|
|
|
from django.contrib.auth.models import User
|
2016-08-12 17:20:01 -04:00
|
|
|
from django.contrib.contenttypes.models import ContentType
|
2018-06-29 16:01:28 -04:00
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
2018-07-10 10:00:21 -04:00
|
|
|
from taggit.forms import TagField
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2018-08-09 12:22:34 -04:00
|
|
|
from dcim.models import DeviceRole, Platform, Region, Site
|
|
|
|
from tenancy.models import Tenant, TenantGroup
|
|
|
|
from utilities.forms import (
|
2019-08-28 11:56:00 -04:00
|
|
|
add_blank_choice, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect, ColorSelect,
|
2019-12-28 22:55:00 +00:00
|
|
|
CommentField, ContentTypeSelect, DatePicker, DateTimePicker, FilterChoiceField, LaxURLField, JSONField,
|
|
|
|
SlugField, StaticSelect2, BOOLEAN_WITH_BLANK_CHOICES,
|
2018-08-09 12:22:34 -04:00
|
|
|
)
|
2019-10-04 12:08:48 -04:00
|
|
|
from .constants import *
|
2019-02-20 03:52:47 -05:00
|
|
|
from .models import ConfigContext, CustomField, CustomFieldValue, ImageAttachment, ObjectChange, Tag
|
2016-08-12 17:20:01 -04:00
|
|
|
|
|
|
|
|
2018-05-22 12:22:46 -04:00
|
|
|
#
|
|
|
|
# Custom fields
|
|
|
|
#
|
|
|
|
|
2016-08-23 16:45:26 -04:00
|
|
|
def get_custom_fields_for_model(content_type, filterable_only=False, bulk_edit=False):
|
2016-08-17 13:40:22 -04:00
|
|
|
"""
|
|
|
|
Retrieve all CustomFields applicable to the given ContentType
|
|
|
|
"""
|
2016-08-23 16:45:26 -04:00
|
|
|
field_dict = OrderedDict()
|
2018-02-21 15:40:11 -05:00
|
|
|
custom_fields = CustomField.objects.filter(obj_type=content_type)
|
2016-08-23 16:45:26 -04:00
|
|
|
if filterable_only:
|
2018-02-21 15:40:11 -05:00
|
|
|
custom_fields = custom_fields.exclude(filter_logic=CF_FILTER_DISABLED)
|
2016-08-16 14:57:04 -04:00
|
|
|
|
|
|
|
for cf in custom_fields:
|
|
|
|
field_name = 'cf_{}'.format(str(cf.name))
|
2018-02-02 21:30:16 -05:00
|
|
|
initial = cf.default if not bulk_edit else None
|
2016-08-16 14:57:04 -04:00
|
|
|
|
|
|
|
# Integer
|
|
|
|
if cf.type == CF_TYPE_INTEGER:
|
2018-02-02 21:30:16 -05:00
|
|
|
field = forms.IntegerField(required=cf.required, initial=initial)
|
2016-08-16 14:57:04 -04:00
|
|
|
|
|
|
|
# Boolean
|
|
|
|
elif cf.type == CF_TYPE_BOOLEAN:
|
|
|
|
choices = (
|
|
|
|
(None, '---------'),
|
2016-09-28 09:58:59 -04:00
|
|
|
(1, 'True'),
|
|
|
|
(0, 'False'),
|
2016-08-16 14:57:04 -04:00
|
|
|
)
|
2018-02-21 15:40:11 -05:00
|
|
|
if initial is not None and initial.lower() in ['true', 'yes', '1']:
|
2017-01-04 09:47:26 -05:00
|
|
|
initial = 1
|
2018-02-21 15:40:11 -05:00
|
|
|
elif initial is not None and initial.lower() in ['false', 'no', '0']:
|
2017-01-04 09:47:26 -05:00
|
|
|
initial = 0
|
2016-08-18 11:44:40 -04:00
|
|
|
else:
|
|
|
|
initial = None
|
2018-02-02 21:30:16 -05:00
|
|
|
field = forms.NullBooleanField(
|
2020-01-01 23:46:51 +00:00
|
|
|
required=cf.required, initial=initial, widget=StaticSelect2(choices=choices)
|
2018-02-02 21:30:16 -05:00
|
|
|
)
|
2016-08-16 14:57:04 -04:00
|
|
|
|
|
|
|
# Date
|
|
|
|
elif cf.type == CF_TYPE_DATE:
|
2019-12-28 22:55:00 +00:00
|
|
|
field = forms.DateField(required=cf.required, initial=initial, widget=DatePicker())
|
2016-08-16 14:57:04 -04:00
|
|
|
|
|
|
|
# Select
|
|
|
|
elif cf.type == CF_TYPE_SELECT:
|
2016-09-16 13:41:53 -04:00
|
|
|
choices = [(cfc.pk, cfc) for cfc in cf.choices.all()]
|
2016-12-07 14:00:52 -05:00
|
|
|
if not cf.required or bulk_edit or filterable_only:
|
2016-08-16 14:57:04 -04:00
|
|
|
choices = [(None, '---------')] + choices
|
2018-06-29 16:01:28 -04:00
|
|
|
# Check for a default choice
|
|
|
|
default_choice = None
|
|
|
|
if initial:
|
|
|
|
try:
|
|
|
|
default_choice = cf.choices.get(value=initial).pk
|
|
|
|
except ObjectDoesNotExist:
|
|
|
|
pass
|
2020-01-01 23:46:51 +00:00
|
|
|
field = forms.TypedChoiceField(
|
|
|
|
choices=choices, coerce=int, required=cf.required, initial=default_choice, widget=StaticSelect2()
|
|
|
|
)
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-08-23 16:45:26 -04:00
|
|
|
# URL
|
|
|
|
elif cf.type == CF_TYPE_URL:
|
2018-02-02 21:30:16 -05:00
|
|
|
field = LaxURLField(required=cf.required, initial=initial)
|
2016-08-23 16:45:26 -04:00
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
# Text
|
|
|
|
else:
|
2018-02-02 21:30:16 -05:00
|
|
|
field = forms.CharField(max_length=255, required=cf.required, initial=initial)
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
field.model = cf
|
2016-08-18 14:23:28 -04:00
|
|
|
field.label = cf.label if cf.label else cf.name.replace('_', ' ').capitalize()
|
2016-12-16 10:54:45 -05:00
|
|
|
if cf.description:
|
|
|
|
field.help_text = cf.description
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
field_dict[field_name] = field
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
return field_dict
|
2016-08-12 17:20:01 -04:00
|
|
|
|
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
class CustomFieldForm(forms.ModelForm):
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
def __init__(self, *args, **kwargs):
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-10-05 15:17:17 -04:00
|
|
|
self.custom_fields = []
|
2016-08-16 14:57:04 -04:00
|
|
|
self.obj_type = ContentType.objects.get_for_model(self._meta.model)
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2018-11-27 10:52:24 -05:00
|
|
|
super().__init__(*args, **kwargs)
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
# Add all applicable CustomFields to the form
|
2016-08-17 13:40:22 -04:00
|
|
|
custom_fields = []
|
2016-08-16 14:57:04 -04:00
|
|
|
for name, field in get_custom_fields_for_model(self.obj_type).items():
|
|
|
|
self.fields[name] = field
|
2016-08-17 13:40:22 -04:00
|
|
|
custom_fields.append(name)
|
|
|
|
self.custom_fields = custom_fields
|
2016-08-15 15:24:23 -04:00
|
|
|
|
|
|
|
# If editing an existing object, initialize values for all custom fields
|
|
|
|
if self.instance.pk:
|
2019-08-19 01:53:39 -04:00
|
|
|
existing_values = CustomFieldValue.objects.filter(
|
|
|
|
obj_type=self.obj_type,
|
|
|
|
obj_id=self.instance.pk
|
|
|
|
).prefetch_related('field')
|
2016-08-15 15:24:23 -04:00
|
|
|
for cfv in existing_values:
|
2016-09-28 09:58:59 -04:00
|
|
|
self.initial['cf_{}'.format(str(cfv.field.name))] = cfv.serialized_value
|
2016-08-15 15:24:23 -04:00
|
|
|
|
|
|
|
def _save_custom_fields(self):
|
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
for field_name in self.custom_fields:
|
2016-08-23 16:45:26 -04:00
|
|
|
try:
|
2019-08-19 01:53:39 -04:00
|
|
|
cfv = CustomFieldValue.objects.prefetch_related('field').get(
|
|
|
|
field=self.fields[field_name].model,
|
|
|
|
obj_type=self.obj_type,
|
|
|
|
obj_id=self.instance.pk
|
|
|
|
)
|
2016-08-23 16:45:26 -04:00
|
|
|
except CustomFieldValue.DoesNotExist:
|
|
|
|
# Skip this field if none exists already and its value is empty
|
2017-05-24 11:33:11 -04:00
|
|
|
if self.cleaned_data[field_name] in [None, '']:
|
2016-08-23 16:45:26 -04:00
|
|
|
continue
|
|
|
|
cfv = CustomFieldValue(
|
|
|
|
field=self.fields[field_name].model,
|
|
|
|
obj_type=self.obj_type,
|
|
|
|
obj_id=self.instance.pk
|
|
|
|
)
|
|
|
|
cfv.value = self.cleaned_data[field_name]
|
|
|
|
cfv.save()
|
2016-08-15 15:24:23 -04:00
|
|
|
|
|
|
|
def save(self, commit=True):
|
2018-11-27 10:52:24 -05:00
|
|
|
obj = super().save(commit)
|
2016-08-15 15:24:23 -04:00
|
|
|
|
|
|
|
# Handle custom fields the same way we do M2M fields
|
|
|
|
if commit:
|
|
|
|
self._save_custom_fields()
|
|
|
|
else:
|
|
|
|
self.save_custom_fields = self._save_custom_fields
|
|
|
|
|
|
|
|
return obj
|
2016-08-16 14:57:04 -04:00
|
|
|
|
|
|
|
|
2016-09-30 16:17:41 -04:00
|
|
|
class CustomFieldBulkEditForm(BulkEditForm):
|
2016-08-16 14:57:04 -04:00
|
|
|
|
2016-10-05 15:17:17 -04:00
|
|
|
def __init__(self, *args, **kwargs):
|
2018-11-27 10:52:24 -05:00
|
|
|
super().__init__(*args, **kwargs)
|
2016-08-16 14:57:04 -04:00
|
|
|
|
2016-10-05 15:17:17 -04:00
|
|
|
self.custom_fields = []
|
|
|
|
self.obj_type = ContentType.objects.get_for_model(self.model)
|
|
|
|
|
2016-08-16 14:57:04 -04:00
|
|
|
# Add all applicable CustomFields to the form
|
2016-10-05 15:17:17 -04:00
|
|
|
custom_fields = get_custom_fields_for_model(self.obj_type, bulk_edit=True).items()
|
|
|
|
for name, field in custom_fields:
|
|
|
|
# Annotate non-required custom fields as nullable
|
|
|
|
if not field.required:
|
|
|
|
self.nullable_fields.append(name)
|
2016-08-16 14:57:04 -04:00
|
|
|
field.required = False
|
|
|
|
self.fields[name] = field
|
2016-10-05 15:17:17 -04:00
|
|
|
# Annotate this as a custom field
|
|
|
|
self.custom_fields.append(name)
|
2016-08-23 12:05:28 -04:00
|
|
|
|
|
|
|
|
|
|
|
class CustomFieldFilterForm(forms.Form):
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
|
|
self.obj_type = ContentType.objects.get_for_model(self.model)
|
|
|
|
|
2018-11-27 10:52:24 -05:00
|
|
|
super().__init__(*args, **kwargs)
|
2016-08-23 12:05:28 -04:00
|
|
|
|
|
|
|
# Add all applicable CustomFields to the form
|
2016-08-23 16:45:26 -04:00
|
|
|
custom_fields = get_custom_fields_for_model(self.obj_type, filterable_only=True).items()
|
2016-08-23 12:05:28 -04:00
|
|
|
for name, field in custom_fields:
|
|
|
|
field.required = False
|
|
|
|
self.fields[name] = field
|
2017-03-30 21:55:57 -04:00
|
|
|
|
|
|
|
|
2018-05-22 12:22:46 -04:00
|
|
|
#
|
|
|
|
# Tags
|
|
|
|
#
|
|
|
|
|
|
|
|
class TagForm(BootstrapMixin, forms.ModelForm):
|
|
|
|
slug = SlugField()
|
2019-02-20 03:52:47 -05:00
|
|
|
comments = CommentField()
|
2018-05-22 12:22:46 -04:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = Tag
|
2018-11-27 11:57:29 -05:00
|
|
|
fields = [
|
2019-02-20 03:52:47 -05:00
|
|
|
'name', 'slug', 'color', 'comments'
|
2018-11-27 11:57:29 -05:00
|
|
|
]
|
2018-05-22 12:22:46 -04:00
|
|
|
|
|
|
|
|
2018-07-10 10:00:21 -04:00
|
|
|
class AddRemoveTagsForm(forms.Form):
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
2018-11-27 10:52:24 -05:00
|
|
|
super().__init__(*args, **kwargs)
|
2018-07-10 10:00:21 -04:00
|
|
|
|
|
|
|
# Add add/remove tags fields
|
|
|
|
self.fields['add_tags'] = TagField(required=False)
|
|
|
|
self.fields['remove_tags'] = TagField(required=False)
|
|
|
|
|
|
|
|
|
2018-11-15 16:47:41 -05:00
|
|
|
class TagFilterForm(BootstrapMixin, forms.Form):
|
|
|
|
model = Tag
|
2018-11-27 11:57:29 -05:00
|
|
|
q = forms.CharField(
|
|
|
|
required=False,
|
|
|
|
label='Search'
|
|
|
|
)
|
2018-11-15 16:47:41 -05:00
|
|
|
|
|
|
|
|
2019-08-28 11:56:00 -04:00
|
|
|
class TagBulkEditForm(BootstrapMixin, BulkEditForm):
|
|
|
|
pk = forms.ModelMultipleChoiceField(
|
|
|
|
queryset=Tag.objects.all(),
|
|
|
|
widget=forms.MultipleHiddenInput
|
|
|
|
)
|
|
|
|
color = forms.CharField(
|
|
|
|
max_length=6,
|
|
|
|
required=False,
|
|
|
|
widget=ColorSelect()
|
|
|
|
)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
nullable_fields = []
|
|
|
|
|
|
|
|
|
2018-06-27 16:02:34 -04:00
|
|
|
#
|
|
|
|
# Config contexts
|
|
|
|
#
|
|
|
|
|
|
|
|
class ConfigContextForm(BootstrapMixin, forms.ModelForm):
|
2019-09-18 15:39:26 -04:00
|
|
|
data = JSONField(
|
|
|
|
label=''
|
|
|
|
)
|
2018-06-27 16:02:34 -04:00
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = ConfigContext
|
2018-06-29 09:44:32 -04:00
|
|
|
fields = [
|
2018-07-27 15:47:29 -04:00
|
|
|
'name', 'weight', 'description', 'is_active', 'regions', 'sites', 'roles', 'platforms', 'tenant_groups',
|
|
|
|
'tenants', 'data',
|
2018-06-29 09:44:32 -04:00
|
|
|
]
|
2019-02-18 21:10:15 -05:00
|
|
|
widgets = {
|
|
|
|
'regions': APISelectMultiple(
|
|
|
|
api_url="/api/dcim/regions/"
|
|
|
|
),
|
|
|
|
'sites': APISelectMultiple(
|
|
|
|
api_url="/api/dcim/sites/"
|
|
|
|
),
|
|
|
|
'roles': APISelectMultiple(
|
|
|
|
api_url="/api/dcim/device-roles/"
|
|
|
|
),
|
|
|
|
'platforms': APISelectMultiple(
|
|
|
|
api_url="/api/dcim/platforms/"
|
|
|
|
),
|
|
|
|
'tenant_groups': APISelectMultiple(
|
|
|
|
api_url="/api/tenancy/tenant-groups/"
|
|
|
|
),
|
|
|
|
'tenants': APISelectMultiple(
|
|
|
|
api_url="/api/tenancy/tenants/"
|
|
|
|
)
|
|
|
|
}
|
2018-06-27 16:02:34 -04:00
|
|
|
|
|
|
|
|
2018-11-13 15:08:55 -05:00
|
|
|
class ConfigContextBulkEditForm(BootstrapMixin, BulkEditForm):
|
|
|
|
pk = forms.ModelMultipleChoiceField(
|
|
|
|
queryset=ConfigContext.objects.all(),
|
|
|
|
widget=forms.MultipleHiddenInput
|
|
|
|
)
|
|
|
|
weight = forms.IntegerField(
|
|
|
|
required=False,
|
|
|
|
min_value=0
|
|
|
|
)
|
|
|
|
is_active = forms.NullBooleanField(
|
|
|
|
required=False,
|
|
|
|
widget=BulkEditNullBooleanSelect()
|
|
|
|
)
|
|
|
|
description = forms.CharField(
|
|
|
|
required=False,
|
|
|
|
max_length=100
|
|
|
|
)
|
|
|
|
|
|
|
|
class Meta:
|
2018-11-27 11:57:29 -05:00
|
|
|
nullable_fields = [
|
|
|
|
'description',
|
|
|
|
]
|
2018-11-13 15:08:55 -05:00
|
|
|
|
|
|
|
|
2018-08-09 12:22:34 -04:00
|
|
|
class ConfigContextFilterForm(BootstrapMixin, forms.Form):
|
|
|
|
q = forms.CharField(
|
|
|
|
required=False,
|
|
|
|
label='Search'
|
|
|
|
)
|
2019-02-18 21:10:15 -05:00
|
|
|
region = FilterChoiceField(
|
2018-08-09 12:22:34 -04:00
|
|
|
queryset=Region.objects.all(),
|
2019-02-18 21:10:15 -05:00
|
|
|
to_field_name='slug',
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
api_url="/api/dcim/regions/",
|
|
|
|
value_field="slug",
|
|
|
|
)
|
2018-08-09 12:22:34 -04:00
|
|
|
)
|
|
|
|
site = FilterChoiceField(
|
|
|
|
queryset=Site.objects.all(),
|
2019-02-18 21:10:15 -05:00
|
|
|
to_field_name='slug',
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
api_url="/api/dcim/sites/",
|
|
|
|
value_field="slug",
|
|
|
|
)
|
2018-08-09 12:22:34 -04:00
|
|
|
)
|
|
|
|
role = FilterChoiceField(
|
|
|
|
queryset=DeviceRole.objects.all(),
|
2019-02-18 21:10:15 -05:00
|
|
|
to_field_name='slug',
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
api_url="/api/dcim/device-roles/",
|
|
|
|
value_field="slug",
|
|
|
|
)
|
2018-08-09 12:22:34 -04:00
|
|
|
)
|
|
|
|
platform = FilterChoiceField(
|
|
|
|
queryset=Platform.objects.all(),
|
2019-02-18 21:10:15 -05:00
|
|
|
to_field_name='slug',
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
api_url="/api/dcim/platforms/",
|
|
|
|
value_field="slug",
|
|
|
|
)
|
2018-08-09 12:22:34 -04:00
|
|
|
)
|
|
|
|
tenant_group = FilterChoiceField(
|
|
|
|
queryset=TenantGroup.objects.all(),
|
2019-02-18 21:10:15 -05:00
|
|
|
to_field_name='slug',
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
api_url="/api/tenancy/tenant-groups/",
|
|
|
|
value_field="slug",
|
|
|
|
)
|
2018-08-09 12:22:34 -04:00
|
|
|
)
|
|
|
|
tenant = FilterChoiceField(
|
|
|
|
queryset=Tenant.objects.all(),
|
2019-02-18 21:10:15 -05:00
|
|
|
to_field_name='slug',
|
|
|
|
widget=APISelectMultiple(
|
|
|
|
api_url="/api/tenancy/tenants/",
|
|
|
|
value_field="slug",
|
|
|
|
)
|
2018-08-09 12:22:34 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2019-09-06 11:42:56 -05:00
|
|
|
#
|
|
|
|
# Filter form for local config context data
|
|
|
|
#
|
|
|
|
|
|
|
|
class LocalConfigContextFilterForm(forms.Form):
|
|
|
|
local_context_data = forms.NullBooleanField(
|
|
|
|
required=False,
|
|
|
|
label='Has local config context data',
|
|
|
|
widget=StaticSelect2(
|
|
|
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2018-05-22 12:22:46 -04:00
|
|
|
#
|
|
|
|
# Image attachments
|
|
|
|
#
|
|
|
|
|
2017-03-30 21:55:57 -04:00
|
|
|
class ImageAttachmentForm(BootstrapMixin, forms.ModelForm):
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
model = ImageAttachment
|
2018-11-27 11:57:29 -05:00
|
|
|
fields = [
|
|
|
|
'name', 'image',
|
|
|
|
]
|
2018-06-20 13:52:54 -04:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Change logging
|
|
|
|
#
|
|
|
|
|
2018-12-13 14:35:26 -05:00
|
|
|
class ObjectChangeFilterForm(BootstrapMixin, forms.Form):
|
2018-06-20 13:52:54 -04:00
|
|
|
model = ObjectChange
|
|
|
|
q = forms.CharField(
|
|
|
|
required=False,
|
|
|
|
label='Search'
|
|
|
|
)
|
2018-12-13 14:43:05 -05:00
|
|
|
time_after = forms.DateTimeField(
|
2018-06-20 13:52:54 -04:00
|
|
|
label='After',
|
|
|
|
required=False,
|
2019-12-28 22:55:00 +00:00
|
|
|
widget=DateTimePicker()
|
2018-06-20 13:52:54 -04:00
|
|
|
)
|
2018-12-13 14:43:05 -05:00
|
|
|
time_before = forms.DateTimeField(
|
2018-06-20 13:52:54 -04:00
|
|
|
label='Before',
|
|
|
|
required=False,
|
2019-12-28 22:55:00 +00:00
|
|
|
widget=DateTimePicker()
|
2018-06-20 13:52:54 -04:00
|
|
|
)
|
|
|
|
action = forms.ChoiceField(
|
|
|
|
choices=add_blank_choice(OBJECTCHANGE_ACTION_CHOICES),
|
|
|
|
required=False
|
|
|
|
)
|
|
|
|
user = forms.ModelChoiceField(
|
|
|
|
queryset=User.objects.order_by('username'),
|
|
|
|
required=False
|
|
|
|
)
|
2018-12-13 14:35:26 -05:00
|
|
|
changed_object_type = forms.ModelChoiceField(
|
|
|
|
queryset=ContentType.objects.order_by('model'),
|
|
|
|
required=False,
|
|
|
|
widget=ContentTypeSelect(),
|
|
|
|
label='Object Type'
|
|
|
|
)
|
2019-08-09 12:33:33 -04:00
|
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
# Scripts
|
|
|
|
#
|
|
|
|
|
|
|
|
class ScriptForm(BootstrapMixin, forms.Form):
|
2019-08-12 14:28:06 -04:00
|
|
|
_commit = forms.BooleanField(
|
|
|
|
required=False,
|
|
|
|
initial=True,
|
|
|
|
label="Commit changes",
|
|
|
|
help_text="Commit changes to the database (uncheck for a dry-run)"
|
|
|
|
)
|
2019-08-09 12:33:33 -04:00
|
|
|
|
2019-10-09 15:16:50 -04:00
|
|
|
def __init__(self, vars, *args, commit_default=True, **kwargs):
|
2019-08-09 12:33:33 -04:00
|
|
|
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
|
|
|
|
# Dynamically populate fields for variables
|
2019-08-09 16:34:01 -04:00
|
|
|
for name, var in vars.items():
|
2019-08-09 12:33:33 -04:00
|
|
|
self.fields[name] = var.as_field()
|
2019-08-12 14:28:06 -04:00
|
|
|
|
2019-10-09 15:16:50 -04:00
|
|
|
# Toggle default commit behavior based on Meta option
|
|
|
|
if not commit_default:
|
|
|
|
self.fields['_commit'].initial = False
|
|
|
|
|
2019-08-12 14:28:06 -04:00
|
|
|
# Move _commit to the end of the form
|
|
|
|
self.fields.move_to_end('_commit', True)
|
2019-08-14 10:18:25 -04:00
|
|
|
|
|
|
|
@property
|
|
|
|
def requires_input(self):
|
|
|
|
"""
|
|
|
|
A boolean indicating whether the form requires user input (ignore the _commit field).
|
|
|
|
"""
|
|
|
|
return bool(len(self.fields) > 1)
|