Skip to content

Commit 8da8a8e

Browse files
committed
feat: add support for multiple data sources in DatePeriod filters
Add support for comma-separated data source values in DatePeriodFilter to allow filtering by multiple data sources in a single API call. Changes: - Update data_source filter to use custom method supporting comma-separated values - Update resource_data_source filter to support comma-separated values - Both filters use OR logic to match any of the provided data sources - Add tests for multiple data source filtering - Maintain backward compatibility with single data source values Filters now support values like "ds1,ds2,ds3" to filter date periods that match any of the specified data sources. Refs: HAUKI-757
1 parent d8776a5 commit 8da8a8e

File tree

2 files changed

+119
-5
lines changed

2 files changed

+119
-5
lines changed

hours/filters.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ def filter(self, qs, value):
121121

122122

123123
class DatePeriodFilter(filters.FilterSet):
124-
data_source = filters.CharFilter(field_name="origins__data_source")
124+
data_source = filters.CharFilter(method="data_source_filter")
125125
resource = filters.CharFilter(method="resource_filter")
126126
resource_data_source = filters.CharFilter(method="resource_data_source_filter")
127127

@@ -144,6 +144,23 @@ class Meta:
144144
model = DatePeriod
145145
fields = ["resource"]
146146

147+
def data_source_filter(self, queryset, name, value):
148+
if name != "data_source":
149+
return queryset
150+
151+
data_sources = value.split(",")
152+
q_objects = []
153+
for data_source in data_sources:
154+
q_objects.append(Q(origins__data_source=data_source))
155+
156+
query_q = Q()
157+
for q in q_objects:
158+
query_q |= q
159+
160+
queryset = queryset.filter(query_q)
161+
162+
return queryset
163+
147164
def resource_filter(self, queryset, name, value):
148165
if name != "resource":
149166
return queryset
@@ -164,10 +181,19 @@ def resource_data_source_filter(self, queryset, name, value):
164181
if name != "resource_data_source":
165182
return queryset
166183

167-
queryset = queryset.filter(
168-
Q(resource__data_sources=value)
169-
| Q(resource__ancestry_data_source__contains=[value])
170-
)
184+
data_sources = value.split(",")
185+
q_objects = []
186+
for data_source in data_sources:
187+
q_objects.append(
188+
Q(resource__data_sources=data_source)
189+
| Q(resource__ancestry_data_source__contains=[data_source])
190+
)
191+
192+
query_q = Q()
193+
for q in q_objects:
194+
query_q |= q
195+
196+
queryset = queryset.filter(query_q)
171197

172198
return queryset
173199

hours/tests/test_dateperiod_api.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,45 @@ def test_list_date_periods_filter_by_data_source(
134134
assert response.data[0]["id"] == expected_date_period.id
135135

136136

137+
@pytest.mark.django_db
138+
def test_list_date_periods_filter_by_multiple_data_sources(
139+
admin_client, resource, data_source_factory, date_period_factory
140+
):
141+
data_source_1 = data_source_factory()
142+
data_source_2 = data_source_factory()
143+
144+
date_period_1 = date_period_factory(
145+
resource=resource,
146+
data_sources=[data_source_1],
147+
)
148+
149+
date_period_2 = date_period_factory(
150+
resource=resource,
151+
data_sources=[data_source_2],
152+
)
153+
154+
date_period_factory(
155+
resource=resource,
156+
data_sources=[data_source_factory()],
157+
)
158+
159+
url = reverse("date_period-list")
160+
161+
response = admin_client.get(
162+
url,
163+
data={
164+
"resource": resource.id,
165+
"data_source": f"{data_source_1.id},{data_source_2.id}",
166+
},
167+
)
168+
169+
assert_response_status_code(response, 200)
170+
assert len(response.data) == 2
171+
returned_ids = [item["id"] for item in response.data]
172+
assert date_period_1.id in returned_ids
173+
assert date_period_2.id in returned_ids
174+
175+
137176
@pytest.mark.django_db
138177
def test_list_date_periods_filter_by_resource_direct_data_source(
139178
admin_client, resource, data_source_factory, date_period_factory, resource_factory
@@ -205,6 +244,55 @@ def test_list_date_periods_filter_by_resource_data_source_ancestor(
205244
assert response.data[0]["id"] == expected_date_period.id
206245

207246

247+
@pytest.mark.django_db
248+
def test_list_date_periods_filter_by_multiple_resource_data_sources(
249+
admin_client,
250+
resource,
251+
data_source_factory,
252+
date_period_factory,
253+
resource_factory,
254+
):
255+
data_source_1 = data_source_factory()
256+
data_source_2 = data_source_factory()
257+
258+
resource_1 = resource
259+
resource_1.data_sources.add(data_source_1)
260+
date_period_1 = date_period_factory(
261+
resource=resource_1,
262+
start_date=datetime.date(year=2024, month=1, day=1),
263+
)
264+
265+
resource_2 = resource_factory()
266+
resource_2.data_sources.add(data_source_2)
267+
date_period_2 = date_period_factory(
268+
resource=resource_2,
269+
start_date=datetime.date(year=2024, month=1, day=1),
270+
)
271+
272+
resource_3 = resource_factory()
273+
resource_3.data_sources.add(data_source_factory())
274+
date_period_factory(
275+
resource=resource_3,
276+
start_date=datetime.date(year=2024, month=1, day=1),
277+
)
278+
279+
url = reverse("date_period-list")
280+
281+
response = admin_client.get(
282+
url,
283+
data={
284+
"resource_data_source": f"{data_source_1.id},{data_source_2.id}",
285+
"start_date": "2024-01-01",
286+
},
287+
)
288+
289+
assert_response_status_code(response, 200)
290+
assert len(response.data) == 2
291+
returned_ids = [item["id"] for item in response.data]
292+
assert date_period_1.id in returned_ids
293+
assert date_period_2.id in returned_ids
294+
295+
208296
@pytest.mark.django_db
209297
def test_list_date_periods_filter_start_date_lte(
210298
admin_client, resource, date_period_factory

0 commit comments

Comments
 (0)