Skip to content

Commit 85c6647

Browse files
authored
Allow to filter changesets by osm tags with OR condition (#627)
* Allow to filter changesets by osm tags with OR condition * Fix tests * Another test fix
1 parent 24f0cf7 commit 85c6647

File tree

2 files changed

+46
-6
lines changed

2 files changed

+46
-6
lines changed

osmchadjango/changeset/filters.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,14 @@ class ChangesetFilter(GeoFilterSet):
269269
values. To query by any value use key=*.
270270
"""
271271
)
272+
all_tag_changes = filters.CharFilter(
273+
field_name='tag_changes',
274+
method='filter_all_tag_changes',
275+
help_text="""Filter changesets by the tag_changes field using the AND logic. It supports a
276+
combination of OSM tags and will query using both the old and new
277+
values. To query by any value use key=*.
278+
"""
279+
)
272280

273281
def get_past_n_days(self, queryset, field_name, value):
274282
start_date = date.today() - timedelta(days=int(value))
@@ -281,7 +289,7 @@ def split_values(self, value):
281289
if len(t.split('=')) == 2
282290
]
283291

284-
def filter_tag_changes(self, queryset, name, value):
292+
def filter_all_tag_changes(self, queryset, name, value):
285293
for query in self.split_values(value):
286294
if query[1] == '*':
287295
key = 'tag_changes__has_key'
@@ -292,6 +300,21 @@ def filter_tag_changes(self, queryset, name, value):
292300
queryset = queryset.filter(**{key: query[1]})
293301
return queryset
294302

303+
def filter_tag_changes(self, queryset, name, value):
304+
or_condition = Q()
305+
keys = []
306+
for query in self.split_values(value):
307+
if query[1] == '*':
308+
keys.append(query[0])
309+
else:
310+
key = 'tag_changes__{}__contains'.format(query[0])
311+
or_condition.add(Q(**{key: query[1]}), Q.OR)
312+
if len(keys):
313+
or_condition.add(Q(**{'tag_changes__has_any_keys': keys}), Q.OR)
314+
315+
queryset = queryset.filter(or_condition)
316+
return queryset
317+
295318
def filter_metadata(self, queryset, name, value):
296319
for query in self.split_values(value):
297320
if '__' in query[0]:

osmchadjango/changeset/tests/test_filters.py

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,17 +399,34 @@ def test_metadata_filter(self):
399399
self.assertEqual(ChangesetFilter({'metadata': 'wrongtag__min=abc'}).qs.count(), 0)
400400
self.assertEqual(ChangesetFilter({'metadata': 'closed:improveosm=*'}).qs.count(), 1)
401401

402+
def test_all_tag_changes_filter(self):
403+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'amenity=*'}).qs.count(), 1)
404+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=*'}).qs.count(), 2)
405+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'surface=grass'}).qs.count(), 1)
406+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=primary'}).qs.count(), 1)
407+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary'}).qs.count(), 2)
408+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link'}).qs.count(), 1)
409+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary,name=*'}).qs.count(), 1)
410+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,surface=*'}).qs.count(), 1)
411+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 0)
412+
self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 0)
413+
402414
def test_tag_changes_filter(self):
403-
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=*'}).qs.count(), 2)
415+
# with one tag, the result is the same as all_tag_changes
404416
self.assertEqual(ChangesetFilter({'tag_changes': 'amenity=*'}).qs.count(), 1)
417+
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=*'}).qs.count(), 2)
405418
self.assertEqual(ChangesetFilter({'tag_changes': 'surface=grass'}).qs.count(), 1)
406419
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=primary'}).qs.count(), 1)
407420
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary'}).qs.count(), 2)
408421
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link'}).qs.count(), 1)
409-
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary,name=*'}).qs.count(), 1)
410-
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,surface=*'}).qs.count(), 1)
411-
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 0)
412-
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 0)
422+
# with multiple tags, it filters using the OR condition
423+
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 2)
424+
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary,surface=*'}).qs.count(), 2)
425+
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 1)
426+
self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 2)
427+
self.assertEqual(ChangesetFilter({'tag_changes': 'name=Store,surface=paved'}).qs.count(), 3)
428+
self.assertEqual(ChangesetFilter({'tag_changes': 'landuse=residential,waterway=river'}).qs.count(), 0)
429+
413430

414431

415432
class TestChangesetAreaLowerThan(TestCase):

0 commit comments

Comments
 (0)