Skip to content

Commit eb9bf97

Browse files
committed
Address PR feedback for the as_of_date filter to include valid_from dates and without it returns all baselines see HEA-914
1 parent 1e0293d commit eb9bf97

3 files changed

Lines changed: 43 additions & 34 deletions

File tree

apps/baseline/models.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,20 @@ class LivelihoodZoneBaselineQuerySet(models.QuerySet):
138138
"""
139139

140140
def filter_current(self, as_of_date=None):
141+
"""
142+
Return a queryset filtered to the baselines that are valid as of the date specified.
143+
"""
141144
if not as_of_date:
142145
as_of_date = datetime.date.today()
143-
return self.filter(models.Q(valid_to_date__isnull=True) | models.Q(valid_to_date__gte=as_of_date))
146+
return self.filter(
147+
(models.Q(valid_from_date__lte=as_of_date) | models.Q(valid_from_date__isnull=True))
148+
& (models.Q(valid_to_date__gte=as_of_date) | models.Q(valid_to_date__isnull=True))
149+
)
144150

145151
def current_all(self, as_of_date=None):
146-
# Return all the baselines that are valid as of the date specified.
152+
"""
153+
Return all the baselines that are valid as of the date specified.
154+
"""
147155
return self.filter_current(as_of_date).all()
148156

149157

apps/baseline/tests/test_viewsets.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -596,50 +596,75 @@ def test_filter_by_wealth_characteristic(self):
596596
self.assertEqual(len(response.json()), 1)
597597

598598
def test_as_of_date_filter_returns_valid_baselines(self):
599-
# Test that the as_of_date filter returns valid baselines as of the specified date.
599+
"""
600+
Test that the as_of_date filter returns only baselines valid as of the specified date.
601+
"""
600602
today = datetime.date.today()
603+
604+
# Baseline that expired in the past
601605
expired_baseline = LivelihoodZoneBaselineFactory(
602606
valid_from_date=today - datetime.timedelta(days=365),
603607
valid_to_date=today - datetime.timedelta(days=30),
604608
)
609+
610+
# Baseline currently valid
605611
current_baseline = LivelihoodZoneBaselineFactory(
606612
valid_from_date=today - datetime.timedelta(days=30),
607613
valid_to_date=today + datetime.timedelta(days=365),
608614
)
609-
# Test default behavior (as of today) - should exclude expired_baseline
615+
616+
# Baseline that starts in the future (not yet valid)
617+
future_baseline = LivelihoodZoneBaselineFactory(
618+
valid_from_date=today + datetime.timedelta(days=30),
619+
valid_to_date=today + datetime.timedelta(days=365),
620+
)
621+
622+
# Test default behavior (no as_of_date param) - should return all baselines
610623
response = self.client.get(self.url)
611624
self.assertEqual(response.status_code, 200)
612625
baseline_ids = [b["id"] for b in response.json()]
613626
self.assertIn(current_baseline.id, baseline_ids)
627+
self.assertIn(expired_baseline.id, baseline_ids)
628+
self.assertIn(future_baseline.id, baseline_ids)
629+
630+
# Test with explicit as_of_date=today - should filter to current baselines
631+
response = self.client.get(self.url, {"as_of_date": today.isoformat()})
632+
self.assertEqual(response.status_code, 200)
633+
baseline_ids = [b["id"] for b in response.json()]
634+
self.assertIn(current_baseline.id, baseline_ids)
614635
self.assertNotIn(expired_baseline.id, baseline_ids)
636+
self.assertNotIn(future_baseline.id, baseline_ids)
615637

616-
# Test with a past date before the expired_baseline's valid_to_date
638+
# Test with a past date when expired_baseline was still valid
639+
# current_baseline hadn't started yet, so it should be excluded
617640
past_date = today - datetime.timedelta(days=180)
618641
response = self.client.get(self.url, {"as_of_date": past_date.isoformat()})
619642
self.assertEqual(response.status_code, 200)
620643
baseline_ids = [b["id"] for b in response.json()]
621644
self.assertIn(expired_baseline.id, baseline_ids)
622-
self.assertIn(current_baseline.id, baseline_ids)
645+
self.assertNotIn(current_baseline.id, baseline_ids) # hadn't started yet
646+
self.assertNotIn(future_baseline.id, baseline_ids)
623647

624-
# Test with a future date - expired_baseline should still be excluded
648+
# Test with a future date when future_baseline will be valid
625649
future_date = today + datetime.timedelta(days=60)
626650
response = self.client.get(self.url, {"as_of_date": future_date.isoformat()})
627651
self.assertEqual(response.status_code, 200)
628652
baseline_ids = [b["id"] for b in response.json()]
629653
self.assertNotIn(expired_baseline.id, baseline_ids)
630654
self.assertIn(current_baseline.id, baseline_ids)
655+
self.assertIn(future_baseline.id, baseline_ids)
631656

632-
# test as of date filter handles null dates
657+
# Baseline with null valid_from_date (valid from the beginning of time)
633658
baseline_no_from = LivelihoodZoneBaselineFactory(
634659
valid_from_date=None,
635660
valid_to_date=today + datetime.timedelta(days=365),
636661
)
637-
# Create a baseline with null valid_to_date (valid indefinitely)
662+
# Baseline with null valid_to_date (valid indefinitely)
638663
baseline_no_to = LivelihoodZoneBaselineFactory(
639664
valid_from_date=today - datetime.timedelta(days=365),
640665
valid_to_date=None,
641666
)
642-
# Create a baseline with both dates null (always valid)
667+
# Baseline with both dates null (always valid)
643668
baseline_no_dates = LivelihoodZoneBaselineFactory(
644669
valid_from_date=None,
645670
valid_to_date=None,

apps/baseline/viewsets.py

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -254,14 +254,6 @@ def filter_by_wealth_characteristic(self, queryset, name, value):
254254
class LivelihoodZoneBaselineViewSet(BaseModelViewSet):
255255
"""
256256
API endpoint that allows livelihood zone baselines to be viewed or edited.
257-
258-
By default, this endpoint returns only baselines that are currently valid (as of today's date).
259-
This behavior can be controlled using the `as_of_date` query parameter:
260-
261-
- No `as_of_date` parameter: Returns baselines valid as of today
262-
- `as_of_date=YYYY-MM-DD`: Returns baselines valid as of the specified date
263-
- `as_of_date=today`: Returns baselines valid as of today (explicit)
264-
- `as_of_date=<special_value>`: Supports special values like 'last_month', 'one_year_ago', etc.
265257
"""
266258

267259
queryset = LivelihoodZoneBaseline.objects.select_related(
@@ -278,22 +270,6 @@ class LivelihoodZoneBaselineViewSet(BaseModelViewSet):
278270
ordering_fields = ["livelihood_zone__code", "reference_year_end_date"]
279271
ordering = ["livelihood_zone__code", "reference_year_end_date"]
280272

281-
def get_queryset(self):
282-
"""
283-
Override get_queryset to apply default as_of_date filter for list actions.
284-
"""
285-
queryset = super().get_queryset()
286-
287-
if self.action != "list":
288-
return queryset
289-
290-
as_of_date_param = self.request.query_params.get("as_of_date", None)
291-
292-
if as_of_date_param is None:
293-
queryset = queryset.filter_current()
294-
295-
return queryset
296-
297273
def get_serializer_class(self):
298274
if self.request.accepted_renderer.format == "geojson":
299275
return LivelihoodZoneBaselineGeoSerializer # Use GeoFeatureModelSerializer for GeoJSON

0 commit comments

Comments
 (0)