diff --git a/osmchadjango/changeset/filters.py b/osmchadjango/changeset/filters.py index a1ca3b1f..b63f230c 100644 --- a/osmchadjango/changeset/filters.py +++ b/osmchadjango/changeset/filters.py @@ -269,6 +269,14 @@ class ChangesetFilter(GeoFilterSet): values. To query by any value use key=*. """ ) + all_tag_changes = filters.CharFilter( + field_name='tag_changes', + method='filter_all_tag_changes', + help_text="""Filter changesets by the tag_changes field using the AND logic. It supports a + combination of OSM tags and will query using both the old and new + values. To query by any value use key=*. + """ + ) def get_past_n_days(self, queryset, field_name, value): start_date = date.today() - timedelta(days=int(value)) @@ -281,7 +289,7 @@ def split_values(self, value): if len(t.split('=')) == 2 ] - def filter_tag_changes(self, queryset, name, value): + def filter_all_tag_changes(self, queryset, name, value): for query in self.split_values(value): if query[1] == '*': key = 'tag_changes__has_key' @@ -292,6 +300,21 @@ def filter_tag_changes(self, queryset, name, value): queryset = queryset.filter(**{key: query[1]}) return queryset + def filter_tag_changes(self, queryset, name, value): + or_condition = Q() + keys = [] + for query in self.split_values(value): + if query[1] == '*': + keys.append(query[0]) + else: + key = 'tag_changes__{}__contains'.format(query[0]) + or_condition.add(Q(**{key: query[1]}), Q.OR) + if len(keys): + or_condition.add(Q(**{'tag_changes__has_any_keys': keys}), Q.OR) + + queryset = queryset.filter(or_condition) + return queryset + def filter_metadata(self, queryset, name, value): for query in self.split_values(value): if '__' in query[0]: diff --git a/osmchadjango/changeset/tests/test_filters.py b/osmchadjango/changeset/tests/test_filters.py index 5f83feb4..c7b3cf11 100644 --- a/osmchadjango/changeset/tests/test_filters.py +++ b/osmchadjango/changeset/tests/test_filters.py @@ -399,17 +399,34 @@ def test_metadata_filter(self): self.assertEqual(ChangesetFilter({'metadata': 'wrongtag__min=abc'}).qs.count(), 0) self.assertEqual(ChangesetFilter({'metadata': 'closed:improveosm=*'}).qs.count(), 1) + def test_all_tag_changes_filter(self): + self.assertEqual(ChangesetFilter({'all_tag_changes': 'amenity=*'}).qs.count(), 1) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=*'}).qs.count(), 2) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'surface=grass'}).qs.count(), 1) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=primary'}).qs.count(), 1) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary'}).qs.count(), 2) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link'}).qs.count(), 1) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary,name=*'}).qs.count(), 1) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,surface=*'}).qs.count(), 1) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 0) + self.assertEqual(ChangesetFilter({'all_tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 0) + def test_tag_changes_filter(self): - self.assertEqual(ChangesetFilter({'tag_changes': 'highway=*'}).qs.count(), 2) + # with one tag, the result is the same as all_tag_changes self.assertEqual(ChangesetFilter({'tag_changes': 'amenity=*'}).qs.count(), 1) + self.assertEqual(ChangesetFilter({'tag_changes': 'highway=*'}).qs.count(), 2) self.assertEqual(ChangesetFilter({'tag_changes': 'surface=grass'}).qs.count(), 1) self.assertEqual(ChangesetFilter({'tag_changes': 'highway=primary'}).qs.count(), 1) self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary'}).qs.count(), 2) self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link'}).qs.count(), 1) - self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary,name=*'}).qs.count(), 1) - self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,surface=*'}).qs.count(), 1) - self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 0) - self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 0) + # with multiple tags, it filters using the OR condition + self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 2) + self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary,surface=*'}).qs.count(), 2) + self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,name=Sky'}).qs.count(), 1) + self.assertEqual(ChangesetFilter({'tag_changes': 'highway=tertiary_link,highway=primary'}).qs.count(), 2) + self.assertEqual(ChangesetFilter({'tag_changes': 'name=Store,surface=paved'}).qs.count(), 3) + self.assertEqual(ChangesetFilter({'tag_changes': 'landuse=residential,waterway=river'}).qs.count(), 0) + class TestChangesetAreaLowerThan(TestCase):