fields.py 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. """
  2. A DateTimeField and DateField that use the `dateutil` package for parsing.
  3. """
  4. from __future__ import unicode_literals
  5. from dateutil import parser
  6. from wtforms.fields import Field
  7. from wtforms.validators import ValidationError
  8. from wtforms.widgets import TextInput
  9. __all__ = (
  10. 'DateTimeField', 'DateField',
  11. )
  12. # This is a fix to handle issues in dateutil which arose in version 2.2.
  13. # A bug ticket is filed: https://bugs.launchpad.net/dateutil/+bug/1247643
  14. try:
  15. parser.parse('foobar')
  16. except TypeError:
  17. DATEUTIL_TYPEERROR_ISSUE = True
  18. except ValueError:
  19. DATEUTIL_TYPEERROR_ISSUE = False
  20. else:
  21. import warnings
  22. warnings.warn('In testing for a dateutil issue, we ran into a very strange error.', ImportWarning)
  23. class DateTimeField(Field):
  24. """
  25. DateTimeField represented by a text input, accepts all input text formats
  26. that `dateutil.parser.parse` will.
  27. :param parse_kwargs:
  28. A dictionary of keyword args to pass to the dateutil parse() function.
  29. See dateutil docs for available keywords.
  30. :param display_format:
  31. A format string to pass to strftime() to format dates for display.
  32. """
  33. widget = TextInput()
  34. def __init__(self, label=None, validators=None, parse_kwargs=None,
  35. display_format='%Y-%m-%d %H:%M', **kwargs):
  36. super(DateTimeField, self).__init__(label, validators, **kwargs)
  37. if parse_kwargs is None:
  38. parse_kwargs = {}
  39. self.parse_kwargs = parse_kwargs
  40. self.display_format = display_format
  41. def _value(self):
  42. if self.raw_data:
  43. return ' '.join(self.raw_data)
  44. else:
  45. return self.data and self.data.strftime(self.display_format) or ''
  46. def process_formdata(self, valuelist):
  47. if valuelist:
  48. date_str = ' '.join(valuelist)
  49. if not date_str:
  50. self.data = None
  51. raise ValidationError(self.gettext('Please input a date/time value'))
  52. parse_kwargs = self.parse_kwargs.copy()
  53. if 'default' not in parse_kwargs:
  54. try:
  55. parse_kwargs['default'] = self.default()
  56. except TypeError:
  57. parse_kwargs['default'] = self.default
  58. try:
  59. self.data = parser.parse(date_str, **parse_kwargs)
  60. except ValueError:
  61. self.data = None
  62. raise ValidationError(self.gettext('Invalid date/time input'))
  63. except TypeError:
  64. if not DATEUTIL_TYPEERROR_ISSUE:
  65. raise
  66. # If we're using dateutil 2.2, then consider it a normal
  67. # ValidationError. Hopefully dateutil fixes this issue soon.
  68. self.data = None
  69. raise ValidationError(self.gettext('Invalid date/time input'))
  70. class DateField(DateTimeField):
  71. """
  72. Same as the DateTimeField, but stores only the date portion.
  73. """
  74. def __init__(self, label=None, validators=None, parse_kwargs=None,
  75. display_format='%Y-%m-%d', **kwargs):
  76. super(DateField, self).__init__(label, validators, parse_kwargs=parse_kwargs, display_format=display_format, **kwargs)
  77. def process_formdata(self, valuelist):
  78. super(DateField, self).process_formdata(valuelist)
  79. if self.data is not None and hasattr(self.data, 'date'):
  80. self.data = self.data.date()