mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Added bulk editing capability for custom fields
This commit is contained in:
@@ -4,78 +4,90 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from .models import CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CustomField, CustomFieldValue
|
||||
|
||||
|
||||
def get_custom_fields_for_model(content_type, bulk_editing=False):
|
||||
"""Retrieve all CustomFields applicable to the given ContentType"""
|
||||
field_dict = {}
|
||||
custom_fields = CustomField.objects.filter(obj_type=content_type)
|
||||
|
||||
for cf in custom_fields:
|
||||
field_name = 'cf_{}'.format(str(cf.name))
|
||||
|
||||
# Integer
|
||||
if cf.type == CF_TYPE_INTEGER:
|
||||
field = forms.IntegerField(required=cf.required, initial=cf.default)
|
||||
|
||||
# Boolean
|
||||
elif cf.type == CF_TYPE_BOOLEAN:
|
||||
choices = (
|
||||
(None, '---------'),
|
||||
(True, 'True'),
|
||||
(False, 'False'),
|
||||
)
|
||||
field = forms.NullBooleanField(required=cf.required, widget=forms.Select(choices=choices))
|
||||
|
||||
# Date
|
||||
elif cf.type == CF_TYPE_DATE:
|
||||
field = forms.DateField(required=cf.required, initial=cf.default)
|
||||
|
||||
# Select
|
||||
elif cf.type == CF_TYPE_SELECT:
|
||||
choices = [(cfc.pk, cfc) for cfc in cf.choices.all()]
|
||||
if not cf.required:
|
||||
choices = [(0, 'None')] + choices
|
||||
if bulk_editing:
|
||||
choices = [(None, '---------')] + choices
|
||||
field = forms.TypedChoiceField(choices=choices, coerce=int, required=cf.required)
|
||||
else:
|
||||
field = forms.ModelChoiceField(queryset=cf.choices.all(), required=cf.required)
|
||||
|
||||
# Text
|
||||
else:
|
||||
field = forms.CharField(max_length=100, required=cf.required, initial=cf.default)
|
||||
|
||||
field.model = cf
|
||||
field.label = cf.label if cf.label else cf.name.capitalize()
|
||||
field.help_text = cf.description
|
||||
|
||||
field_dict[field_name] = field
|
||||
|
||||
return field_dict
|
||||
|
||||
|
||||
class CustomFieldForm(forms.ModelForm):
|
||||
custom_fields = []
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
self.obj_type = ContentType.objects.get_for_model(self._meta.model)
|
||||
|
||||
super(CustomFieldForm, self).__init__(*args, **kwargs)
|
||||
|
||||
obj_type = ContentType.objects.get_for_model(self._meta.model)
|
||||
|
||||
# Find all CustomFields for this model
|
||||
custom_fields = CustomField.objects.filter(obj_type=obj_type)
|
||||
for cf in custom_fields:
|
||||
|
||||
field_name = 'cf_{}'.format(str(cf.name))
|
||||
|
||||
# Integer
|
||||
if cf.type == CF_TYPE_INTEGER:
|
||||
field = forms.IntegerField(required=cf.required, initial=cf.default)
|
||||
|
||||
# Boolean
|
||||
elif cf.type == CF_TYPE_BOOLEAN:
|
||||
if cf.required:
|
||||
field = forms.BooleanField(required=False, initial=bool(cf.default))
|
||||
else:
|
||||
field = forms.NullBooleanField(required=False, initial=bool(cf.default))
|
||||
|
||||
# Date
|
||||
elif cf.type == CF_TYPE_DATE:
|
||||
field = forms.DateField(required=cf.required, initial=cf.default)
|
||||
|
||||
# Select
|
||||
elif cf.type == CF_TYPE_SELECT:
|
||||
field = forms.ModelChoiceField(queryset=cf.choices.all(), required=cf.required)
|
||||
|
||||
# Text
|
||||
else:
|
||||
field = forms.CharField(max_length=100, required=cf.required, initial=cf.default)
|
||||
|
||||
field.model = cf
|
||||
field.label = cf.label if cf.label else cf.name.capitalize()
|
||||
field.help_text = cf.description
|
||||
self.fields[field_name] = field
|
||||
self.custom_fields.append(field_name)
|
||||
# Add all applicable CustomFields to the form
|
||||
for name, field in get_custom_fields_for_model(self.obj_type).items():
|
||||
self.fields[name] = field
|
||||
self.custom_fields.append(name)
|
||||
|
||||
# If editing an existing object, initialize values for all custom fields
|
||||
if self.instance.pk:
|
||||
existing_values = CustomFieldValue.objects.filter(obj_type=obj_type, obj_id=self.instance.pk)\
|
||||
existing_values = CustomFieldValue.objects.filter(obj_type=self.obj_type, obj_id=self.instance.pk)\
|
||||
.select_related('field')
|
||||
for cfv in existing_values:
|
||||
self.initial['cf_{}'.format(str(cfv.field.name))] = cfv.value
|
||||
|
||||
def _save_custom_fields(self):
|
||||
|
||||
if self.instance.pk:
|
||||
obj_type = ContentType.objects.get_for_model(self.instance)
|
||||
|
||||
for field_name in self.custom_fields:
|
||||
|
||||
try:
|
||||
cfv = CustomFieldValue.objects.get(field=self.fields[field_name].model, obj_type=obj_type,
|
||||
obj_id=self.instance.pk)
|
||||
except CustomFieldValue.DoesNotExist:
|
||||
cfv = CustomFieldValue(
|
||||
field=self.fields[field_name].model,
|
||||
obj_type=obj_type,
|
||||
obj_id=self.instance.pk
|
||||
)
|
||||
if cfv.pk and self.cleaned_data[field_name] is None:
|
||||
cfv.delete()
|
||||
elif self.cleaned_data[field_name] is not None:
|
||||
cfv.value = self.cleaned_data[field_name]
|
||||
cfv.save()
|
||||
for field_name in self.custom_fields:
|
||||
try:
|
||||
cfv = CustomFieldValue.objects.get(field=self.fields[field_name].model, obj_type=self.obj_type,
|
||||
obj_id=self.instance.pk)
|
||||
except CustomFieldValue.DoesNotExist:
|
||||
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()
|
||||
|
||||
def save(self, commit=True):
|
||||
obj = super(CustomFieldForm, self).save(commit)
|
||||
@@ -87,3 +99,19 @@ class CustomFieldForm(forms.ModelForm):
|
||||
self.save_custom_fields = self._save_custom_fields
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class CustomFieldBulkEditForm(forms.Form):
|
||||
custom_fields = []
|
||||
|
||||
def __init__(self, model, *args, **kwargs):
|
||||
|
||||
self.obj_type = ContentType.objects.get_for_model(model)
|
||||
|
||||
super(CustomFieldBulkEditForm, self).__init__(*args, **kwargs)
|
||||
|
||||
# Add all applicable CustomFields to the form
|
||||
for name, field in get_custom_fields_for_model(self.obj_type, bulk_editing=True).items():
|
||||
field.required = False
|
||||
self.fields[name] = field
|
||||
self.custom_fields.append(name)
|
||||
|
@@ -131,14 +131,22 @@ class CustomFieldValue(models.Model):
|
||||
if self.field.type == CF_TYPE_INTEGER:
|
||||
self.val_int = value
|
||||
elif self.field.type == CF_TYPE_BOOLEAN:
|
||||
self.val_int = bool(value) if value else None
|
||||
self.val_int = int(bool(value)) if value is not None else None
|
||||
elif self.field.type == CF_TYPE_DATE:
|
||||
self.val_date = value
|
||||
elif self.field.type == CF_TYPE_SELECT:
|
||||
self.val_int = value.id
|
||||
# Could be ModelChoiceField or TypedChoiceField
|
||||
self.val_int = value.id if hasattr(value, 'id') else value
|
||||
else:
|
||||
self.val_char = value
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if (self.field.type == CF_TYPE_TEXT and self.value == '') or self.value is None:
|
||||
if self.pk:
|
||||
self.delete()
|
||||
else:
|
||||
super(CustomFieldValue, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class CustomFieldChoice(models.Model):
|
||||
field = models.ForeignKey('CustomField', related_name='choices', limit_choices_to={'type': CF_TYPE_SELECT},
|
||||
|
Reference in New Issue
Block a user