Skip to content
This repository has been archived by the owner on May 15, 2020. It is now read-only.

Commit

Permalink
OPT: Support filtering on reverse related fields
Browse files Browse the repository at this point in the history
  • Loading branch information
JeroennC committed Dec 24, 2019
1 parent e614f7d commit ab5ba1b
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 8 deletions.
9 changes: 8 additions & 1 deletion katka/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class TeamViewSet(FilterViewMixin, AuditViewSet):
serializer_class = TeamSerializer
lookup_field = "public_identifier"
lookup_value_regex = "[0-9a-f-]{36}"
parameter_lookup_map = {"application": "project__application"}

def get_queryset(self):
# Only show teams that are linked to a group that the user is part of
Expand Down Expand Up @@ -256,7 +257,13 @@ class SCMReleaseViewSet(FilterViewMixin, ReadOnlyAuditViewMixin):

def get_queryset(self):
user_groups = self.request.user.groups.all()
return super().get_queryset().filter(scm_pipeline_runs__application__project__team__group__in=user_groups)
# Do select distinct because of the many to many relationship
return (
super()
.get_queryset()
.distinct()
.filter(scm_pipeline_runs__application__project__team__group__in=user_groups)
)


class ApplicationMetadataViewSet(AuditViewSet):
Expand Down
12 changes: 5 additions & 7 deletions katka/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,10 @@ class FilterViewMixin:
def get_queryset(self):
queryset = super().get_queryset()

# Fetch distinct for all model fields, to prevent duplications due to SQL Joins
queryset = queryset.distinct()

# Allow filtering on any field in serializer
all_fields = self.serializer_class.Meta.fields
filter_fields_lookup = {field: field for field in all_fields}
filter_fields_keys = list(all_fields)
all_fields = self.model._meta.get_fields()
filter_fields_lookup = {field.name: field.name for field in all_fields}
filter_fields_keys = list(field.name for field in all_fields)

# Also support a mapping from query parameter to django query field
if self.parameter_lookup_map:
Expand All @@ -64,6 +61,7 @@ def get_queryset(self):
filters[django_lookup_field] = value

if filters:
queryset = queryset.filter(**filters)
# Fetch distinct for all model fields, to prevent duplications due to SQL Joins
queryset = queryset.distinct().filter(**filters)

return queryset
24 changes: 24 additions & 0 deletions tests/integration/test_team_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,30 @@ def test_get(self, client, logged_in_user, team):
assert parsed["group"] == "group1"
UUID(parsed["public_identifier"]) # should not raise

def test_get_by_project(self, client, logged_in_user, team, project):
response = client.get(f"/teams/{team.public_identifier}/?project={project.public_identifier}")
assert response.status_code == 200
parsed = response.json()
assert parsed["name"] == "A-Team"
assert parsed["group"] == "group1"
UUID(parsed["public_identifier"]) # should not raise

def test_get_by_project_bad(self, client, logged_in_user, team, project):
response = client.get(f"/teams/{team.public_identifier}/?project=12345")
assert response.status_code == 404

def test_get_by_application(self, client, logged_in_user, team, application):
response = client.get(f"/teams/{team.public_identifier}/?application={application.public_identifier}")
assert response.status_code == 200
parsed = response.json()
assert parsed["name"] == "A-Team"
assert parsed["group"] == "group1"
UUID(parsed["public_identifier"]) # should not raise

def test_get_by_application_bad(self, client, logged_in_user, team, application):
response = client.get(f"/teams/{team.public_identifier}/?application=12345")
assert response.status_code == 404

def test_get_excludes_inactive(self, client, logged_in_user, deactivated_team):
response = client.get(f"/teams/{deactivated_team.public_identifier}/")
assert response.status_code == 404
Expand Down

0 comments on commit ab5ba1b

Please sign in to comment.