filters.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import re
  2. from datetime import timedelta
  3. from django.db.models import Avg, Count
  4. from django.utils import timezone
  5. from django_filters import rest_framework as filters
  6. from django_filters.fields import IsoDateTimeField
  7. from projects.models import Project
  8. from .models import TransactionGroup
  9. RELATIVE_TIME_REGEX = re.compile(r"now\-\d+(m|h|d)$")
  10. class RelativeIsoDateTimeField(IsoDateTimeField):
  11. """
  12. Allow relative terms like now or now-1h. Only 0 or 1 subtraction operation is permitted.
  13. Accepts
  14. - now
  15. - - (subtraction)
  16. - m (minutes)
  17. - h (hours)
  18. - d (days)
  19. """
  20. def strptime(self, value, format):
  21. # Check for relative time, if panic just assume it's a datetime
  22. result = timezone.now()
  23. if value == "now":
  24. return result
  25. if RELATIVE_TIME_REGEX.match(value):
  26. numbers = int(re.findall(r"\d+", value)[0])
  27. if value[-1] == "m":
  28. result -= timedelta(minutes=numbers)
  29. if value[-1] == "h":
  30. result -= timedelta(hours=numbers)
  31. if value[-1] == "d":
  32. result -= timedelta(days=numbers)
  33. return result
  34. return super().strptime(value, format)
  35. class RelativeIsoDateTimeFilter(filters.IsoDateTimeFilter):
  36. field_class = RelativeIsoDateTimeField
  37. class TransactionGroupFilter(filters.FilterSet):
  38. start = RelativeIsoDateTimeFilter(
  39. field_name="transactionevent__created",
  40. lookup_expr="gte",
  41. label="Transaction start date",
  42. )
  43. end = RelativeIsoDateTimeFilter(
  44. field_name="transactionevent__created",
  45. lookup_expr="lte",
  46. label="Transaction end date",
  47. )
  48. project = filters.ModelMultipleChoiceFilter(queryset=Project.objects.all())
  49. query = filters.CharFilter(
  50. field_name="transaction",
  51. lookup_expr="icontains",
  52. label="Transaction text search",
  53. )
  54. class Meta:
  55. model = TransactionGroup
  56. fields = ["project", "start", "end"]
  57. def filter_queryset(self, queryset):
  58. queryset = super().filter_queryset(queryset)
  59. environments = self.request.query_params.getlist("environment")
  60. if environments:
  61. queryset = queryset.filter(tags__environment__has_any_keys=environments)
  62. # This annotation must be applied after any related transactionevent filter
  63. queryset = queryset.annotate(
  64. avg_duration=Avg("transactionevent__duration"),
  65. transaction_count=Count("transactionevent"),
  66. )
  67. return queryset