2016-08-12 17:20:01 -04:00
|
|
|
from django import forms
|
|
|
|
|
from django.contrib.contenttypes.models import ContentType
|
|
|
|
|
|
2016-08-15 15:24:23 -04:00
|
|
|
from .models import CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CustomField, CustomFieldValue
|
2016-08-12 17:20:01 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
class CustomFieldForm(forms.ModelForm):
|
|
|
|
|
custom_fields = []
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
|
|
|
|
|
super(CustomFieldForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
2016-08-15 15:24:23 -04:00
|
|
|
obj_type = ContentType.objects.get_for_model(self._meta.model)
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-08-15 15:24:23 -04:00
|
|
|
# Find all CustomFields for this model
|
|
|
|
|
custom_fields = CustomField.objects.filter(obj_type=obj_type)
|
2016-08-12 17:20:01 -04:00
|
|
|
for cf in custom_fields:
|
|
|
|
|
|
|
|
|
|
field_name = 'cf_{}'.format(str(cf.name))
|
|
|
|
|
|
|
|
|
|
# Integer
|
|
|
|
|
if cf.type == CF_TYPE_INTEGER:
|
2016-08-15 15:24:23 -04:00
|
|
|
field = forms.IntegerField(required=cf.required, initial=cf.default)
|
2016-08-12 17:20:01 -04:00
|
|
|
|
|
|
|
|
# Boolean
|
|
|
|
|
elif cf.type == CF_TYPE_BOOLEAN:
|
|
|
|
|
if cf.required:
|
2016-08-15 15:24:23 -04:00
|
|
|
field = forms.BooleanField(required=False, initial=bool(cf.default))
|
2016-08-12 17:20:01 -04:00
|
|
|
else:
|
2016-08-15 15:24:23 -04:00
|
|
|
field = forms.NullBooleanField(required=False, initial=bool(cf.default))
|
2016-08-12 17:20:01 -04:00
|
|
|
|
|
|
|
|
# Date
|
|
|
|
|
elif cf.type == CF_TYPE_DATE:
|
2016-08-15 15:24:23 -04:00
|
|
|
field = forms.DateField(required=cf.required, initial=cf.default)
|
2016-08-12 17:20:01 -04:00
|
|
|
|
|
|
|
|
# Select
|
|
|
|
|
elif cf.type == CF_TYPE_SELECT:
|
|
|
|
|
field = forms.ModelChoiceField(queryset=cf.choices.all(), required=cf.required)
|
|
|
|
|
|
|
|
|
|
# Text
|
|
|
|
|
else:
|
2016-08-15 15:24:23 -04:00
|
|
|
field = forms.CharField(max_length=100, required=cf.required, initial=cf.default)
|
2016-08-12 17:20:01 -04:00
|
|
|
|
2016-08-15 15:24:23 -04:00
|
|
|
field.model = cf
|
2016-08-15 16:58:25 -04:00
|
|
|
field.label = cf.label if cf.label else cf.name.capitalize()
|
2016-08-12 17:20:01 -04:00
|
|
|
field.help_text = cf.description
|
|
|
|
|
self.fields[field_name] = field
|
|
|
|
|
self.custom_fields.append(field_name)
|
2016-08-15 15:24:23 -04:00
|
|
|
|
|
|
|
|
# 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)\
|
|
|
|
|
.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()
|
|
|
|
|
|
|
|
|
|
def save(self, commit=True):
|
|
|
|
|
obj = super(CustomFieldForm, self).save(commit)
|
|
|
|
|
|
|
|
|
|
# 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
|