| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- from django import forms
- from django.contrib.contenttypes.models import ContentType
- from django.db.models import Q
- from extras.choices import *
- from extras.models import *
- from utilities.forms import BootstrapMixin, BulkEditBaseForm, CSVModelForm
- __all__ = (
- 'CustomFieldModelCSVForm',
- 'CustomFieldModelBulkEditForm',
- 'CustomFieldModelFilterForm',
- 'CustomFieldModelForm',
- 'CustomFieldsMixin',
- )
- class CustomFieldsMixin:
- """
- Extend a Form to include custom field support.
- """
- def __init__(self, *args, **kwargs):
- self.custom_fields = []
- super().__init__(*args, **kwargs)
- self._append_customfield_fields()
- def _get_content_type(self):
- """
- Return the ContentType of the form's model.
- """
- if not hasattr(self, 'model'):
- raise NotImplementedError(f"{self.__class__.__name__} must specify a model class.")
- return ContentType.objects.get_for_model(self.model)
- def _get_custom_fields(self, content_type):
- return CustomField.objects.filter(content_types=content_type)
- def _get_form_field(self, customfield):
- return customfield.to_form_field()
- def _append_customfield_fields(self):
- """
- Append form fields for all CustomFields assigned to this object type.
- """
- for customfield in self._get_custom_fields(self._get_content_type()):
- field_name = f'cf_{customfield.name}'
- self.fields[field_name] = self._get_form_field(customfield)
- # Annotate the field in the list of CustomField form fields
- self.custom_fields.append(field_name)
- class CustomFieldModelForm(BootstrapMixin, CustomFieldsMixin, forms.ModelForm):
- """
- Extend ModelForm to include custom field support.
- """
- def _get_content_type(self):
- return ContentType.objects.get_for_model(self._meta.model)
- def _get_form_field(self, customfield):
- if self.instance.pk:
- form_field = customfield.to_form_field(set_initial=False)
- form_field.initial = self.instance.custom_field_data.get(customfield.name, None)
- return form_field
- return customfield.to_form_field()
- def clean(self):
- # Save custom field data on instance
- for cf_name in self.custom_fields:
- key = cf_name[3:] # Strip "cf_" from field name
- value = self.cleaned_data.get(cf_name)
- empty_values = self.fields[cf_name].empty_values
- # Convert "empty" values to null
- self.instance.custom_field_data[key] = value if value not in empty_values else None
- return super().clean()
- class CustomFieldModelCSVForm(CSVModelForm, CustomFieldModelForm):
- def _get_form_field(self, customfield):
- return customfield.to_form_field(for_csv_import=True)
- class CustomFieldModelBulkEditForm(BootstrapMixin, CustomFieldsMixin, BulkEditBaseForm):
- def _get_form_field(self, customfield):
- return customfield.to_form_field(set_initial=False, enforce_required=False)
- def _append_customfield_fields(self):
- """
- Append form fields for all CustomFields assigned to this object type.
- """
- for customfield in self._get_custom_fields(self._get_content_type()):
- # Annotate non-required custom fields as nullable
- if not customfield.required:
- self.nullable_fields.append(customfield.name)
- self.fields[customfield.name] = self._get_form_field(customfield)
- # Annotate the field in the list of CustomField form fields
- self.custom_fields.append(customfield.name)
- class CustomFieldModelFilterForm(BootstrapMixin, CustomFieldsMixin, forms.Form):
- q = forms.CharField(
- required=False,
- label='Search'
- )
- def _get_custom_fields(self, content_type):
- return CustomField.objects.filter(content_types=content_type).exclude(
- Q(filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED) |
- Q(type=CustomFieldTypeChoices.TYPE_JSON)
- )
- def _get_form_field(self, customfield):
- return customfield.to_form_field(set_initial=False, enforce_required=False)
|