forms.py 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. from __future__ import absolute_import
  2. from django.forms import CheckboxSelectMultiple, IntegerField, ValidationError
  3. from django.utils.encoding import force_str
  4. from bitfield.types import BitHandler
  5. class BitFieldCheckboxSelectMultiple(CheckboxSelectMultiple):
  6. def render(self, name, value, attrs=None, choices=(), renderer=None):
  7. if isinstance(value, BitHandler):
  8. value = [k for k, v in value if v]
  9. elif isinstance(value, int):
  10. real_value = []
  11. div = 2
  12. for k, v in self.choices:
  13. if value % div != 0:
  14. real_value.append(k)
  15. value -= value % div
  16. div *= 2
  17. value = real_value
  18. return super(BitFieldCheckboxSelectMultiple, self).render(
  19. name, value, attrs=attrs
  20. )
  21. def has_changed(self, initial, data):
  22. if initial is None:
  23. initial = []
  24. if data is None:
  25. data = []
  26. if initial != data:
  27. return True
  28. initial_set = set([force_str(value) for value in initial])
  29. data_set = set([force_str(value) for value in data])
  30. return data_set != initial_set
  31. class BitFormField(IntegerField):
  32. def __init__(
  33. self, choices=(), widget=BitFieldCheckboxSelectMultiple, *args, **kwargs
  34. ):
  35. if isinstance(kwargs["initial"], int):
  36. iv = kwargs["initial"]
  37. iv_list = []
  38. for i in range(0, min(len(choices), 63)):
  39. if (1 << i) & iv > 0:
  40. iv_list += [choices[i][0]]
  41. kwargs["initial"] = iv_list
  42. self.widget = widget
  43. super(BitFormField, self).__init__(widget=widget, *args, **kwargs)
  44. self.choices = self.widget.choices = choices
  45. def clean(self, value):
  46. if not value:
  47. return 0
  48. # Assume an iterable which contains an item per flag that's enabled
  49. result = BitHandler(0, [k for k, v in self.choices])
  50. for k in value:
  51. try:
  52. setattr(result, str(k), True)
  53. except AttributeError:
  54. raise ValidationError("Unknown choice: %r" % (k,))
  55. return int(result)