forms.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. from django import forms
  2. from django.contrib.contenttypes.models import ContentType
  3. from .models import CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CustomField, CustomFieldValue
  4. def get_custom_fields_for_model(content_type, bulk_editing=False):
  5. """
  6. Retrieve all CustomFields applicable to the given ContentType
  7. """
  8. field_dict = {}
  9. custom_fields = CustomField.objects.filter(obj_type=content_type)
  10. for cf in custom_fields:
  11. field_name = 'cf_{}'.format(str(cf.name))
  12. # Integer
  13. if cf.type == CF_TYPE_INTEGER:
  14. field = forms.IntegerField(required=cf.required, initial=cf.default)
  15. # Boolean
  16. elif cf.type == CF_TYPE_BOOLEAN:
  17. choices = (
  18. (None, '---------'),
  19. (True, 'True'),
  20. (False, 'False'),
  21. )
  22. field = forms.NullBooleanField(required=cf.required, widget=forms.Select(choices=choices))
  23. # Date
  24. elif cf.type == CF_TYPE_DATE:
  25. field = forms.DateField(required=cf.required, initial=cf.default)
  26. # Select
  27. elif cf.type == CF_TYPE_SELECT:
  28. choices = [(cfc.pk, cfc) for cfc in cf.choices.all()]
  29. if not cf.required:
  30. choices = [(0, 'None')] + choices
  31. if bulk_editing:
  32. choices = [(None, '---------')] + choices
  33. field = forms.TypedChoiceField(choices=choices, coerce=int, required=cf.required)
  34. else:
  35. field = forms.ModelChoiceField(queryset=cf.choices.all(), required=cf.required)
  36. # Text
  37. else:
  38. field = forms.CharField(max_length=100, required=cf.required, initial=cf.default)
  39. field.model = cf
  40. field.label = cf.label if cf.label else cf.name.capitalize()
  41. field.help_text = cf.description
  42. field_dict[field_name] = field
  43. return field_dict
  44. class CustomFieldForm(forms.ModelForm):
  45. custom_fields = []
  46. def __init__(self, *args, **kwargs):
  47. self.obj_type = ContentType.objects.get_for_model(self._meta.model)
  48. super(CustomFieldForm, self).__init__(*args, **kwargs)
  49. # Add all applicable CustomFields to the form
  50. custom_fields = []
  51. for name, field in get_custom_fields_for_model(self.obj_type).items():
  52. self.fields[name] = field
  53. custom_fields.append(name)
  54. self.custom_fields = custom_fields
  55. # If editing an existing object, initialize values for all custom fields
  56. if self.instance.pk:
  57. existing_values = CustomFieldValue.objects.filter(obj_type=self.obj_type, obj_id=self.instance.pk)\
  58. .select_related('field')
  59. for cfv in existing_values:
  60. self.initial['cf_{}'.format(str(cfv.field.name))] = cfv.value
  61. def _save_custom_fields(self):
  62. for field_name in self.custom_fields:
  63. try:
  64. cfv = CustomFieldValue.objects.select_related('field').get(field=self.fields[field_name].model,
  65. obj_type=self.obj_type,
  66. obj_id=self.instance.pk)
  67. except CustomFieldValue.DoesNotExist:
  68. cfv = CustomFieldValue(
  69. field=self.fields[field_name].model,
  70. obj_type=self.obj_type,
  71. obj_id=self.instance.pk
  72. )
  73. cfv.value = self.cleaned_data[field_name]
  74. cfv.save()
  75. def save(self, commit=True):
  76. obj = super(CustomFieldForm, self).save(commit)
  77. # Handle custom fields the same way we do M2M fields
  78. if commit:
  79. self._save_custom_fields()
  80. else:
  81. self.save_custom_fields = self._save_custom_fields
  82. return obj
  83. class CustomFieldBulkEditForm(forms.Form):
  84. custom_fields = []
  85. def __init__(self, model, *args, **kwargs):
  86. self.obj_type = ContentType.objects.get_for_model(model)
  87. super(CustomFieldBulkEditForm, self).__init__(*args, **kwargs)
  88. # Add all applicable CustomFields to the form
  89. custom_fields = []
  90. for name, field in get_custom_fields_for_model(self.obj_type, bulk_editing=True).items():
  91. field.required = False
  92. self.fields[name] = field
  93. custom_fields.append(name)
  94. self.custom_fields = custom_fields