filters.py 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. import re
  2. from datetime import timedelta
  3. from django.utils import timezone
  4. from django_filters import rest_framework as filters
  5. from django_filters.fields import IsoDateTimeField, RangeField
  6. from django_filters.widgets import DateRangeWidget
  7. # Workaround https://github.com/carltongibson/django-filter/issues/1403
  8. class StartEndDateRangeWidget(DateRangeWidget):
  9. """
  10. A range widget that uses 'start' and 'end' query params
  11. """
  12. suffixes = ["start", "end"]
  13. def suffixed(self, name, suffix):
  14. return suffix
  15. RELATIVE_TIME_REGEX = re.compile(r"now\s*\-\s*\d+\s*(m|h|d)\s*$")
  16. class RelativeIsoDateTimeField(IsoDateTimeField):
  17. """
  18. Allow relative terms like now or now-1h. Only 0 or 1 subtraction operation is permitted.
  19. Accepts
  20. - now
  21. - - (subtraction)
  22. - m (minutes)
  23. - h (hours)
  24. - d (days)
  25. """
  26. def strptime(self, value, format):
  27. # Check for relative time, if panic just assume it's a datetime
  28. result = timezone.now()
  29. if value == "now":
  30. return result
  31. if RELATIVE_TIME_REGEX.match(value):
  32. spaces_stripped = value.replace(" ", "")
  33. numbers = int(re.findall(r"\d+", spaces_stripped)[0])
  34. if spaces_stripped[-1] == "m":
  35. result -= timedelta(minutes=numbers)
  36. if spaces_stripped[-1] == "h":
  37. result -= timedelta(hours=numbers)
  38. if spaces_stripped[-1] == "d":
  39. result -= timedelta(days=numbers)
  40. return result
  41. return super().strptime(value, format)
  42. class StartEndRelativeIsoDateTimeRangeField(RangeField):
  43. widget = StartEndDateRangeWidget
  44. def __init__(self, *args, **kwargs):
  45. fields = (RelativeIsoDateTimeField(), RelativeIsoDateTimeField())
  46. super().__init__(fields, *args, **kwargs)
  47. class StartEndRelativeIsoDateTimeRangeFilter(filters.IsoDateTimeFromToRangeFilter):
  48. field_class = StartEndRelativeIsoDateTimeRangeField