forms.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import re
  2. from django.forms import (
  3. CharField,
  4. DateTimeField,
  5. RadioSelect,
  6. TypedChoiceField,
  7. ValidationError,
  8. )
  9. from django.core.validators import RegexValidator
  10. from django.utils.translation import gettext_lazy as _
  11. from ..core.utils import parse_iso8601_string
  12. class IsoDateTimeField(DateTimeField):
  13. input_formats = ["iso8601"]
  14. def prepare_value(self, value):
  15. try:
  16. return value.isoformat()
  17. except AttributeError:
  18. return value
  19. def to_python(self, value):
  20. """
  21. Validates that the input can be converted to a datetime. Returns a
  22. Python datetime.datetime object.
  23. """
  24. if value in self.empty_values:
  25. return None
  26. try:
  27. return parse_iso8601_string(value)
  28. except ValueError:
  29. raise ValidationError(self.error_messages["invalid"], code="invalid")
  30. def ColorField(**kwargs):
  31. return CharField(
  32. validators=[
  33. RegexValidator(
  34. r"^#[0-9a-f]{6}$",
  35. flags=re.IGNORECASE,
  36. message=_(
  37. "Value must be a 7-character string specifying an RGB color "
  38. "in a hexadecimal format."
  39. ),
  40. )
  41. ],
  42. **kwargs
  43. )
  44. class YesNoSwitchBase(TypedChoiceField):
  45. def prepare_value(self, value):
  46. """normalize bools to binary 1/0 so field works on them too"""
  47. if value in (True, "True", "true", 1, "1"):
  48. return 1
  49. return 0
  50. def clean(self, value):
  51. return self.prepare_value(value)
  52. def YesNoSwitch(**kwargs):
  53. yes_label = kwargs.pop("yes_label", _("Yes"))
  54. no_label = kwargs.pop("no_label", _("No"))
  55. return YesNoSwitchBase(
  56. coerce=int,
  57. choices=[(1, yes_label), (0, no_label)],
  58. widget=RadioSelect(attrs={"class": "yesno-switch"}),
  59. **kwargs
  60. )